算子调用
开发应用时,如果涉及执行单个算子,则应用程序中必须包含执行单个算子的代码逻辑,关于执行单个算子的接口调用流程,请依次参见主要接口调用流程以及本节中的说明。
对于系统不支持的算子,用户需先参见《TBE自定义算子开发指南》或《AI CPU自定义算子开发指南》完成自定义算子开发。
图1 算子调用流程
关键接口的说明如下(调用示例请参见单算子调用):
- 编译算子。
- 编译算子后,算子相关数据保存在*.om模型文件中
该种方式下编译算子,需使用ATC工具,详细描述请参见《ATC工具使用指南》,将单算子定义文件(*.json)编译成适配昇腾AI处理器的离线模型(*.om文件)。
- 编译算子后,算子相关数据保存在内存中
该种方式下编译算子,需调用AscendCL提供的接口,根据不同场景调用不同的接口:
- 对于同一个算子,编译一次,多次执行的场景,建议调用aclopCompile接口编译算子。编译算子后,依次进行3、4、5、6。
- 对于编译算子、执行算子次数相同的场景,建议先执行3,再调用aclopCompileAndExecute接口编译算子。编译算子后,再依次进行5、6。
- 对于TIK自定义动态Shape算子,需要先注册算子选择器,流程如下:
- 调用aclopRegisterCompileFunc接口注册算子选择器(即选择Tiling策略的函数),用于在算子执行时,能针对不同Shape,选择相应的Tiling策略。
算子选择器需由用户提前定义并实现,算子选择器的实现样例请参见《TBE自定义算子开发指南》中的“专题 > TIK自定义算子动态Shape专题”:
函数原型:typedef aclError (*aclopCompileFunc)(int numInputs, const aclTensorDesc *const inputDesc[], int numOutputs, const aclTensorDesc *const outputDesc[], const aclopAttr *opAttr, aclopKernelDesc *aclopKernelDesc);
函数实现:
用户自行编写代码逻辑实现Tiling策略选择、Tiling参数生成,并将调用aclopSetKernelArgs接口,设置算子Tiling参数、执行并发数等。
- 调用aclopCreateKernel接口将算子注册到系统内部,用于在算子执行时,查找到算子实现代码。
- 调用aclopUpdateParams接口编译指定算子,触发算子选择器的调用逻辑。
- 调用aclopRegisterCompileFunc接口注册算子选择器(即选择Tiling策略的函数),用于在算子执行时,能针对不同Shape,选择相应的Tiling策略。
- 编译算子后,算子相关数据保存在*.om模型文件中
- 加载算子模型文件。
支持以下2种方式中的一种加载单算子模型文件:
- 调用aclopSetModelDir接口,设置加载模型文件的目录,目录下存放单算子模型文件(*.om文件)。
- 调用aclopLoad接口,从内存中加载单算子模型数据,由用户管理内存。单算子模型数据是指“单算子编译成*.om文件后,再将om文件读取到内存中”的数据。
- 调用aclrtMalloc接口申请Device上的内存,存放执行算子的输入、输出数据。
如果需要将Host上数据传输到Device,则需要调用aclrtMemcpy接口(同步接口)或aclrtMemcpyAsync接口(异步接口)通过内存复制的方式实现数据传输。
- 执行算子。
- 对于被封装成AscendCL接口的算子GEMM,用户可直接调用CBLAS接口执行该算子。
- 对于未被封装成AscendCL接口的算子,用户可调用aclopExecuteV2或aclopExecWithHandle接口执行算子。
- 调用aclrtSynchronizeStream接口阻塞应用运行,直到指定Stream中的所有任务都完成。
- 调用aclrtFree接口释放内存。
如果需要将Device上的算子执行结果数据传输到Host,则需要调用aclrtMemcpy接口(同步接口)或aclrtMemcpyAsync接口(异步接口)通过内存复制的方式实现数据传输,然后再释放内存。
父主题: 接口调用流程