Ascend C sqrt 算子实战
本文分享自华为云社区《【2023 · CANN训练营第一季】——Ascend C sqrt算子实战》,作者:dayao。
前言
编写一个 Ascend C 的 sqrt 算子,并通过内核调用方式在 cpu 和 npu 模式下进行验证。在训练营沙箱环境下,cpu 模式工作正常结果正确。
一、概述
先简单回顾下 TIK C++算子矢量编程的流程和实现。
矢量算子开发流程如下:
主要工作内容有:
1、算子分析:确定输入输出,确定数学表达式以及底层实现接口,确定核函数定义。
2、算子类的实现:实现 init()和 process()。init()完成内存初始化,实质上体现的是多核运行,和单核数据切分以及是否开启 double buffer 优化;Process()实现的是 CopyIn,Compute、CopyOut 三个流水任务。
3、算子验证:通过核函数的内核调用符的方式调用算子,计算出结果,并于使用相同输入用 numpy 计算结果进行比对,误差在一定范围内即可。实际应用中,需要使用原有框架的算子进行计算精度比对。
二、算子分析
算子定义如下:假定仍是 8 个逻辑核。
查询 TIK C++的 API 可知,可以使用(TIK C++ API/矢量计算/单目/Sqrt,采用 2 级接口)完成运算,得到最终结果。
三、代码分析
直接在训练营课程提供的 add_tik2 算子工程上修改。代码地址:https://gitee.com/zgx950813/samples/tree/master/tik2_demo/kernel_samples/kernel_add_sample
修改代码目录结构如下:CMakeLists.txt 和 data_utils.h 未作修改,编译和执行脚本 run.sh 只改了计算结果与真值比对部分。
一)、核函数定义
与例程相比,输入参数只有 x。
二)、算子类
实现方式与 add 例程类似。init()函数里初始化内存:x,y 的 Global Memory ;流水线任务通讯内存;Process()实现流水线任务;按范式编写 CopyIn、Compute、CopyOut。与 add 例程最大差异是,在 compute 函数中,调用 sqrt 的 2 类接口 API 实现计算。
三)、核函数调用
1、在 CPU 模式下,通过 ICPU_RUN_KF 调用
2、在 NPU 模式下,通过<<<>>>调用
由于<<<>>>,只能在 NPU 模式下调用,所以需要用条件编译,不在 CPU 调试模式下有效。在调用 sqrt_tik2_do,需要按 ascendcl 应用编程的要求进行。
3、调用代码
通过“__CCE_KT_TEST__”宏区分 CPU 和 NPU 模式。
四)、基准数据生成——sqrt_tik2.py
使用 numpy 生成 input_x 和基准结果 golden。
五)、计算结果比较
使用 numpy 的 allclose()函数比较算子计算与基准数据的结果。实际上由于 npu 模式编译出错,实际未执行改函数进行比较。CPU 模式下,算子计算出的结果与基准 golden 数据完全一致,两者的 md5 相同。
四、编译运行
本次课程提供了沙箱运行环境,想个办法把代码搞进去。
一)、配置环境变量
二)、CPU 模式
cpu 模式顺利编译运行,结果与对比组完全一致。
三)、NPU 模式
npu 模式下编译报错,因为沙箱时间有限,以后有机会再研究。
版权声明: 本文为 InfoQ 作者【华为云开发者联盟】的原创文章。
原文链接:【http://xie.infoq.cn/article/4163b518a21a9765146dc5c5f】。文章转载请联系作者。
评论