您可以参考本章节进行算子适配插件的开发,将基于第三方框架的算子映射成适配昇腾AI处理器的算子,将算子信息注册到Graph Engine(简称:GE)中。基于Caffe框架的网络运行时,首先会加载并调用GE中的插件信息,将原始框架网络中的算子进行解析并映射成适配昇腾AI处理器中的算子。
下文我们将适配昇腾AI处理器的算子称为CANN算子。
Caffe框架算子到CANN算子的一对多、多对多、多对一映射暂不支持。
算子插件的实现包含CANN算子类型的注册、原始框架中算子类型的注册以及原始框架中算子属性到CANN算子属性的映射,算子的映射通过Parser模块完成。插件在整网络运行场景下的实现流程如图1所示。
GE提供REGISTER_CUSTOM_OP宏,按照指定的算子名称完成算子的注册。
#include "register/register.h" #include "graph/operator.h" namespace domi { REGISTER_CUSTOM_OP("OpType") .FrameworkType(CAFFE) .OriginOpType("OriginOpType") .ParseParamsByOperatorFn(ParseParamByOpFunc) // 用来注册解析算子属性的函数 .ImplyType(ImplyType::TVM); // TBE算子:ImplyType::TVM;AI CPU算子:ImplyType::AI_CPU }
register.h存储在CANN软件安装后文件存储路径的“include/register/”目录下,包含该头文件,可使用算子注册相关类,调用算子注册相关的接口。
operator.h(可选),存储在CANN软件安装后文件存储路径的“include/graph/”目录下,包含该头文件,可以使用Operator类相关接口,获取算子输入输出及属性等算子信息。
回调函数ParseParamByOpFunc的声明如下所示:
Status ParseParamByOpFunc(const ge::Operator& op_src, ge::Operator& op_dest)
ParseParamByOpFunc函数的实现如下所示:
用户首先需要调用Operator类的GetAttr接口获取op_src对象的属性值,然后调用SetAttr接口将获取到的属性值赋给op_dest对象。
GetAttr接口支持不同类型的属性值,例如:
例如:caffe.proto中定义如下所示:
message BiasParameter { repeated BiasStruct bias_struct = 1; } message BiasStruct { optional uint32 offset = 1; repeated uint32 width = 2; };
使用GetAttr("bias_struct", attr_value)获取attr_value(AscendString类型), 再将其转化为attr_value(string类型) , 最后再将string类型转化为json格式去访问其中的字段。
假设prototxt中算子参数如下:
layer { name: "bias" top: "out" bottom: "data" type: "Bias" bias_param { bias_struct { offset : 2 width: 8 width: 10 } bias_struct { offset : 1 width: 20 } } }
则转换为json格式后的数据如下:
{ "bias_struct": [ { "offset": 2, "width": [ 8, 10 ] } { "offset": 1, "width": [ 20 ] } ] }
开发者可自由选择将string转为json的方式,下面以使用json.hpp为例进行说明,开发者可将json.hpp放在工程可以找到的任意路径下,使用时包含头文件即可。
ParseParamByOpFunc函数中访问json字段代码如下:
if (ge::GRAPH_SUCCESS == op_src.GetAttr("bias_struct", bias_struct_val)) { std::string bias_struct_str = bias_struct_val.GetString(); // convert to json bias_struc_json = nlohmann::json::parse(bias_struct); for (int i = 0; i < bias_struc_json["bias_struct"].size(); i++) { nlohmann::json bias_value = bias_struc_json["bias_struct"][i]; uint32_t value = bias_value["offset"].get<uint32_t>(); for (int idx = 0; idx < bias_value["width"].size(); idx++) { uint32_t value = bias_value["width"][idx].get<uint32_t>(); } } }