您可以参考本章节进行算子适配插件的开发,将基于第三方框架的算子映射成适配昇腾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>();
}
}
}