ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CANN / GE 扩展算子规则

CANN / GE 扩展算子规则 扩展算子规则【免费下载链接】geGEGraph Engine是面向昇腾的图编译器和执行器提供了计算图优化、多流并行、内存复用和模型下沉等技术手段加速模型执行效率减少模型内存占用。 GE 提供对 PyTorch、TensorFlow 前端的友好接入能力并同时支持 onnx、pb 等主流模型格式的解析与编译。项目地址: https://gitcode.com/cann/ge扩展算子的实现可以在Caffe、TensorFlow、MindSpore深度学习框架中获取扩展算子中的第一种是基于Caffe框架进行扩展实现的如ROIPooling、PSROIPooling、Normalize和Upsample层等因此有公开的prototxt标准定义。而扩展算子中的第二种并不是在Caffe框架下实现的对于这类网络中的自定义算子也需要给出prototxt的标准定义用于在prototxt中定义网络中相应的算子。Reverse在指定的轴上反序如输入为[1,2,3]其反序为[3,2,1]。算子定义如下在LayerParameter中添加ReverseParametermessage LayerParameter { ... optional ReverseParameter reverse_param 157; ... }定义ReverseParameter类型以及属性参数message ReverseParameter{ repeated int32 axis 1; }ROIPooling在目标检测算法中region proposal产生的ROI大小不一而分类网络的FC层要固定的输入所以ROIPooling起到一个连接作用。ROIPooling层为Faster RCNN网络中用于将不同图像经过卷积层后得到的feature map进行维度统一的操作输入为一个feature map以及需要从中提取的ROI框坐标值输出为一个维度归一化的feature map。ROIPooling层需要对caffe.proto文件进行扩展定义ROIPoolingParameter扩展方式如下所示定义的参数包括spatial_scale即输入feature map与原始图片的尺寸比例用于转换ROI的坐标因为ROI坐标是在原图尺寸上的。pooled_h、pooled_w输出feature map在spatial维度上h和w的大小。在LayerParameter中添加ROIPoolingParametermessage LayerParameter { ... optional ROIPoolingParameter roi_pooling_param 161; ... }定义ROIPoolingParameter类型以及属性参数message ROIPoolingParameter { required int32 pooled_h 1; required int32 pooled_w 2; optional float spatial_scale 3 [default0.0625]; optional float spatial_scale_h 4; optional float spatial_scale_w 5; }基于上述原则ROIPooling层在prototxt中定义的代码样例如下layer { name: roi_pooling type: ROIPooling bottom: res4f bottom: rois bottom: actual_rois_num top: roi_pool roi_pooling_param { pooled_h: 14 pooled_w: 14 spatial_scale:0.0625 spatial_scale_h:0.0625 spatial_scale_w:0.0625 } }PSROIPoolingPSROIPooling层的操作与ROIPooling层类似不同之处在于不同空间维度输出的图片特征来自不同的feature map channels且对每个小区域进行的是Average Pooling不同于ROIPooling的Max Pooling。对于一个输出k*k的结果不同空间维度的特征取自输入feature map中不同的组即将输入的feature map均匀分为k*k组每组的channel数与输出的channel一致得到上述输出。PSROIPooling层需要对caffe.proto文件进行扩展定义PSROIPoolingParameter扩展方式如下所示定义的参数包括spatial_scale即输入feature map与原始图片的尺寸比例。output_dim输出feature map的channel。group_size输出的spatial维度即上述的k。在LayerParameter中添加PSROIPoolingParametermessage LayerParameter { ... optional PSROIPoolingParameter psroi_pooling_param 207; ... }定义PSROIPoolingParameter类型以及属性参数message PSROIPoolingParameter { required float spatial_scale 1; required int32 output_dim 2; // output channel number required int32 group_size 3; // number of groups to encode position-sensitive score maps }基于上述原则PSROIPooling层在prototxt中定义的代码样例如下layer { name: psroipooling type: PSROIPooling bottom: some_input bottom: some_input top: some_output psroi_pooling_param { spatial_scale: 0.0625 output_dim: 21 group_size: 7 } }UpsampleUpsample层为Pooling层的逆操作其中每个Upsample层均与网络之前一个对应大小输入、输出Pooling层一一对应完成feature map在spatial维度上的扩充。Upsample层需要对caffe.proto文件进行扩展定义UpsampleParameter扩展方式示例如下所示。定义的参数包括stride即输出与输入的尺寸比例如2。在LayerParameter中添加UpsampleParametermessage LayerParameter { ... optional UpsampleParameter upsample_param 160; ... }定义UpsampleParameter类型以及属性参数message UpsampleParameter{ optional float scale 1[default 1]; optional int32 stride 2[default 2]; optional int32 stride_h 3[default 2]; optional int32 stride_w 4[default2]; }基于上述原则Upsample在prototxt中定义的代码样例如下layer { name: layer86-upsample type: Upsample bottom: some_input top: some_output upsample_param { scale: 1 stride: 2 } }NormalizeNormalize层为SSD网络中的一个归一化层主要作用是将空间或者通道内的元素归一化到0到1之间其进行的操作为对于一个c*h*w的三维tensor输出是同样大小的tensor其中间计算为每个元素以channel方向的平方和的平方根求normalize其具体计算公式为$$ x_i \frac{x_i}{\sqrt{\sum_{i1}^{c} x_i^2}} $$其中分母位置的平方和的累加向量为同一h与w位置的所有c方向的向量如图1中的橙色区域。图 1Normalize层原理图 ![](https://raw.gitcode.com/cann/ge/raw/a67f6ec35ec66842d35cb5db9c8d9a4c34d31086/docs/zh/user_guides/atc_tools/figures/normalize_layer_principle.png Normalize层原理图?utm_sourcegitcode_repo_files)经过上述计算归一化后再对每个feature map做scale每个channel对应一个scale值。Normalize层需要对caffe.proto文件进行扩展定义NormalizeParameter扩展方式如下所示。定义的参数包括across_spatial参数表示是否对整个图片进行归一化归一化的维度为1 x c x h x w否则对每个像素点进行归一化1 x c x 1 x 1。channel_shared表示scale是否相同如果为true则scale都是一样的否则对于channel一样对不同channel像素点是不一样的默认为True。eps防止normalize过程中除以0的一个很小数值默认为1e-10可配置。normalize的计算公式转换为$$ x_i \frac{x_i}{\sqrt{\sum_{i1}^{n} x_i^2 \text{eps}}} \times \text{scale}_i $$算子定义如下在LayerParameter中添加NormalizeParametermessage LayerParameter { ... optional NormalizeParameter norm_param 206; ... }定义NormalizeParameter类型以及属性参数message NormalizeParameter { optional bool across_spatial 1 [default true]; // Initial value of scale. Default is 1.0 for all optional FillerParameter scale_filler 2; // Whether or not scale parameters are shared across channels. optional bool channel_shared 3 [default true]; // Epsilon for not dividing by zero while normalizing variance optional float eps 4 [default 1e-10]; }基于上述原则Normalize在prototxt中定义的代码样例如下layer { name: normalize_layer type: Normalize bottom: some_input top: some_output norm_param { across_spatial: false scale_filler { type: constant value: 20 } channel_shared: false } }ReorgReorg算子在AI处理器内部以PassThrough算子呈现将通道数据转移到平面上或反过来操作。PassThrough层为Yolo v2中的一个自定义层由于Yolo v2并不是使用Caffe框架实现因此对于该层没有标准的定义。该层实现的功能为将feature map在spatial维度上的数据展开到channel维度上原始在channel维度上连续的元素在展开后的feature map中依然是连续的。算子定义如下在LayerParameter中添加ReorgParametermessage LayerParameter { ... optional ReorgParameter reorg_param 155; ... }定义ReorgParameter类型以及属性参数message ReorgParameter{ optional uint32 stride 2 [default 2]; optional bool reverse 1 [default false]; }基于上述原则Reorg在prototxt中定义的代码样例如下layer { bottom: some_input top: some_output name: reorg type: Reorg reorg_param { stride: 2 } }ProposalProposal算子根据rpn_cls_prob的foregroundrpn_bbox_pred中的bounding box regression修正anchors获得精确的proposals。具体可以分为3个算子decoded_bbox、topk和nms实现如图2所示。图 2Proposal算子实现 ![](https://raw.gitcode.com/cann/ge/raw/a67f6ec35ec66842d35cb5db9c8d9a4c34d31086/docs/zh/user_guides/atc_tools/figures/proposal_op.png Proposal算子实现?utm_sourcegitcode_repo_files)算子定义如下在LayerParameter中添加ProposalParametermessage LayerParameter { ... optional ProposalParameter proposal_param 201; ... }定义ProposalParameter类型以及属性参数message ProposalParameter { optional float feat_stride 1 [default 16]; optional float base_size 2 [default 16]; optional float min_size 3 [default 16]; repeated float ratio 4; repeated float scale 5; optional int32 pre_nms_topn 6 [default 3000]; optional int32 post_nms_topn 7 [default 304]; optional float iou_threshold 8 [default 0.7]; optional bool output_actual_rois_num 9 [default false]; }基于上述原则Proposal在prototxt中定义的代码样例如下layer { name: faster_rcnn_proposal type: Proposal // 算子Type bottom: rpn_cls_prob_reshape bottom: rpn_bbox_pred bottom: im_info top: rois top: actual_rois_num // 增加的算子输出 proposal_param { feat_stride: 16 base_size: 16 min_size: 16 pre_nms_topn: 3000 post_nms_topn: 304 iou_threshold: 0.7 output_actual_rois_num: true } }[!NOTE]说明如果用户的网络模型中存在“ProposalROIAlign业务算子”相关的网络结构由于Proposal算子的输出为3维而ROIAlign算子的rois是2维因此需要在Proposal算子后面增加Reshape算子用来改变Tensor shape然后作为ROIAlign的输入。但该场景下输入给ROIAlign算子的rois框数据坐标排序混乱不符合ROIAlign算子的要求。 基于上述问题需要在Reshape算子后再增加Permute算子进行转置之后再次输出的数据符合ROIAlign算子的要求。修改后的网络结构样例如下对应修改后的prototxt中代码样例如下layer { name: proposal type: Proposal bottom: rpn_cls bottom: rpn_loc bottom: img_info top: roi_proposal proposal_param { feat_stride: 16 pre_nms_topn: 1000 post_nms_topn: 16 nms_thresh: 0.7 base_size: 16 min_size: 8 ratio: [0.5, 1.0, 2.0] scale: [32, 64, 128, 256, 512] } } layer { name: Reshape1 type: Reshape bottom: roi_proposal top: roi_proposal_reshape reshape_param { shape { dim: 5 dim: 16 } } } layer { name: Permute1 type: Permute bottom: roi_proposal_reshape top: roi_proposal_permute permute_param { order: 1 order: 0 } } layer { name: align type: ROIAlign bottom: 111 bottom: roi_proposal_permute top: align roi_align_param { pooled_w: 14 pooled_h: 14 spatial_scale: 0.0625 } }ROIAlignROIAlign是在Mask-RCNN论文里提出的一种区域特征聚集方式与ROIPooling算法进行改进用双线性插值替换ROIPooling操作中两次量化以解决ROIPooling造成的区域不匹配的问题提高检测准确性。ROIAlign算子是从feature map中获取ROIrange of interest分为pooled_w x pooled_h个单元格每个单元格均分为sampling_ratio*sampling_ratio个小方格每个小方格的中心点就是采样点。如图3所示虚线部分表示feature map实线表示ROI这里将ROI切分成2x2的单元格。如果采样点数是4则首先将每个单元格均分成四个小方格如红色线所示每个小方格中心就是采样点。由于采样点的坐标通常是浮点数所以需要对采样点像素进行双线性插值如图3中的四个箭头所示就可以得到该像素点的值了。然后对每个单元格内的四个采样点取均值就可以得到最终的ROIAlign的结果。图 3ROIAlign原理图 ![](https://raw.gitcode.com/cann/ge/raw/a67f6ec35ec66842d35cb5db9c8d9a4c34d31086/docs/zh/user_guides/atc_tools/figures/roialign_principle.png ROIAlign原理图?utm_sourcegitcode_repo_files)算子定义如下在LayerParameter中添加ROIAlignParametermessage LayerParameter { ... optional ROIAlignParameter roi_align_param 154; ... }定义ROIAlignParameter类型以及属性参数message ROIAlignParameter { // Pad, kernel size, and stride are all given as a single value for equal // dimensions in height and width or as Y, X pairs. optional uint32 pooled_h 1 [default 0]; // The pooled output height optional uint32 pooled_w 2 [default 0]; // The pooled output width // Multiplicative spatial scale factor to translate ROI coords from their // input scale to the scale used when pooling optional float spatial_scale 3 [default 1]; optional int32 sampling_ratio 4 [default -1]; optional int32 roi_end_mode 5 [default 0]; }根据上述类型以及属性用户可以自定义prototxt。ShuffleChannelShuffleChannel是把channel维度分为[group, channel/group]然后再在channel维度中进行数据转置[channel/group,group]。例如对于channel4group2则执行此算子后就是把channel[1]、channel[2]的数据交换位置。算子定义如下在LayerParameter中添加ShuffleChannelParametermessage LayerParameter { ... optional ShuffleChannelParameter shuffle_channel_param 159; ... }定义ShuffleChannelParameter类型以及属性参数message ShuffleChannelParameter{ optional uint32 group 1[default 1]; // The number of group }基于上述原则ShuffleChannel在prototxt中定义的代码样例如下layer { name: layer_shuffle type: ShuffleChannel bottom: some_input top: some_output shuffle_channel_param { group: 3 } }YoloYOLO算子出现在YOLO V2网络且目前仅在YOLO V2、V3网络中使用对数据做sigmoid和softmax操作。在YOLO V2中根据background和softmax的参数有4种场景backgroundfalsesoftmaxtrue对(x,y,h,w)中的(x,y)做sigmoid对b做sigmoid对classes做softmax。backgroundfalsesoftmaxfalse对(x,y,h,w)中的(x,y)做sigmoid对b做sigmoid对classes做sigmoid。backgroundtruesoftmaxfalse对(x,y,h,w)中的(x,y)做sigmoid对b不做计算对classes做sigmoid。backgroundtruesoftmax true对(x,y,h,w)中的(x,y)做sigmoid对b和classes放在一起做softmax。在YOLO V3中只有一种场景对(x,y,h,w)中的(x,y)做sigmoid对b做sigmoid对classes做sigmoid。输入数据格式为Tensor(n, coordsbackgroundclasses,l.h,l.w)其中n是anchor box的数量coords表示x,y,w,h。算子定义如下在LayerParameter中添加YoloParametermessage LayerParameter { ... optional YoloParameter yolo_param 199; ... }定义YoloParameter类型以及属性参数message YoloParameter { optional int32 boxes 1 [default 3]; optional int32 coords 2 [default 4]; optional int32 classes 3 [default 80]; optional string yolo_version 4 [default V3]; optional bool softmax 5 [default false]; optional bool background 6 [default false]; optional bool softmaxtree 7 [default false]; }基于上述原则Yolo在prototxt中定义的代码样例如下layer { bottom: layer82-conv top: yolo1_coords top: yolo1_obj top: yolo1_classes name: yolo1 type: Yolo yolo_param { boxes: 3 coords: 4 classes: 80 yolo_version: V3 softmax: true background: false } }PriorBox根据输入的参数生成prior box。下面以conv7_2_mbox_priorbox为例根据对应的参数生成prior box的数量。定义如下layer{ name:conv7_2_mbox_priorbox type:PriorBox bottom:conv7_2 bottom:data top:conv7_2_mbox_priorbox prior_box_param{ min_size:162.0 max_size:213.0 aspect_ratio:2 aspect_ratio:3 flip:true clip:false variance:0.1 variance:0.1 variance:0.2 variance:0.2 img_size:300 step:64 offset:0.5 } }宽高都为min_size生成prior box。如果存在max_size则用sqrt(min_size*max_size)确定宽高生成一个框约束max_sizemin_size。根据aspect_ratio如定义所示aspect_ratio为23flip是true自动添加aspect_ratio1/2、1/3生成对应的prior box。因此num_priorsprior box的数量min_size的数量aspect_ratio的数量这里为4*min_size的数量这里为1max_size的数量max_size的数量和min_size的数量一一对应。算子定义如下在LayerParameter中添加PriorBoxParametermessage LayerParameter { ... optional PriorBoxParameter prior_box_param 203; ... }定义PriorBoxParameter类型以及属性参数message PriorBoxParameter { // Encode/decode type. enum CodeType { CORNER 1; CENTER_SIZE 2; CORNER_SIZE 3; } // Minimum box size (in pixels). Required! repeated float min_size 1; // Maximum box size (in pixels). Required! repeated float max_size 2; // Various of aspect ratios. Duplicate ratios will be ignored. // If none is provided, we use default ratio 1. repeated float aspect_ratio 3; // If true, will flip each aspect ratio. // For example, if there is aspect ratio r, // we will generate aspect ratio 1.0/r as well. optional bool flip 4 [default true]; // If true, will clip the prior so that it is within [0, 1] optional bool clip 5 [default false]; // Variance for adjusting the prior bboxes. repeated float variance 6; // By default, we calculate img_height, img_width, step_x, step_y based on // bottom[0] (feat) and bottom[1] (img). Unless these values are explicitely // provided. // Explicitly provide the img_size. optional uint32 img_size 7; // Either img_size or img_h/img_w should be specified; not both. optional uint32 img_h 8; optional uint32 img_w 9; // Explicitly provide the step size. optional float step 10; // Either step or step_h/step_w should be specified; not both. optional float step_h 11; optional float step_w 12; // Offset to the top left corner of each cell. optional float offset 13 [default 0.5]; }基于上述原则PriorBox在prototxt中定义的代码样例如下layer { name: layer_priorbox type: PriorBox bottom: some_input bottom: some_input top: some_output prior_box_param { min_size: 30.0 max_size: 60.0 aspect_ratio: 2 flip: true clip: false variance: 0.1 variance: 0.1 variance: 0.2 variance: 0.2 step: 8 offset: 0.5 } }SpatialTransformer该算子计算过程其实做了一个仿射变换仿射变换的参数可以是在prototxt固定的多个batch使用一份也可以是层的第二个输入每个batch使用不一样的参数。计算步骤对于输出坐标通过如下公式将其变换成[-1,1]区间中的值。$$ X x \times \frac{1.0}{\text{out}_h} \times 2 -1 $$$$ y y \times \frac{1.0}{\text{out}_w} \times 2 -1 $$计算代码如下Dtype* data output_grid.mutable_cpu_data(); for(int i0; i output_H_ * output_W_; i) { data[3 * i] (i / output_W_) * 1.0 / output_H_ * 2 - 1; data[3 * i 1] (i % output_W_) * 1.0 / output_W_ * 2 - 1; data[3 * i 2] 1; }通过仿射变换转换为输入的坐标其中s为输入坐标t为输出坐标计算公式如下$$ \begin{pmatrix} x_i^s \ y_i^s \end{pmatrix}\begin{bmatrix} \theta_{11} \theta_{12} \theta_{13} \ \theta_{21} \theta_{22} \theta_{23} \ \end{bmatrix} \begin{pmatrix} x_i^t \ y_i^t 1 \end{pmatrix} $$计算代码如下caffe_cpu_gemmDtype(CblasNoTrans, CblasTrans, output_H_ * output_W_, 2, 3, (Dtype)1., output_grid_data, full_theta_data 6 * i, (Dtype)0., coordinates);通过输入坐标取对应位置的值赋值给输出的对应位置。因为在第一步对输出坐标做了一次转换所以对应的输入坐标使用同样的方式再缩放回去代码样例如下Dtype x (px 1) / 2 * H; Dtype y (py 1) / 2 * W; if(debug) std::coutprefix(x, y) (x, y)std::endl; for(int m floor(x); m ceil(x); m) for(int n floor(y); n ceil(y); n) { if(debug) std::coutprefix(m, n) (m, n)std::endl; if(m 0 m H n 0 n W) { res (1 - abs(x - m)) * (1 - abs(y - n) * pic[m * W n]); if(debug) std::coutprefix pic[m * W n] std::endl; } }算子定义如下在LayerParameter中添加SpatialTransformParametermessage LayerParameter { ... optional SpatialTransformParameter spatial_transform_param 153; ... }定义SpatialTransformParameter类型以及属性参数message SpatialTransformParameter { optional uint32 output_h 1 [default 0]; optional uint32 output_w 2 [default 0]; optional float border_value 3 [default 0]; repeated float affine_transform 4; enum Engine { DEFAULT 0; CAFFE 1; CUDNN 2; } optional Engine engine 15 [default DEFAULT]; }基于上述原则SpatialTransform层在prototxt中定义的代码样例如下layer { name: st_1 type: SpatialTransformer bottom: data bottom: theta top: transformed st_param { to_compute_dU: false theta_1_1: -0.129 theta_1_2: 0.626 theta_2_1: 0.344 theta_2_2: 0.157 } }【免费下载链接】geGEGraph Engine是面向昇腾的图编译器和执行器提供了计算图优化、多流并行、内存复用和模型下沉等技术手段加速模型执行效率减少模型内存占用。 GE 提供对 PyTorch、TensorFlow 前端的友好接入能力并同时支持 onnx、pb 等主流模型格式的解析与编译。项目地址: https://gitcode.com/cann/ge创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表