您可以参考本章节进行算子适配插件的开发,将ONNX框架的算子映射成适配昇腾AI处理器的算子(下文简称CANN算子),从而完成从ONNX框架调用Ascend C自定义算子的过程。
完成算子工程创建后,会在算子工程目录下生成framework/onnx_plugin目录,用于存放ONNX框架适配插件实现文件。以自定义CANN算子LeakyReluCustom为例,算子工程目录如下:
LeakyReluCustom ├── build.sh // 编译入口脚本 ├── cmake ├── CMakeLists.txt // 算子工程的CMakeLists.txt ├── CMakePresets.json // 编译配置项 ├── framework // 框架适配插件实现文件目录 │ ├── onnx_plugin // ONNX框架适配插件实现文件目录 │ │ ├── CMakeLists.txt │ │ ├── leaky_relu_custom_plugin.cc // ONNX框架适配插件实现文件 │ ├── CMakeLists.txt ├── op_host // host侧实现文件 ├── op_kernel // kernel侧实现文件 └── scripts // 自定义算子工程打包相关脚本所在目录
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include "register/register.h" #include "graph/operator.h" #include "json.hpp" namespace domi { Status ParseParamByOpFunc(const ge::Operator& op_src, ge::Operator& op_dest) { //... } REGISTER_CUSTOM_OP("OpType") .FrameworkType(ONNX) .OriginOpType("OriginOpType") .ParseParamsByOperatorFn(ParseParamByOpFunc) //用来注册解析算子属性的函数 .ImplyType(ImplyType::TVM); // Ascend C算子实现类型设置为TVM } |
1
|
Status ParseParamByOpFunc(const ge::Operator& op_src, ge::Operator& op_dest) |
开发者需要在回调函数中实现属性的解析和映射,具体实现方式如下:
ONNX原始模型中,属性为repeated message类型,对于repeated message类型的参数,可使用GetAttr(const char *name, ge::AscendString &attr_value)接口获取其属性值,然后将AscendString类型的属性值转换为String类型,再将其转换为json格式进行属性字段的解析。
实现如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Status ParseParamLeakyReluAscend(const ge::Operator& op_src, ge::Operator& op_dest) { float negative_slope = 0.01f; string negative_slope_str; AscendString attrs_string; // 使用固定属性名称“attribute”获取ONNX算子中的属性,并赋值给AscendString类型对象 if (ge::GRAPH_SUCCESS == op_src.GetAttr("attribute", attrs_string)) { // 转换为json格式 json attrs = json::parse(attrs_string.GetString()); for (json attr : attrs["attribute"]) { if (attr["name"] == "alpha" && attr["type"] == kTypeFloat) { negative_slope_str = attr["f"]; // float type in json has accuracy loss, so we use string type to store it negative_slope = atof(negative_slope_str.c_str()); } } } op_dest.SetAttr("negative_slope", negative_slope); return SUCCESS; } |