1.微认证题目:
参考tensorflow的Sinh算子,实现Ascend C算子Sinh,算子命名为SinhCustom,并完成aclnn算子调用相关算法: sinh(x) = (exp(x) - exp(-x)) / 2.0
要求:
1、完成host侧和kernel侧代码实现。
2、实现sinh功能,支持float16类型输入,使用内核调试符方式调用算子测试通过。
3、使用单算子API调用方式调用SinhCustom算子测试通过
提交要求:
完成编程后,将上述实现的工程代码打包在rar包内提交,如SinhCustom.rar.
2.环境准备
我是在华为云ModelArts西南贵阳一创建的Notebook,镜像为:
mindspore_2.2.0-cann_7.0.1-py_3.9-euler_2.10.7-aarch64-snt9b
3.算子分析
算子分析的流程图如下:
对应题目,本题主要解决的是核函数代码,Kernel侧代码、Host侧代码,单算子调用时的代码。
Sinh算子的数学表达式为:sinh(x) = (exp(x) - exp(-x)) / 2.0
算子分析表格为:
整个算子分析计算过程分为三个阶段:CopyIn,Compute,CopyOut
CopyIn:搬入x到Local内存
Compute:使用Local内存进行计算
CopyOut:搬运Local计算结果到z
4.算子开发
可以参考samples仓库的Add算子,把Add算子的内核调用代码复制一份到SinhCustom
cp -r samples/operator/AddCustomSample/KernelLaunch/AddKernelInvocation/* samples/SinhCustomSample/KernelLaunch/SinhKernelInvocation
4.1核函数开发
首先修改最重要的sinh_custom.cpp
进行核函数的定义,并在核函数中调用算子类的Init和Process函数。
使用__global__函数类型限定符来标识它是一个核函数,可以被<<<…>>>调用;使用__aicore__函数类型限定符来标识该核函数在设备端AI Core上执行。
根据矢量编程范式实现算子类
基于矢量编程范式,将核函数的实现分为3个基本任务:CopyIn,Compute,CopyOut。Process函数中通过如下方式调用这三个函数。
CopyIn函数实现
Compute函数实现
Exp(xLocal, xLocal, TILE_LENGTH);:对从输入队列取出的本地张量 xLocal 进行指数运算(Exponential)。这用于计算 e^x,其中 x 是 xLocal 中的元素。TILE_LENGTH 是可能是一个常量,表示操作的长度。
Reciprocal(zLocal, xLocal, TILE_LENGTH);:计算 1/xLocal 的倒数,并将结果存储在 zLocal 中。
Muls(zLocal, zLocal, scalar, TILE_LENGTH);:将 zLocal 中的每个元素乘以标量 scalar,并将结果存储回 zLocal。
CopyOut函数实现
4.2核函数运行验证
CPU模式下执行如下命令
bash run.sh ascend910 cpu
运行结果如下:
可以看到真实值和期望值相差很小,基本没有误差。
NPU模式下执行如下命令:
bash run.sh ascend910 npu_onboard
这里报了一个aclError,不知道是不是硬件问题。
4.3创建算子工程
CANN软件包中提供了工程创建工具msopgen,我们可以输入算子原型定义文件生成Ascend C算子开发工程。
编写Sinh_Custom算子的原型定义json文件,如下:
[
{
"op": "SinhCustom",
"language": "cpp",
"input_desc": [
{
"name": "x",
"param_type": "required",
"format": [
"ND"
],
"type": [
"fp16"
]
}
],
"output_desc": [
{
"name": "z",
"param_type": "required",
"format": [
"ND"
],
"type": [
"fp16"
]
}
]
}
然后使用以下命令生成算子文件夹:
/usr/local/Ascend/ascend-toolkit/latest/python/site-packages/bin/msopgen gen -i /home/ma-user/work/samples/sinh_custom.json -c ai_core-Ascend910B2 -lan cpp -out /home/ma-user/work/samples/SinhCustom
生成的SinhCustom算子文件夹如下:
build_out文件夹是后面编译部署生成的,这里我们主要要修改的文件有:CMakePresets.json,op_host目录下的sinh_custom_tiling.h、sinh_custom.cpp、op_kernel目录下的sinh_custom.cpp。
下面分别展开:
4.4 op_kernel侧实现
Init()方法实现
可以先把Add_custom算子的kernel侧实现代码复制过来,然后在此基础上进行修改,首先是KernelSinh类的初始化代码,题目有一个输入,一个输出,修改如下:
CopyIn()方法实现
Compute()方法实现
Compute()函数是算子开发的核心,根据题目sinh(x) = (exp(x) - exp(-x)) / 2.0
Exp(xLocal, xLocal, TILE_LENGTH);:对从输入队列取出的本地张量 xLocal 进行指数运算(Exponential)。这用于计算 e^x,其中 x 是 xLocal 中的元素。TILE_LENGTH 是可能是一个常量,表示操作的长度。
Reciprocal(zLocal, xLocal, TILE_LENGTH);:计算 1/xLocal 的倒数,并将结果存储在 zLocal 中。
Compute()函数代码如下:
这里用到了Muls()方法用于矢量中每个元素与标量求积
CopyOut()方法实现
4.5 op_host侧实现
sinh_custom_tiling.h文件实现
这个文件要修改的地方是TilingData结构定义头文件的编写
sinh_custom.cpp文件实现
该文件是Tiling函数实现代码,主要修改算子原型注册代码,如下
5.算子工程编译和部署
算子kernel侧和host侧代码实现了之后,需要对算子工程进行编译,生成自定义算子安装包*.run
编译之前要修改CMakePresets.json文件下的ASCEND_CANN_PACKAGE_PATH变量,修改成你实际的CANN安装路径,我的修改如下:
修改好之后,切换到SinhCustom目录下,执行以下命令:
./build.sh
编译成功截图如下:
此时会生成一个build_out文件夹,里面有一个文件custom_opp_euleros_aarch64.run,使用以下命令部署
./custom_opp_euleros_aarch64.run
看到SUCCESS代表算子部署成功
6.使用aclnn方式调用
把AddCustom算子的AclNNInvocation文件夹复制一遍,目录位于samples/operator/AddCustomSample / FrameworkLaunch/AclNNInvocation,目录结构如下:
需要修改的文件有scripts文件下的gen_data.py,src文件下的main.cpp,op_runner.cpp
gen_data.py修改
main.cpp修改
要修改输入输出文件的位置
op_runner.cpp修改
要修改调用的算子名称,以及引入aclnn_sinh_custom.h头文件
修改完上述文件之后,就可以使用ACLNN的方式调用验证算子,进入AclNNInvocation文件夹,运行以下命令
bash run.sh
打印如下图,则代表测试通过!
可以看到真实结果和预期结果非常接近。误差很小。