2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子
  mrxYOEPYpIE7 2023年11月02日 59 0

前言:

        AscendC算子先进,硬核吗?必须是!那AscendC算子开发很难了,必须不是,算子开发很难,但AscendC开发算子不难!把复杂的事情流程(范式)化,把困难的事情简单(SPMD)化,这才是AscendC算子开发的硬核所在。这篇文档,交流下通过参考例程,动手写(改)出自己的AscendC算子。

        选择LeakyReLU算子作为样例,有点投机取巧的成分,因为sample仓本身就有部分代码。拿它作为例子,是为了展示一个知识点“通过TilingData传递算子的属性信息”。LeakyReLU算子有一个“negative_slope”,这是个标量,本例就是将这个属性值通过TilingData传递给核函数,进行运算的。本篇以实战为主,相关知识都给了官方链接,有兴趣的小伙伴可以参考阅读。受限于篇幅,本篇仅完成算子工程代码和简单核函数方式调用工程的编写,单算子调用工程以后再展开写。下面开始我们的AscendC编程之旅。

一、准备开发环境

        按照“Ascend C环境准备 https://www.hiascend.com/forum/thread-0235128261452483095-1-1.html?fid=0163125572293226003”贴,选择免费的modelarts CodeLab搭建开发环境,在此环境上,还可以完成CPU侧的验证,而且这个环境自带pytorch,所以也可以在算子分析阶段用来熟悉算子。如果需要进行NPU实际环境的验证,可参考“AscendC算子NPU开发调试环境成功搭建篇https://www.bilibili.com/read/cv26991439/ ”,完成环境搭建。

        使用此环境需要注意,由于modelarts,只保留work目录的内容(安装包放在work目录,就需要每次重新下载了),所以每次使用前需要重新安装toolkits和算子开发包,并配置环境变量。

        安装toolkit和算子开发包:

./Ascend-cann-toolkit_7.0.RC1.alpha002_linux-x86_64.run --install --force
tar -xf Ascend-cann-communitysdk_7.0.RC1.alpha002_linux-x86_64.tar.gz -C ~/Ascend/ascend-toolkit/latest

        配置环境变量:

source /home/ma-user/Ascend/ascend-toolkit/set_env.sh
export ASCEND_CUSTOM_PATH=$HOME/Ascend/ascend-toolkit/latest
export ASCEND_HOME_DIR=$HOME/Ascend/ascend-toolkit/latest
export PATH=/home/ma-user/work/cmake-3.26.4-linux-x86_64/bin:$PATH

二、下载参考例程:

        昇腾的sample仓(https://gitee.com/ascend/samples.git)提供了AscendC算子的代码例程,目前有两处:

1)samples/operator目录下,有“AddCustomSample”和“LeakyReLUCustomSample”两个例程。

2)samples/ cplusplus / level1_single_api / 4_op_dev / 6_ascendc_custom_op目录下,有一些例程。

        两部分例程都很好,第2个目录下例程知识点比较全,第1个目录下例程比较简单且结构更为简洁,比较适合拿来作为初学的样板做练习。本文以“samples/operator目录”下的AddCustomSample工程作为模板。

三、开发过程

1、算子分析

1)先去官网找一下,算子的定义https://pytorch.org/docs/stable/generated/torch.nn.LeakyReLU.html#torch.nn.LeakyReLU,然后在pytorch环境下,运行下算子,了解各种参数的意义。

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营


2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_02

2)分析计算实现的方法,查找AscendC官方文档,在标量双目指令中有LeakyRelu算子,本例可以直接使用。对没有直接API实现的算子,需要先分解成基本API的组合。

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_03

3)出算子设计规格表:假定输入类型为float16,形状8 * 1024(和AddCustom保持一致),且不考虑“inplace的情形

        关于算子分析可参看“文档首页>CANN社区版>7.0.RC1.alpha003>算子开发>Ascend C算子开发>算子开发(基础篇)>矢量编程>算子分析 https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/70RC1alpha003/operatordevelopment/ascendcopdevg/atlas_ascendc_10_0015.html”,

        如下图所示:左侧是Add例程,右侧是参考例程写出的“LeakyReluCustom”。红色的是有差异的地方,请记住这些或者等我们完成代码编写后再回头看一下这儿,会发现所做的修改都和此处有关系。

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_04

2、编写LeakyReLU算子原型定义json文件

        为了方便描述,我将add_custom.json输入类型做了简化,仅保留了float16。根据上面的分析表,将输入和输出写对就可以了,这里面需要注意“属性”的写法。具体写法可参考文档:“文档首页>CANN社区版>7.0.RC1.alpha003>算子开发>Ascend C算子开发>算子开发(进阶篇)>基于msopgen工具创建算子工程

https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/70RC1alpha003/operatordevelopment/ascendcopdevg/atlas_ascendc_10_0023.html

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_05

3、生成算子工程

        使用msopgen生成算子工程。

/home/ma-user/Ascend/ascend-toolkit/latest/python/site-packages/bin/msopgen gen -i ./leakyrely_custom.json -c ai_core-ascend910,ai_core-ascend910B,ai_core-ascend310p -lan cpp -out ./LeakyReLUCustom

      关于msopgen的使用,请参考昇腾社区的文档“文档首页>CANN社区版>7.0.RC1.alpha003>算子开发>Ascend C算子开发>附录>msopgen工具使用>使用说明”

https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/70RC1alpha003/operatordevelopment/ascendcopdevg/atlas_ascendc_10_0076.html

      参数含义:

  • -i:指定算子原型定义文件add_custom.json所在路径,请根据实际情况修改。
  • -c:ai_core-<soc_version>代表算子在AI Core上执行,<soc_version>为昇腾AI处理器的型号。多个处理器之间用逗号“,”分割。
  • -lan: 参数cpp代表算子基于Ascend C编程框架,使用C++编程语言开发。
  • -out:生成文件所在路径,可配置为绝对路径或者相对路径,并且工具执行用户对路径具有可读写权限。若不配置,则默认生成在执行命令的当前路径。

      生成的目录结构如下图右侧:此处主要修改三个文件:算子tiling定义文件;host侧实现文件;kernel侧实现文件。

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_06

4、修改device侧和host侧的代码

     1)修改host/leaky_relu_custom_tiling.h

      tilingdata是用来计算数据切分的,在固定算子shape的情形下,只需要totalLength和tileNum即可,leakyreluCustom算子需要传递value的属性值,所以增加1个value。改动处都用红框标记了,这里需要注意的就是增加value那一行。进一步学习,可参考“文档首页>CANN社区版>7.0.RC1.alpha003>算子开发>Ascend C算子开发>算子开发(进阶篇)>host侧算子实现>Tiling实现 https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/70RC1alpha003/operatordevelopment/ascendcopdevg/atlas_ascendc_10_0027.html”。

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_07

      2)修改host/leaky_relu_custom.cpp代码

      host侧算子实现开发包括Tiling实现、Shape推导等函数实现、算子原型注册。进一步学习,可参考“文档首页>CANN社区版>7.0.RC1.alpha003>算子开发>Ascend C算子开发>算子开发(进阶篇)>host侧算子实现>host侧算子实现概述 https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/70RC1alpha003/operatordevelopment/ascendcopdevg/atlas_ascendc_10_0026.html

      首先是Tiling实现,这里面需要注意的是获取算子value属性代码,其余的可以和例程保持一致即可。GetAttrs()可在API参考里查找。“文档首页>CANN社区版>7.0.RC1.alpha003>算子开发>Ascend C算子开发>API参考>Host侧实现API>basics>ComputeNodeInfo类>GetAttrs”

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_08

      Shape推导的代码不用修改,输出shape和输入shape保持一致。

      算子原型注册代码有差异,仔细看的话,会发现和算子原型定义的那个json文件是一致的。但此处通过工具自动生成,也不需要修改。请注意右侧用红框标出的部分,特别是关于属性的定义“this->Attr("value").Float();”

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_09

      3)修改device侧代码

      这是算子编程的很重要的部分,需要修改的地方如下图所示。进一步可阅读“文档首页>CANN社区版>7.0.RC1.alpha003>算子开发>Ascend C算子开发>算子开发(进阶篇)>kernel侧算子实现 https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/70RC1alpha003/operatordevelopment/ascendcopdevg/atlas_ascendc_10_0024.html”。

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_10

      算子类实现代码,进一步阅读,参考“文档首页>CANN社区版>7.0.RC1.alpha003>算子开发>Ascend C算子开发>算子开发(基础篇)>矢量编程>算子类实现 https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/70RC1alpha003/operatordevelopment/ascendcopdevg/atlas_ascendc_10_0017.html”。这部分内容建议刚开始学的小伙伴要好好看明白,这里面包含了“多核并行”,“编程范式”,“流水线”等众多AscendC编程思想。虽说以后编写代码也可以ctrl+c,和ctrl+v,但理解了就能一劳永逸。

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_11

5、编写简单核函数调用代码

      简单、粗暴,直接将例程的“kernel_direct_call"目录拷过来,然后将下图中的三个文件改名。这三个文件,加上run.sh,我们只需要修改这四个文件,就可以完成调用代码的改写。这部分内容,有兴趣的小伙伴,参看“文档首页>CANN社区版>7.0.RC1.alpha003>算子开发>Ascend C算子开发>算子开发(基础篇)>核函数运行验证 https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/70RC1alpha003/operatordevelopment/ascendcopdevg/atlas_ascendc_10_0019.html

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_12

      1)kernel_call_leakyrelu_custom_tiling.h

      这个文件,是模拟算子工程host侧算子实现和kernel侧算子实现,传递tilingdata数据用的。改动很小,但需要花时间去好好阅读下,感觉此处解密了AscendC算子这一功能的实现方式。

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_13

      2)kernle_call_leakyrelu_custom.py

      此脚本,生成输入数据,然后计算出输出数据,并落盘,然后再run.sh脚本里与AscendC算子的结果进行比较。

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_14

      3)main.cpp

      这里面是分别cpu和npu方式调用核函数的代码,“孪生调试”。代码修改主要就是名称,函数的参数数量之类,版面首限,也没有办法展开,不再赘述。此处需要注意的是读取tilingdata模拟数据时,因为增加了算子属性value,所以读取长度,需要再原来的基础上增加sizeof(float)。

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_15

      4)run.sh

      主要修改2处:

      修改算子工程名

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_16

      需要将算子工程op_kernel的算子实现代码拷贝到核函数调用工程里,需要对路径名和文件名做相应修改。run.sh其余部分无需修改,它是通过比较kernle_call_leakyrelu_custom.py和AscendC算子对相同数据的计算结果的md5sum,来判断结果是否一致的。

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_17


四、编译运行

1、CPU模式

      1)将代码做成zip格式的压缩包,启动环境,将代码上传到环境。

      2)安装toolkit和算子开发包。(参见第一节,搭建cpu开发运行环境章节)

      3)解压缩。并给算子工程“/util”目录下文件,赋权限750,否则会报错。

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_18

      4)编译运行

      进入“kernel_direct_call”目录,运行“bash run.sh ascend910B1 cpu”

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_19

      运行结果:

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_20

2、npu模式

      参考AscendC算子NPU开发调试环境成功搭建篇https://www.bilibili.com/read/cv26991439/ ”搭建NPU的调试运行环境。并把代码搞里头,过程参考cpu模式。

      进入kernel_direct_call目录,运行 bash run.sh ascend910B1 npu_onboard 

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_21

      运行结果如下:

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_22

      至此,完成了leakyrelu算子的开发和核函数调用方式的验证。

附录:

      看到这儿的小伙伴,如果还没有加入CANN训练营,可以按下面的链接进行报名,不仅可以学到基于昇腾AI开发的知识,还有大奖可以拿。

报名链接:https://www.hiascend.com/developer/activities/details/84b950830fc44476851860f51f0873a2/signup?channelCode=0&recommended=234384

2023·CANN训练营第二季——跟着sample仓例程,动手写(改)自己的AscendC算子_CANN训练营_23

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

mrxYOEPYpIE7