解析算子
对于用户新开发的自定义算子,需要自定义实现解析算子中属性的函数,将原始模型中的算子属性定义转换为适配昇腾AI处理器的离线模型中的算子属性定义。如果用户重写昇腾AI处理器内置算子,则此步骤跳过,插件会自动实现对内置算子的解析。
函数声明
算子解析函数的声明如下所示:
Status ParseParamsxx(const Message* op_origin, ge::Operator& op_dest)
- ParseParamsxx:函数名称,用户自定义,需要保持唯一。
- op_origin:源算子模型,为protobuf格式的数据结构,来源于Caffe模型的proto文件,存储路径为DDK安装目录下的“/include/inc/custom/proto/caffe/caffe.proto”,若用户自定义的算子在caffe.proto文件中未定义,则需要参考caffe.proto文件算子定义(可选)增加算子定义。
算子插件实现时会根据算子名称从caffe.proto编译生成的proto/caffe/caffe.pb.h文件与caffe.pb.cc文件中读取相关的算子属性进行解析,进而将算子数据结构转换为离线模型支持的数据结构。
DDK中内置的caffe.proto文件的路径为DDK安装目录下的:“/include/inc/custom/proto/caffe/caffe.proto”,用户可基于此文件进行修改,添加自定义算子的定义。
- op_dest:目标算子模型,适配昇腾AI处理器的离线模型的算子数据结构,保存算子信息,Operator类的详细描述请参见《GE API参考》中的“Operator类接口”。
实现流程
ParseParamsxx函数的实现流程如下所示:
- 定义指向LayerParameter的对象,并获取当前算子层的句柄。
const caffe::LayerParameter* layer =dynamic_cast<const caffe::LayerParameter*>(op_origin); const caffe::xxxParameter& param = layer->reduction_param();
其中:
- param对象的类型caffe::xxxParameter中的xxxParameter需要与LayerParameter对象中声明的类型保持一致。
- layer对象的成员函数xxx_param()的名字需要与与LayerParameter对象中声明的对象名字保持一致。
例如caffe.proto中Reduction算子及Convolution算子的定义如下:
message LayerParameter { optional ReductionParameter reduction_param = 136; optional ConvolutionParameter convolution_param = 106; ... }
则获取当前Reduction算子层及Convolution算子层的句柄代码定义如下:
const caffe::ReductionParameter& param = layer->reduction_param()
const caffe::ConvolutionParameter& param = layer->convolution_param()
- 解析算子的每一个属性,并将其赋给Operator类型的对象op_dest。
开发者可调用CreateFrom<AttrValue::T>(DT&& val)接口将DT类型的参数转换为AttrValue类的T类型的参数,然后调用SetAttr(const string& name, const AttrValue& value)接口将转换后的AttrValue对象的值赋给op_dest对象的相应属性。
T类型是昇腾AI软件栈为了简化类型定义,对当前支持的数据类型做的重命名,T类型与原始数据类型的对应关系如表1所示,原型定义可参考DDK安装目录的“include/inc/graph/attr_value.h”文件。
表1 T类型与原始数据类型对应关系 T类型
原始数据类型
INT
int64_t
FLOAT
float
STR
std::string
TENSOR
TensorPtr
TENSOR_DESC
TensorDesc
GRAPH
ComputeGraphPtr
BYTES
Buffer
NAMED_ATTRS
NamedAttrs
BOOL
bool
LIST_INT
vector<INT>
LIST_FLOAT
vector<FLOAT>
LIST_BOOL
vector<BOOL>
LIST_STR
vector<STR>
LIST_TENSOR
vector<TENSOR>
LIST_TENSOR_DESC
vector<TENSOR_DESC>
LIST_GRAPH
vector<GRAPH>
LIST_BYTES
vector<BYTES>
LIST_NAMED_ATTRS
vector<NAMED_ATTRS>
SetAttr接口的详细描述请参见《GE API参考》。
下面给出几种常见类型的参数解析示例:- int或者float类型参数
例如,caffe.proto文件中算子参数定义如下所示:
message ReductionParameter { …… optional int32 axis = 2 [default = 0]; optional float coeff = 3 [default = 1.0]; }
调用SetAttr接口,将“param.axis()”的值赋给op_dest对象的axis属性,并将类型转换为INT;将“param.coeff()”的值赋给op_dest对象的coeff属性,并将类型转换为FLOAT,如下所示:
op_dest.SetAttr("axis", AttrValue::CreateFrom<AttrValue::INT>(param.axis())); op_dest.SetAttr("coeff", AttrValue::CreateFrom<AttrValue::FLOAT>(param.coeff()));
其中CreateFrom<AttrValue::T>(DT&& val)是将DT类型的参数转换为AttrValue类的T类型的参数。
- enum类型参数
例如,caffe.proto文件中算子属性定义如下所示:
message ReductionParameter { enum ReductionOp { SUM = 1; ASUM = 2; SUMSQ = 3; MEAN = 4; } ...}
- 首先,需要将enum类型参数转换为map类型参数。
std::map<caffe::ReductionParameter_ReductionOp, std::string> operation_map = { { caffe::ReductionParameter_ReductionOp_SUM, "SUM" }, { caffe::ReductionParameter_ReductionOp_ASUM, "ASUM" }, { caffe::ReductionParameter_ReductionOp_SUMSQ, "SUMSQ" }, { caffe::ReductionParameter_ReductionOp_MEAN, "MEAN" }, };
- 调用SetAttr接口,将map类型参数operation_map赋值给op_dest对象的operation属性。
op_dest.SetAttr("operation", AttrValue::CreateFrom<AttrValue::STR>(operation_map[param.operation()]));
SetAttr接口的详细描述请参见《GE API参考》。
- 首先,需要将enum类型参数转换为map类型参数。
- repeated类型参数
例如caffe.proto文件中算子参数定义如下所示:
message xxxParameter { ... repeated float min_size = 1; repeated uint32 offset = 2; .... }
- 首先,将repeated float类型参数转换为vector<float>类型参数,将repeated uint32类型参数转换为vector<uint32>类型参数,并对vector类型的参数进行赋值。
vector<float> min_size; vector<uint32> offset; for(int i = 0; i < param.min_size_size(); ++i) { min_size.push_back(param.min_size(i)); //调用vector类型对象的push_back函数为min_size对象赋值 } for(int i = 0; i < param.offset_size(); ++i) { offset.push_back(param.offset(i)); //调用vector对象的push_back函数为offset对象赋值 }
- 调用SetAttr接口,将vector<float>类型参数min_size赋值给op_dest对象的min_size属性;将vector<uint32>类型参数offset赋值给op_dest对象的offset属性,类型为LIST_INT。
op_dest.SetAttr("min_size", ge::AttrValue::CreateFrom<ge::AttrValue::LIST_FLOAT>(min_size)); op_dest.SetAttr("offset", ge::AttrValue::CreateFrom<ge::AttrValue::LIST_INT>(offset));
SetAttr接口的详细描述请参见《GE API参考》。
- 首先,将repeated float类型参数转换为vector<float>类型参数,将repeated uint32类型参数转换为vector<uint32>类型参数,并对vector类型的参数进行赋值。
- int或者float类型参数