Skip to content

Latest commit

 

History

History
234 lines (141 loc) · 10.5 KB

BANGC-OPS算子开发流程.md

File metadata and controls

234 lines (141 loc) · 10.5 KB

BANGC-OPS 算子开发流程

概述

需要添加的文件

算子设计文档

算子测试报告

代码提交流程

概述

MLU-OPS 是面向 MLU 平台的神经网络加速库,算子的功能实现可以利用寒武纪特有的 BANG C 语言实现。

MLU-OPS 库中算子的开发过程,文档与算子的代码实现同样重要。文档是 MLU-OPS 库中参与者沟通的桥梁,是了解算子功能和接口使用的入口,故算子设计文档的撰写需格式规范、层次清晰、功能完整。当算子的实现代码修改时,文档需同步进行修改,保持文档与代码的一致性。

一个算子需要入库的文件包含:算子设计文档、算子实现代码、算子测试代码、测试报告。

  • 算子设计文档:包含算子的需求分析、API 接口设计、算子的实现设计

  • 算子实现代码:包含 C++ 实现源码、C 风格对外接口、BANG C 的 kernel 实现源码

  • 算子测试代码:算子开发者需要编写算子的测试代码,该代码需能够测试到算子的多种使用场景

  • 算子测试报告:包含算子测试结果,如算子测试规模和数据类型、算子性能及稳定性等

需要添加的文件

本章节会详细说明在整个算子开发和维护过程中需要添加和修改的文件及其所在目录。算子开发者在开发过程中务必按照说明中的目录和文件进行添加和修改,以确保 MLU-OPS 库文件和目录结构的简洁。

下面以添加一个加法算子为例说明整个算子开发过程中添加的文件。

1. 文档开发阶段

在 docs/bangc-docs/design_docs/ 目录下新建以算子名命名的目录,目录名首字母小写,并在算子目录下新建以算子名命名的 md 文件。如:

$ cd docs/bangc-docs/design_docs/
$ mkdir add
$ cd add
$ vim add.md

在 add 目录下添加的 add.md 文件,为算子的设计文档,设计文档模板可参考MLU-OPS 算子设计文档模板

如果一个算子存在正向和反向,那么正反向算子当做两个不同的算子来处理。如卷积算子存在卷积前向与卷积反向,目录结构应为

|-- docs
   |-- design_docs
      |-- convolution_forward
         |-- convolution_forward.md
      |-- convolution_backward
         |-- convolution_backward.md

文档中如有涉及公式的地方, 使用 md 的公式格式,不能使用图片的形式插入。

2. 代码开发阶段

在 bangc-ops/kernels/ 目录下,添加以算子名命名的目录,然后在该目录下添加算子功能的实现文件、接口声明文件以及 bangc 编写的 kernel 文件,文件名首字母小写。如:

$ cd kernels
$ mkdir add  // 添加以算子名命名的目录
$ cd add
$ touch add.cpp // add.cpp  ->  mluop 接口的实现文件
$ touch add.mlu // add.mlu  ->  以 bangc 编程的 kernel 函数的实现文件
$ touch add.h   // add.cpp 以及 kernel entry 函数的声明文件

文件命名及组织规则为:

  1. cpp 及 h 文件的文件名为算子名,如 add.cpp / add.h、pooling.cpp / pooling.h 等

  2. mlu 文件根据算子的实现以 "算子名 + 实现方式" 的规则进行命名。 如加法算子的实现方式为单核编程,不涉及核间规约及 cluster 规约,应命名为 add_block.mlu,如算子的实现方式为以 Union1 为最小单位,需命名为 add_union1.mlu,如以 Union2 为最小单位,需命名为 add_union2.mlu.

  3. mlu 文件中所定义的 kernel 入口函数的声明放置在对应的 .h 文件中。

3. 测试阶段

算子开发者在完成算子开发任务后,需要添加 gtest 测试。具体添加方式及注意事项如下:

3.1 添加 gtest

gtest 测试例的添加原则为能够测试到该算子的各种应用场景,包括:

  • 算子输入输出支持的各种数据类型

  • 算子输入输出支持的各种规模

  • 算子输入输出支持的各种 layout

  • 算子在框架端网络中用到的规模及数据类型

  • 必要的边界测试

添加 gtest 的流程大体分为:

  1. 在 mlu_op_test.proto 文件中增加算子信息
  2. 增加测试代码
  3. 手写测例用于测试
1. 修改 proto 文件

路径: mlu-ops/test/mlu_op_gtest/mlu_op_test_proto/mlu_op_test.proto

proto 文件用于定义记录算子测例的 prototxt 文件中的数据类型, 这样的话一个算子的测例格式就是固定, 方便存储和解析.

举例来说, 一个算子需要 float 类型的参数 alpha 和 beta, 那就需要在 proto 文件中定义一个结构体(message), 该结构体中定义两个 float 域, 分别是 alpha 和 beta.

message XXXParam {   //  比如调用XXX算子,需要alpha和beta,因此用message定义一个结构体。
  optional float alpha = 1 [default = 1];
  optional float beta  = 2 [default = 1];
}

注意, 这里说的 proto 仅仅是数据格式的定义, 不同的测例是这个定义的实例化; 同时, 如上述代码, alpha = 1beta = 2 后面的数字是域的 id, 不是值,default = 1 才是域的默认值。

随后, 结合测试代码和手写的 prototxt, 可以获取 alpha 和 beta 的值, 给到算子作为输入. 不同的测例中记录不同的 alpha 和 beta 值, 如此实现全面的测试.

2. 增加测试代码
  1. 新建测试代码路径 mlu_op_gtest/src/zoo 下面新建以算子名命名的目录.

在 mlu-ops 仓库中, 代码中的 mluOpXXX 即算子名, 不算 mluOp 前缀的话是大驼峰命名, 而文件夹名用下划线法命名。例如代码中接口名为 mluOpSqrtBackward 的算子,算子文件夹目录名为 sqrt_backward。请保证同一个算子 kernels 下的文件夹和 zoo 下的文件夹名相同。

并在上述路径添加测试文件的 .cpp 以及 .h 文件(名字不限)。同时添加目录 test_case, test_case 目录下放置 gtest 运行时需读取的 .prototxt 文件。

  1. 编写测试代码
  • 定义类
// 这里的XXX是算子文件夹, 以下划线为分隔符, 首字母大写之后的名字.
// 比如 RMSprop 算子, 文件夹是 rms_prop 这里XXX应为 RmsPropExecutor
// 之所以有这个限制, 是因为我们约定某测例文件夹内全是对应算子的测例, gtest会根据文件夹名调用下述类中定义的方法.
class XXXExecutor : public Executor {
  void compute();   // 在这里, 从prototxt文件中解析算子参数, 调用mluop接口
  void cpuCompute();  // 在这里, 实现该算子的cpu计算(float32), 用于功能验证.
  ...
};

注意: cpuCompute()函数中需要统计算子的理论计算量 theory_ops,具体添加方法可以参考库内的已有算子。

3.2 算子验收标准

1. 精度验收标准

kernels 下的 bangc 算子实现需要与 gtest 中的 cpuCompute()实现作为 baseline 进行精度对比验证,具体精度标准见 MLU-OPS 精度验收标准

为了方便开发者,上述精度公式和结果对比流程已集成到 gtest 测试框架中,各算子只需要明确使用的精度公式和阈值即可。

2. 性能验收标准

MLU-OPS 性能验收标准

算子设计文档

算子负责人接到算子开发任务后,必须先进行算子的需求分析,完成算子设计文档。

算子设计文档模板链接:MLU-OPS 算子设计文档模板

算子设计文档需包含以下 5 个部分:

  • 算子需求分析

  • API 接口设计

  • 算子实现设计

  • 算子性能优化记录

  • 方案实施

1. 算子需求分析

在算子需求分析阶段,算子开发者要了解算子实现的数学原理,以确保算子开发的准确、高效。在该阶段,算子开发者需要调研框架的算子的功能和需求,例如 tensorflow 以及 pytorch 框架。若该算子在多个框架中都有对应实现,需要进行综合调研分析,以确保开发的算子可以同时满足多个框架的需求。

注意,有些算子在两个框架的需求和使用场景不同,比如 Pooling 算子的 add pad 操作,当 padding_width == 3 时,在 tensorflow 框架下 pad_left == 1, pad_right == 2,而在 pytorch 框架下, pad_left == 2, pad_right == 1,因此该算子的接口和内部实现需同时满足两个框架的需求。 因此,一定要确保和两个框架都对接完成后,再进行下一步,否则可能会做许多无用功。

需要和框架对接的内容包括但不限于以下几点:

  • 算子的输入和输出:该算子在框架层的调用需要有几个输入和几个输出、需要支持哪些数据类型、输入输出的物理布局以及该算子是否需要支持多维等

  • 算子的规模限制:算子对于输入输出的规模限制、维度、layout、数据类型信息等

  • 算子的性能需求:两个框架对该算子的性能要求

  • 算子的接口需求:接口设计需满足框架的使用需求

  • 算子是否需要支持原位操作/stride 机制/广播

  • 算子对于 0 元素是直接返回还是需要做特殊处理

  • 算子是否有其他特殊需求(量化,融合等)

2. API 接口设计

在进行算子的接口设计时,需要对框架算子功能做完备的需求分析后进行设计,包括:

  • Pythorch
  • Tensorflow
  • Caffe
  • ...

在设计文档中需写明接口设计时所参考的框架接口,并对所设计的接口参数列表进行详细说明,同时需要说明用户在使用接口时需要注意的事项等。

注意: API 接口设计为 C 风格接口,不允许出现 C++ 的语法风格。

算子测试报告

算子开发者除了编写算子的代码实现部分外,还需要编写算子测试代码,测试代码需能够测试到算子使用的多种场景。测试报告至少需要包含:

  • 功能测试
  • 性能测试
  • 稳定性测试

具体见:MLU-OPS 测试报告模板

代码提交流程

本地编译测试通过后可以执行以下操作提交修改的代码到远程分支。

1. git add FileName                \\ 将所有修改的文件添加到 git 暂存区。
2. git commit                      \\ 将添加到暂存区的修改提交。
3. git pull origin master -r       \\ rebase master, 确保自己的分支领先于最新 master 分支。
4. git push origin your_branch     \\ 将本地分支推到远程。