AscendC 从入门到精通系列(四)使用 Pybind 调用 AscendC 算子
如果已经通过 Ascend C 编程语言实现了算子,那该如何通过 pybind 进行调用呢?
1 Pybind 调用介绍
通过 PyTorch 框架进行模型的训练、推理时,会调用很多算子进行计算,其中的调用方式与 kernel 编译流程有关。
对于自定义算子工程,需要使用 PyTorch Ascend Adapter 中的 OP-Plugin 算子插件对功能进行扩展,让 torch 可以直接调用自定义算子包中的算子,详细内容可以参考 PyTorch 框架;
对于 KernelLaunch 开放式算子编程的方式,通过适配
Pybind 调用,可以实现 PyTorch 框架调用算子 kernel 程序。Pybind 是一个用于将 C++代码与 Python 解释器集成的库,实现原理是通过将 C++代码编译成动态链接库(DLL)或共享对象(SO)文件,使用 Pybind 提供的 API 将算子核函数与 Python 解释器进行绑定。在 Python 解释器中使用绑定的 C++函数、类和变量,从而实现 Python 与 C++代码的交互。在 Kernel 直调中使用时,就是将 Pybind 模块与算子核函数进行绑定,将其封装成 Python 模块,从而实现两者交互。
2 工程目录结构
该样例的工程目录结构如下:
基于该算子工程,开发者进行算子开发的步骤如下:
完成算子 kernel 侧实现。
编写算子调用应用程序和定义 pybind 模块 pybind11.cpp。
编写 Python 调用脚本 add_custom_test.py,包括生成输入- 数据和真值数据,调用封装的模块以及验证结果。
编写 CMake 编译配置文件 CMakeLists.txt。
根据实际需要修改编译运行算子的脚本 run.sh 并执行该脚本,完成算子的编译运行和结果验证。
3 环境准备
3.1 安装 pytorch (这里以 2.1.0 版本为例)
3.2 安装 torch-npu(昇腾适配 torch 的开发工程,这里以 Pytorch2.1.0、python3.9、CANN 版本 8.0.RC1.alpha002 为例)
3.3 安装 pybind11
4 工程实现
4.1 算子 kernel 实现
之前的文章中,已经实现过,add_custom.cpp 内容如下:
4.2 实现 pybind11.cpp
1、按需包含头文件。需要注意的是,需要包含对应的核函数调用接口声明所在的头文件 alcrtlaunch_{kernel_name}.h(该头文件为工程框架自动生成,
2、编写框架调用程序
需要注意的是,输入 x,y 的内存是在 Python 调用脚本 add_custom_test.py(往下看)中分配的。3、 定义 Pybind 模块将 C++函数封装成 Python 函数。PYBIND11_MODULE 是 Pybind11 库中的一个宏,用于定义一个 Python 模块。它接受两个参数,第一个参数是封装后的模块名,第二个参数是一个 Pybind11 模块对象,用于定义模块中的函数、类、常量等。通过调用 m.def()方法,可以将步骤 2 中函数 my_add::run_add_custom()转成 Python 函数 run_add_custom,使其可以在 Python 代码中被调用。
4.3 编写 Python 调用脚本
在 Python 调用脚本中,使用 torch 接口生成随机输入数据并分配内存,通过导入封装的自定义模块 add_custom,调用自定义模块 add_custom 中的 run_add_custom 函数,从而在 NPU 上执行算子。
4.4 编写 CMakeLists 实现 pybind11 文件编译
编译进工程的方式有很多,各个项目不一样,这里提供一个参考:operator/AddCustomSample/KernelLaunch/CppExtensions/CMakeLists.txt · Ascend/samples - 码云 - 开源中国 (gitee.com)
评论