拓冰建站拓冰建站
首页 / 资讯中心 / 正文

CANN/GE算子表达样例指南

Graph中各类算子表达样例【免费下载链接】geGEGraph Engine是面向昇腾的图编译器和执行器提供了计算图优化、多流并行、内存复用和模型下沉等技术手段加速模型执行效率减少模型内存占用。 GE 提供对 PyTorch、TensorFlow 前端的友好接入能力并同时支持 onnx、pb 等主流模型格式的解析与编译。项目地址: https://gitcode.com/cann/ge定义数据节点DataGraph的输入节点也就是数据节点使用Data算子实现。Data算子原型定义REG_OP(Data) .INPUT(x, TensorType::ALL()) .OUTPUT(y, TensorType::ALL()) .ATTR(index, Int, 0) .OP_END_FACTORY_REG(Data)根据Data算子原型定义创建Data算子实例名称为data初始化参数为desc_data。同时通过“update_input_desc_输入名称”和“update_output_desc_输出名称”接口设置Shape、Format和Dtype和用户需要处理的数据信息保持一致。auto shape_data vectorint64_t({1,17,2,2}); TensorDesc desc_data(ge::Shape(shape_data), FORMAT_ND, DT_FLOAT); auto data op::Data(data); // 创建Data算子 data.update_input_desc_x(desc_data); // 设置算子输入描述 data.update_output_desc_y(desc_data); // 设置算子输出描述需要注意的是定义数据节点时必须通过“update_input_desc_输入名称”和“update_output_desc_输出名称”接口设置Shape、Format和Dtype。定义常量节点Const权值、偏置等信息为常量Tensor可以通过Const算子实现。Const算子原型定义REG_OP(Const) .OUTPUT(y, TensorType({DT_FLOAT, DT_FLOAT16, DT_BF16, DT_INT4, DT_INT8, DT_INT16, DT_UINT16, \ DT_UINT8, DT_INT32, DT_INT64, DT_UINT32, DT_UINT64, DT_BOOL, DT_DOUBLE})) .ATTR(value, Tensor, Tensor()) .OP_END_FACTORY_REG(Const)直接构造权重数据根据Const算子原型定义创建Const算子实例初始值即属性value的值为weighttensor1。// 构造weighttensor1 TensorDesc weight_desc(ge::Shape({1,3,3,3}), FORMAT_NCHW, DT_INT8); int bs_size_weight 27; int8_t * bs_inputData_weight nullptr; bs_inputData_weight new int8_t[bs_size_weight]; for (int i0; ibs_size_weight; i) { *(bs_inputData_weighti) 1; } Tensor weighttensor1(weight_desc, (uint8_t*)bs_inputData_weight, bs_size_weight*sizeof(int8_t)); // 创建Const算子初始值即属性value的值为weighttensor1 auto weight1 op::Const().set_attr_value(weighttensor1);如果某个算子的原型输入和输出同名代表这个是inplace操作算子即算子的输出会更新输入。该场景下这种输入不能连接Const节点。从文件读入权重数据除了直接构造权重数据外也可以直接从bin文件读入权重数据。// 构造weight_tensor auto weight_shape ge::Shape({ 5,17,1,1 }); TensorDesc desc_weight_1(weight_shape, FORMAT_NCHW, DT_INT8); Tensor weight_tensor(desc_weight_1); uint32_t weight_1_len weight_shape.GetShapeSize(); // const_0.bin 为常量文件的路径 GetConstTensorFromBin(const_0.bin, weight_tensor, weight_1_len*sizeof(int8_t)); // 创建Const算子初始值即属性value的值为weight_tensor auto conv_weight op::Const(const_0).set_attr_value(weight_tensor);GetConstTensorFromBin函数实现bool GetConstTensorFromBin(string path, Tensor weight, uint32_t len) { // 以二进制模式打开文件 ifstream in_file(path.c_str(), std::ios::in | std::ios::binary); if(!in_file.is_open()) { std::cout failed to open path.c_str() \n; return false; } // 将文件指针移动到文件末尾获取文件总大小 in_file.seekg(0, std::ios_base::end); std::istream::pos_type file_size in_file.tellg(); in_file.seekg(0, ios_base::beg); // 将文件指针移回文件开头 // 检查用户指定的len是否与文件实际大小一致 if(len ! file_size) { std::cout Invalid Param.len: len is not equal with binary size( file_size )\n; in_file.close(); return false; } // 为文件内容分配内存缓冲区 char* pdata new(std::nothrow) char[len]; if(pdata nullptr) { std::cout Invalid Param.len: len is not equal with binary size( file_size )\n; in_file.close(); return false; } // 从文件中读取数据到缓冲区 in_file.read(reinterpret_castchar*(pdata), len); // 将缓冲区中的数据设置到Tensor对象weight中 auto status weight.SetData(reinterpret_castuint8_t*(pdata), len); if(status ! ge::GRAPH_SUCCESS) { std::cout Set Tensor Data Failed \n; in_file.close(); return false; } in_file.close(); delete[] pdata; return true; }GetConstTensorFromBin函数参数说明path入参指定权重文件路径用于到固定目录例如“../data/weight/”下查找权重文件xx.bin用户需要自行将权重文件解析为bin文件。weight出参从权重文件中读取的Tensor类型的权重数据。len入参指定权重数据大小。定义必选输入算子SoftmaxV2下面以SoftmaxV2为例介绍如何进行算子定义。SoftmaxV2算子原型定义REG_OP(SoftmaxV2) .INPUT(x, TensorType({ DT_DOUBLE, DT_FLOAT16, DT_BF16, DT_FLOAT })) .OUTPUT(y, TensorType({ DT_DOUBLE, DT_FLOAT16, DT_BF16, DT_FLOAT })) .ATTR(axes, ListInt, {-1}) .ATTR(half_to_float, Bool, false) .OP_END_FACTORY_REG(SoftmaxV2)从SoftmaxV2算子原型可以看到SoftmaxV2算子有一个必选输入输入名称为x。创建SoftmaxV2算子实例auto softmax op::SoftmaxV2(Softmax) // 创建算子实例传算子名称例如Softmax作为入参 .set_input_x(matmul2); // 设置算子输入例如matmul2定义可选输入算子Conv2D下面以Conv2D为例介绍如何进行算子定义。Conv2D算子原型定义REG_OP(Conv2D) .INPUT(x, TensorType({DT_FLOAT16, DT_FLOAT, DT_INT8, DT_BF16})) .INPUT(filter, TensorType({DT_FLOAT16, DT_FLOAT, DT_INT8, DT_BF16})) .OPTIONAL_INPUT(bias, TensorType({DT_FLOAT16, DT_FLOAT, DT_INT32})) .OPTIONAL_INPUT(offset_w, TensorType({DT_INT8})) .OUTPUT(y, TensorType({DT_FLOAT16, DT_FLOAT, DT_INT32, DT_BF16})) .REQUIRED_ATTR(strides, ListInt) .REQUIRED_ATTR(pads, ListInt) .ATTR(dilations, ListInt, {1, 1, 1, 1}) .ATTR(groups, Int, 1) .ATTR(data_format, String, NHWC) .ATTR(offset_x, Int, 0) .OP_END_FACTORY_REG(Conv2D)从Conv2D算子原型定义可以看到Conv2D算子包括两个必选输入x和filter两个可选输入bias和offset_w两个必选属性strides、pads四个可选属性dilations、groups、data_format、offset_x。基于上述定义Conv2D算子定义的代码为auto conv2d op::Conv2D(Conv2d) // quant, conv_weight, conv_bias为三个输入节点 .set_input_x(quant) .set_input_filter(conv_weight) .set_input_bias(conv_bias) .set_attr_strides({ 1, 1, 1, 1 }) .set_attr_pads({ 0, 0, 0, 0 }) .set_attr_dilations({ 1, 1, 1, 1 }); TensorDesc conv2d_input_desc_x(ge::Shape(), FORMAT_NCHW, DT_INT8); TensorDesc conv2d_input_desc_filter(ge::Shape(), FORMAT_NCHW, DT_INT8); TensorDesc conv2d_input_desc_bias(ge::Shape(), FORMAT_NCHW, DT_INT32); TensorDesc conv2d_output_desc_y(ge::Shape(), FORMAT_NCHW, DT_INT32); conv2d.update_input_desc_x(conv2d_input_desc_x); conv2d.update_input_desc_filter(conv2d_input_desc_filter); conv2d.update_input_desc_bias(conv2d_input_desc_bias); conv2d.update_output_desc_y(conv2d_output_desc_y);主要过程为调用算子类型构造函数“Conv2D(const char* name)”创建算子实例并传入算子名称例如Conv2d作为入参。auto conv2d1 op::Conv2D(Conv2d)调用“set_input_输入名称”接口设置算子的输入。.set_input_x(data) .set_input_filter(conv_weight) .set_input_bias(conv_bias)data为整个graph的输入节点通过Data算子构造具体请参考定义数据节点Data。conv_weight为常量数据通过Const算子构造具体请参考定义常量节点Const。conv_bias为常量数据通过Const算子构造具体请参考定义常量节点Const。调用“set_attr_属性名称”接口设置算子的属性。.set_attr_strides({1, 1, 1, 1}) // 设置strides属性值 .set_attr_pads({0, 0, 0, 0}) // 设置pads属性值 .set_attr_dilations({1, 1, 1, 1}); // 设置dilations属性值对于Conv2D等卷积类或对C轴处理敏感的算子建议通过“update_input_desc_输入名称”接口将Format信息设置为NCHW或者NHWC等具体和用户需要处理的Format格式保持一致。TensorDesc conv2d_input_desc_x(ge::Shape(), FORMAT_NCHW, DT_INT8); TensorDesc conv2d_input_desc_filter(ge::Shape(), FORMAT_NCHW, DT_INT8); TensorDesc conv2d_input_desc_bias(ge::Shape(), FORMAT_NCHW, DT_INT32); TensorDesc conv2d_output_desc_y(ge::Shape(), FORMAT_NCHW, DT_INT32); conv2d.update_input_desc_x(conv2d_input_desc_x); conv2d.update_input_desc_filter(conv2d_input_desc_filter); conv2d.update_input_desc_bias(conv2d_input_desc_bias); conv2d.update_output_desc_y(conv2d_output_desc_y);IR构图不支持输入以下FORMATFORMAT_NC1HWC0 FORMAT_FRACTAL_Z FORMAT_NC1C0HWPAD FORMAT_NHWC1C0 FORMAT_FRACTAL_DECONV FORMAT_C1HWNC0 FORMAT_FRACTAL_DECONV_TRANSPOSE FORMAT_FRACTAL_DECONV_SP_STRIDE_TRANS FORMAT_NC1HWC0_C04 FORMAT_FRACTAL_Z_C04 FORMAT_FRACTAL_DECONV_SP_STRIDE8_TRANS FORMAT_NC1KHKWHWC0 FORMAT_C1HWNCoC0 FORMAT_FRACTAL_ZZ FORMAT_FRACTAL_NZ FORMAT_NDC1HWC0 FORMAT_FRACTAL_Z_3D FORMAT_FRACTAL_Z_3D_TRANSPOSE FORMAT_FRACTAL_ZN_LSTM FORMAT_FRACTAL_Z_G FORMAT_ND_RNN_BIAS FORMAT_FRACTAL_ZN_RNN FORMAT_NYUV FORMAT_NYUV_A定义动态多输入算子AddN某些算子的输入个数不固定为动态多输入算子例如AddN下面介绍如何定义这类算子。AddN算子原型定义REG_OP(AddN) .DYNAMIC_INPUT(x, TensorType({NumberType(), DT_VARIANT})) .OUTPUT(y, TensorType({NumberType(), DT_VARIANT})) .REQUIRED_ATTR(N, Int) .OP_END_FACTORY_REG(AddN)通过AddN算子原型定义可以看到该算子为动态多输入算子我们通过“create_dynamic_input_输入名称”创建动态输入通过“set_dynamic_input_输入名称”设置动态输入。auto data op::Data().set_attr_index(0); auto addn op::AddN(addn) .create_dynamic_input_x(2) // 创建动态输入x包括2个输入并且把这两个输入作为算子最后的输入 .set_dynamic_input_x(0,data) // 设置第1个输入0表示输入索引默认从0开始data表示输入value .set_dynamic_input_x(1,data) // 设置第2个输入1表示输入索引默认从0开始data表示输入value .set_attr_N(2); // 设置属性N的值为2表示该算子有2个输入也可以通过“create_dynamic_input_byindex_输入名称”创建动态输入但是和“create_dynamic_input_输入名称”不能同时使用两者的区别是“create_dynamic_input_输入名称”默认把创建的动态输入作为算子最后的输入而“create_dynamic_input_byindex_输入名称”可以指定动态输入的索引位置例如auto addn op::AddN(addn) .create_dynamic_input_byindex_x(2,0) // 创建动态输入x包括2个输入并将这两个输入插入到索引0和索引1的位置其中0表示动态输入的起始索引 .set_dynamic_input_x(0,data1) // 设置第1个输入0表示输入索引默认从0开始data1表示输入value .set_dynamic_input_x(1,data2) // 设置第2个输入1表示输入索引默认从0开始data2表示输入value .set_attr_N(2); // 设置属性N的值为2表示该算子有2个输入定义动态多输出算子Split某些算子的输出个数不固定为动态多输出算子例如Split下面介绍如何定义这类算子。Split算子原型定义REG_OP(Split) .INPUT(split_dim, TensorType({DT_INT32})) .INPUT(x, TensorType({DT_COMPLEX128, DT_COMPLEX64, DT_DOUBLE, DT_FLOAT, DT_FLOAT16, DT_INT16, DT_INT32, DT_INT64, DT_INT8, DT_QINT16, DT_QINT32, DT_QINT8, DT_QUINT16, DT_QUINT8, DT_UINT16, DT_UINT32, DT_UINT64, DT_UINT8, DT_BF16, DT_BOOL})) .DYNAMIC_OUTPUT(y, TensorType({DT_COMPLEX128, DT_COMPLEX64, DT_DOUBLE, DT_FLOAT, DT_FLOAT16, DT_INT16, DT_INT32, DT_INT64, DT_INT8, DT_QINT16, DT_QINT32, DT_QINT8, DT_QUINT16, DT_QUINT8, DT_UINT16, DT_UINT32, DT_UINT64, DT_UINT8, DT_BF16, DT_BOOL})) .REQUIRED_ATTR(num_split, Int) .OP_END_FACTORY_REG(Split)Split算子原型定义可以看到该算子为动态多输出算子我们通过“create_dynamic_output_输出名称”创建动态输出。auto split op::Split(split) .set_input_x(data) // 构造Data算子 .set_input_split_dim(const) // 构造Const算子 .set_attr_num_split(2) .create_dynamic_output_y(2); // 创建split算子的动态输出y包括2个输出 auto addn op::AddN(addn) .create_dynamic_input_x(1) // 创建动态输入x包括1个输入 .set_dynamic_input_x(0, split, y0) // 设置addn算子的第1个输入split表示输入算子“y0”表示split算子的输出名称 y0为第一个输出 .set_attr_N(1); // 设置属性N的值为1表示该算子有1个输入 auto softplus op::Softplus(softplus) .set_input_x(split, y1); // 设置softplus算子的输入split表示输入算子y1表示split算子的第2个输出如何构造Data算子请参考定义数据节点Data如何构造Const算子请参考定义常量节点Const。定义数据类型转换算子Cast通过算子原型构建Graph时要求前后算子的dtype必须一致上一个算子的输出dtype如果和下一层算子的输入dtype不匹配时需要插入Cast算子。例如下面示例中AddN算子要求输入float32但是Greater算子的输出是bool类型在数据类型发生变换的情况下需要通过插入Cast算子进行数据类型转换。Cast算子原型定义REG_OP(Cast) .INPUT(x, TensorType({DT_BOOL, DT_FLOAT16, DT_FLOAT, DT_INT8, DT_INT32, DT_UINT32, DT_UINT8, DT_INT64, DT_UINT64, DT_INT16, DT_UINT16, DT_DOUBLE, DT_COMPLEX64, DT_COMPLEX128, DT_QINT8, DT_QUINT8, DT_QINT16, DT_QUINT16, DT_QINT32, DT_BF16, DT_UINT1})) .OUTPUT(y, TensorType({DT_BOOL, DT_FLOAT16, DT_FLOAT, DT_INT8, DT_INT32, DT_UINT32, DT_UINT8, DT_INT64, DT_UINT64, DT_INT16, DT_UINT16, DT_DOUBLE, DT_COMPLEX64, DT_COMPLEX128, DT_QINT8, DT_QUINT8, DT_QINT16, DT_QUINT16, DT_QINT32, DT_BF16, DT_COMPLEX32})) .REQUIRED_ATTR(dst_type, Int) .OP_END_FACTORY_REG(Cast)从Cast算子原型定义可以看到有一个必选属性dst_type表示转换后的数据类型设置为0表示转换后的数据类型为float32值和数据类型对应关系请参见《基础数据结构和接口》中的ge命名空间DataType。auto greater op::Greater(greater).set_input_x1(const1).set_input_x2(const2); auto cast op::Cast(cast).set_input_x(greater) .set_attr_dst_type(0); auto addn op::AddN(addn).create_dynamic_input_x(3) .set_dynamic_input_x(0,cast) .set_dynamic_input_x(1,data).set_dynamic_input_x(2,data) .set_attr_N(3);【免费下载链接】geGEGraph Engine是面向昇腾的图编译器和执行器提供了计算图优化、多流并行、内存复用和模型下沉等技术手段加速模型执行效率减少模型内存占用。 GE 提供对 PyTorch、TensorFlow 前端的友好接入能力并同时支持 onnx、pb 等主流模型格式的解析与编译。项目地址: https://gitcode.com/cann/ge创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门