更新时间:2021-03-18 GMT+08:00
分享

解析算子

对于用户新开发的自定义算子,需要自定义实现解析算子中属性的函数,将原始模型中的算子属性定义转换为适配昇腾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函数的实现流程如下所示:

  1. 定义指向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()

  2. 解析算子的每一个属性,并将其赋给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;
        }
      ...}
      1. 首先,需要将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" },
            };
      2. 调用SetAttr接口,将map类型参数operation_map赋值给op_dest对象的operation属性。
        op_dest.SetAttr("operation", AttrValue::CreateFrom<AttrValue::STR>(operation_map[param.operation()]));

        SetAttr接口的详细描述请参见《GE API参考》

    • repeated类型参数

      例如caffe.proto文件中算子参数定义如下所示:

      message xxxParameter {
      ...
        repeated float min_size = 1;
        repeated uint32 offset = 2;
      ....
      }
      1. 首先,将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对象赋值
        }
      2. 调用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参考》

分享:

    相关文档

    相关产品