定制网络修改(Caffe)
简介
本章节修改只适用于Caffe网络模型。
网络的算子可以分为如下几类:
- 标准算子:昇腾AI处理器支持的Caffe标准算子,比如Convolution等。
- 扩展算子:昇腾AI处理器支持的公开但非Caffe标准算子,分为 2 种:
- 一种是基于Caffe框架进行自定义扩展的算子,比如Faster RCNN中的ROIPooling、SSD中的归一化算子Normalize等。
- 另外一种是来源于其他深度学习框架的自定义算子,比如YOLOv2中Passthrough等。
Faster RCNN、SSD等网络都包含了一些原始Caffe框架中没有定义的算子结构,如ROIPooling、Normalize、PSROI Pooling和Upsample等。为了使昇腾AI处理器能支持这些网络,需要对原始的Caffe框架网络模型进行扩展,降低开发者开发自定义算子/开发后处理代码的工作量。若开发者的Caffe框架网络模型中使用了这些扩展算子,在进行模型转换时,需要先在prototxt中修改/添加扩展层的定义,才能成功进行模型转换。
本章节提供了昇腾AI处理器的扩展算子列表,并给出了如何根据扩展算子修改prototxt文件的方法。
扩展算子列表
分类 |
算子类型 |
说明 |
---|---|---|
过程算子 |
将输入tensor指定的轴进行反转。 |
|
用于Faster R-CNN中,对Roi(Region of interest)进行池化操作,主要用于目标检测任务。 |
||
用于R-FCN中,进行位置敏感的候选区域池化操作,主要用于目标检测任务。 |
||
使用pooling mask的上采样。 用于yolo网络。 |
||
将SSD网络中Channel维度中的元素在L2进行归一化。 |
||
Reorg layer in Darknet,将通道数据转移到平面上,或反过来操作。 对应算子规格中的PassThrough算子。 |
||
用于Faster R-CNN,根据rpn_cls_prob的foreground,rpn_bbox_pred中的bounding box regression修正anchors获得精确的proposals。 |
||
从feature map中获取ROI(range of interest)的特征矩阵。 |
||
把channel维度分为[group, channel/Group],再在channel维度中进行数据转置[channel/Group,group]。 |
||
Yolo(Yolo/Detection/Region) |
Yolo/Detection/Region算子,都需要替换为Yolo算子,对卷积网络输出的feature map生成检测框的坐标信息,置信度信息及类别概率。 |
|
用于SSD网络,根据输入参数,生成prior box。 |
||
用于仿射变换。 |
||
后处理算子 |
YoloV3DetectionOutput |
此算子用于YOLOv3的后处理过程,对卷积网络输出的feature map生成检测框的坐标信息,置信度信息及类别概率。 |
YoloV2DetectionOutput |
此算子用于YOLOv2的后处理过程,对卷积网络输出的feature map生成检测框的坐标信息,置信度信息及类别概率。 |
|
SSDDetectionOutput |
此算子用于SSD网络的后处理过程,用于整合预选框、预选框偏移以及得分三项结果,最终输出满足条件的目标检测框、目标的label和得分。 |
|
FSRDetectionOutput |
此算子用于Faster R-CNN网络的后处理过程,对结果进行分类,并对每个类输出最终的bbox数量、坐标、类别概率及类别索引。 |
扩展算子规则
扩展算子的实现可以在Caffe、TensorFlow、MindSpore深度学习框架中实现,扩展算子中的第一种是基于Caffe框架进行扩展实现的,如ROIPooling、Normalize、PSROIPolling和Upsample层等,因此有公开的prototxt标准定义。而扩展算子中的第二种并不是在Caffe框架下实现的,对于这类网络中的自定义算子,也需要给出prototxt的标准定义,用于在prototxt中定义网络中相应的算子。
Reverse
在指定的轴上反序,如输入为[1,2,3],其反序为[3,2,1]。
算子定义如下:
- 在LayerParameter中添加ReverseParameter
message LayerParameter { ... optional ReverseParameter reverse_param = 157; ... }
- 定义ReverseParameter类型以及属性参数
message ReverseParameter{ repeated int32 axis = 1; }
ROIPooling
在目标检测算法中,region proposal产生的ROI大小不一,而分类网络的FC层要固定的输入,所以ROIPooing起到一个连接作用。
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中添加ROIPoolingParameter
message 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 [default=0.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 } }
PSROIPooling
PSROIPooling层的操作与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中添加PSROIPoolingParameter
message 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 } }
Upsample
Upsample层为Pooling层的逆操作,其中每个Upsample层均与网络之前一个对应大小输入、输出Pooling层一一对应,完成feature map在spatial维度上的扩充。
Upsample层需要对caffe.proto文件进行扩展,定义UpsampleParameter,扩展方式示例如下所示。 定义的参数包括stride,即输出与输入的尺寸比例,如2。
- 在LayerParameter中添加UpsampleParameter
message 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[default=2]; }
基于上述原则,Upsample在prototxt中定义的代码样例如下:
layer { name: "layer86-upsample" type: "Upsample" bottom: "some_input" top: "some_output" upsample_param { scale: 1 stride: 2 } }
Normallize
Normalize层为SSD网络中的一个归一化层,主要作用是将空间或者通道内的元素归一化到0到1之间,其进行的操作为对于一个c*h*w的三维tensor,输出是同样大小的tensor,其中间计算为每个元素以channel方向的平方和的平方根求 normalize,其具体计算公式为:
其中分母位置的平方和的累加向量为同一h与w位置的所有c方向的向量,如图2-6中的橙色区域。
经过上述计算归一化后,再对每个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。
- channels_shared表示scale是否相同,如果为true,则scale都是一样的,否则对于channel一样,对不同channel像素点是不一样的,默认为True。
- eps防止normalize过程中除以0的一个很小数值,默认为1e-10,可配置。
normalize的计算公式转换为:
算子定义如下:
- 在LayerParameter中添加NormalizeParameter
message 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 } }
Reorg
Reorg算子在昇腾AI处理器内部以PassThrough算子呈现,将通道数据转移到平面上,或反过来操作。
PassThrough层为Yolo v2中的一个自定义层,由于Yolo v2并不是使用Caffe框架实 现,因此对于该层没有标准的定义。该层实现的功能为将feature map在spatial维度上的数据展开到channel维度上,原始在channel维度上连续的元素在展开后的feature map中依然是连续的。
算子定义如下:
- 在LayerParameter中添加ReorgParameter
message 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 } }
Proposal
proposal算子根据rpn_cls_prob的foreground,rpn_bbox_pred中的bounding box regression修正anchors获得精确的proposals。
具体可以分为3个算子decoded_bbox、topk和nms,实现如图2-7所示。
算子定义如下:
- 在LayerParameter中添加ProposalParameter
message 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 } }
ROIAlign
ROI Align 是在Mask-RCNN论文里提出的一种区域特征聚集方式, 与ROIPooling算法进行改进:用双线性插值替换ROI Pooling操作中两次量化,以解决ROIPooling造成的区域不匹配的问题,提高检测准确性。
ROIAlign算子是从feature map中获取ROI(range of interest),分为pooled_h x pooled_h 个单元格,每个单元格均分为sampling_ratio*sampling_ratio个小方格,每个小方格的中心点就是采样点。如图2-8所示,虚线部分表示feature map,实线表示ROI,这里将ROI切分成2x2的单元格。如果采样点数是4,则首先将每个单元格子均分成四个小方格(如红色线所示),每个小方格中心就是采样点。由于采样点的坐标通常是浮点数,所以需要对采样点像素进行双线性插值(如图2-8中的四个箭头所示),就可以得到该像素点的值了。然后对每个单元格内的四个采样点取均值,就可以得到最终的ROIAlign的结果。
算子定义如下:
- 在LayerParameter中添加ROIAlignParameter
message 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。
ShuffleChannel
ShuffleChannel是把channel维度分为[group, channel/Group],然后再在channel维度中进行数据转置[channel/Group,group]。
例如对于channel=4,group=2,则执行此算子后,就是把channel[1]、channel[2]的数据交换位置。
算子定义如下:
- 在LayerParameter中添加ShuffleChannelParameter
message 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 } }
Yolo
YOLO算子出现在YOLO V2网络,且目前仅在YOLO V2、V3网络中使用,对数据做sigmoid和softmax操作。
- 在YOLO V2中,根据backgroud和softmax的参数,有4种场景:
- background=false,softmax=true,
对(x,y,h,w)中的(x,y)做sigmoid,对b做sigmoid,对classes做softmax。
- background=false,softmax=false,
对(x,y,h,w)中的(x,y)做sigmoid,对b做sigmoid,对classes做sigmoid。
- background=true,softmax=false,
对(x,y,h,w)中的(x,y)做sigmoid,对b不做计算,对classes做sigmoid。
- background=true,softmax= true,
对(x,y,h,w)中的(x,y)做sigmoid,对b和classes放在一起做softmax。
- background=false,softmax=true,
- 在YOLO V3中,只有一种场景:对(x,y,h,w)中的(x,y)做sigmoid,对b做sigmoid,对classes做sigmoid。
输入数据格式为Tensor(n, coords+backgroup+classes,l.h,l.w),其中n是anchor box的数量,corrds表示x,y,w,h。
算子定义如下:
- 在LayerParameter中添加YoloParameter
message 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 } }
- 宽高都为minsize生成prior box。
- 如果存在max_size, 则用sqrt(min_size*max_size)确定宽高生成一个框(约束,max_size>min_size)。
- 根据aspect_ratio(如定义所示aspect_ratio为2,3,flip是true,自动添加aspect_ratio=1/2、1/3),生成对应的prior box。
因此,num_priors_(prior box的数量)= min_size的数量+aspect_ratio的数量(这里为4)*min_size的数量(这里为1)+max_size的数量 (max_size的数量和min_size 的数量一一对应)。
算子定义如下:
- 在LayerParameter中添加PriorBoxParameter
message 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]区间中的值。
计算代码如下:
Dtype* data = output_grid.mutable_cpu_data(); for(int i=0; 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为输出坐标,计算公式如下:
计算代码如下:
caffe_cpu_gemm<Dtype>(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::cout<<prefix<<"(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::cout<<prefix<<"(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::cout<<prefix<<" pic[m * W + n]= "<<std::endl; } }
算子定义如下:
- 在LayerParameter中添加SpatialTransformParameter
message 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 } }
样例参考
本章节介绍几种常用网络的修改方法。
FasterRCNN网络模型prototxt修改
本章节所有的代码样例都不能直接复制到网络模型中使用,需要用户根据使用的网络模型,自行调整相应参数,比如bottom、top中的参数要和具体网络模型中的bottom、top一一对应,并且bottom和top对应的参数顺序不能更改。
如下以FasterRCNN Resnet34网络模型为例进行说明。
- proposal算子修改。根据Caffe框架算子规格,该算子有3个输入,2个输出;根据上述原则,对原始proposal算子进行修改,type修改为caffe.proto文件中的类型,增加actual_rois_num输出节点。参见caffe.proto文件中的属性定义增加相应属性信息。修改情况如图2-9所示,其中左边为原始算子prototxt,右边是适配昇腾AI处理器的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 } }
参数解释请参见Caffe框架算子规格。
- 最后一层增加FSRDetectionOutput算子,用于输出最终的检测结果。
对于FasterRCNN网络,参考扩展算子列表在原始prototxt文件的最后增加后处理算子层FSRDetectionOutput ,参见Caffe框架算子规格,FSRDetectionOutput算子有五个输入,两个输出,此算子的Type及属性定义如下:
代码样例如下:
layer { name: "FSRDetectionOutput_1" type: "FSRDetectionOutput" bottom: "rois" bottom: "bbox_pred" bottom: "cls_prob" bottom: "im_info" bottom: "actual_rois_num" top: "actual_bbox_num1" top: "box1" fsrdetectionoutput_param { num_classes:3 score_threshold:0.0 iou_threshold:0.7 batch_rois:1 } }
参数解释请参见Caffe框架算子规格。
YOLOv3网络模型prototxt修改
本章节所有的代码样例都不能直接复制到网络模型中使用,需要用户根据使用的网络模型,自行调整相应参数,比如bottom、top中的参数要和具体网络模型中的bottom、top一一对应,并且bottom和top对应的参数顺序不能更改。
- upsample算子upsample_param属性参数修改。
参见Caffe框架算子规格,需要将原始算子prototxt中的scale:2修改为scale:1 stride:2。
对比情况如图2-10所示,其中左边为原始算子prototxt,右边是适配昇腾AI处理器的prototxt。
参数解释请参见Caffe框架算子规格。
- 新增三个Yolo算子。
由于Yolo算子+DetectionOutput算子才是特征检测网络完整的后处理逻辑,根据原始算子prototxt所示,在增加YoloV3DetectionOutput算子之前需要先增加三个Yolo算子。
根据Caffe框架算子规格,该算子有1个输入,3个输出,根据上述原则,构造的Yolo算子代码样例如下:- 算子1代码样例:
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 } }
- 算子2代码样例:
layer { bottom: "layer94-conv" top: "yolo2_coords" top: "yolo2_obj" top: "yolo2_classes" name: "yolo2" type: "Yolo" yolo_param { boxes: 3 coords: 4 classes: 80 yolo_version: "V3" softmax: true background: false } }
- 算子3代码样例:
layer { bottom: "layer106-conv" top: "yolo3_coords" top: "yolo3_obj" top: "yolo3_classes" name: "yolo3" type: "Yolo" yolo_param { boxes: 3 coords: 4 classes: 80 yolo_version: "V3" softmax: true background: false } }
参数解释请参见Caffe框架算子规格。
- 算子1代码样例:
- 最后一层增加YoloV3DetectionOutput算子。
对于YOLOv3网络,参考扩展算子列表在原始prototxt文件的最后增加后处理算子层YoloV3DetectionOutput ,参见Caffe框架算子规格,YoloV3DetectionOutput算子有十个输入,两个输出;根据该原则,构造的后处理算子代码样例如下:
layer { name: "detection_out3" type: "YoloV3DetectionOutput" bottom: "yolo1_coords" bottom: "yolo2_coords" bottom: "yolo3_coords" bottom: "yolo1_obj" bottom: "yolo2_obj" bottom: "yolo3_obj" bottom: "yolo1_classes" bottom: "yolo2_classes" bottom: "yolo3_classes" bottom: "img_info" top: "box_out" top: "box_out_num" yolov3_detection_output_param { boxes: 3 classes: 80 relative: true obj_threshold: 0.5 score_threshold: 0.5 iou_threshold: 0.45 pre_nms_topn: 512 post_nms_topn: 1024 biases_high: 10 biases_high: 13 biases_high: 16 biases_high: 30 biases_high: 33 biases_high: 23 biases_mid: 30 biases_mid: 61 biases_mid: 62 biases_mid: 45 biases_mid: 59 biases_mid: 119 biases_low: 116 biases_low: 90 biases_low: 156 biases_low: 198 biases_low: 373 biases_low: 326 } }
参数解释请参见Caffe框架算子规格。
- 新增输入:
由于YoloV3DetectionOutput算子有img_info输入,故模型输入时增加该输入。对比情况如图2-11所示,其中左边为原始算子prototxt,右边是适配昇腾AI处理器的prototxt。
代码样例如下,参数为[batch,4],4表示netH、netW、scaleH、scaleW四个维度。其中netH,netW为网络模型输入的HW,scaleH,scaleW为原始图片的HW。
input: "img_info" input_shape { dim: 1 dim: 4 }
YOLOv2网络模型prototxt修改
本章节所有的代码样例都不能直接复制到网络模型中使用,需要用户根据使用的网络模型,自行调整相应参数,比如bottom、top中的参数要和具体网络模型中的bottom、top一一对应,并且bottom和top对应的参数顺序不能更改。
- 修改Region算子。
由于Yolo算子+DetectionOutput算子才是特征检测网络完整的后处理逻辑,在增加YoloV2DetectionOutput算子之前需要将Region过程算子,替换为Yolo算子。
参见Caffe框架算子规格,Yolo算子有一个输入,三个输出;基于该原则,修改后的Yolo算子如下,对比情况如图2-12所示,其中左边为原始算子prototxt,右边是适配昇腾AI处理器的prototxt。
构造的代码样例如下:
layer { bottom: "layer31-conv" top: "yolo_coords" top: "yolo_obj" top: "yolo_classes" name: "yolo" type: "Yolo" yolo_param { boxes: 5 coords: 4 classes: 80 yolo_version: "V2" softmax: true background: false } }
参数解释请参见Caffe框架算子规格。
- 最后一层增加YoloV2DetectionOutput算子。
对于YoloV2网络,参考扩展算子列表在原始prototxt文件的最后增加后处理算子层YoloV2DetectionOutput ,参见Caffe框架算子规格,YoloV2DetectionOutput算子有四个输入,两个输出;根据上述原则,构造的后处理算子代码样例如下:
layer { name: "detection_out2" type: "YoloV2DetectionOutput" bottom: "yolo_coords" bottom: "yolo_obj" bottom: "yolo_classes" bottom: "img_info" top: "box_out" top: "box_out_num" yolov2_detection_output_param { boxes: 5 classes: 80 relative: true obj_threshold: 0.5 score_threshold: 0.5 iou_threshold: 0.45 pre_nms_topn: 512 post_nms_topn: 1024 biases: 0.572730 biases: 0.677385 biases: 1.874460 biases: 2.062530 biases: 3.338430 biases: 5.474340 biases: 7.882820 biases: 3.527780 biases: 9.770520 biases: 9.168280 } }
参数解释请参见Caffe框架算子规格。
- 新增输入:
由于YoloV2DetectionOutput算子有img_info输入,故模型输入时增加该输入。对比情况如图2-13所示,其中左边为原始算子prototxt,右边是适配昇腾AI处理器的prototxt。
代码样例如下,参数为[batch,4],4表示netH、netW、scaleH、scaleW四个维度。其中netH,netW为网络模型输入的HW,scaleH,scaleW为原始图片的HW。
input: "img_info" input_shape { dim: 1 dim: 4 }
SSD网络模型prototxt修改
本章节所有的代码样例都不能直接复制到网络模型中使用,需要用户根据使用的网络模型,自行调整相应参数,比如bottom、top中的参数要和具体网络模型中的bottom、top一一对应,并且bottom和top对应的参数顺序不能更改。
对于SSD网络,参考扩展算子列表在原始prototxt文件的最后增加后处理算子层SSDDetectionOutput。
参见caffe.proto文件(该文件路径为${install_path}/atc/include/proto),先在LayerParameter message中添加自定义层参数的声明(如下自定义层在caffe.proto中已经声明,用户无需再次添加):
message LayerParameter { ... optional SSDDetectionOutputParameter ssddetectionoutput_param = 232; ... }
参见caffe.proto文件,此算子的Type及属性定义如下:
message SSDDetectionOutputParameter { optional int32 num_classes= 1 [default = 2]; optional bool share_location = 2 [default = true]; optional int32 background_label_id = 3 [default = 0]; optional float iou_threshold = 4 [default = 0.45]; optional int32 top_k = 5 [default = 400]; optional float eta = 6 [default = 1.0]; optional bool variance_encoded_in_target = 7 [default = false]; optional int32 code_type = 8 [default = 2]; optional int32 keep_top_k = 9 [default = 200]; optional float confidence_threshold = 10 [default = 0.01]; }
参见Caffe框架算子规格,SSDDetectionOutput算子有3个输入,2个输出,基于上述原则,构造的代码样例如下:
layer { name: "detection_out" type: "SSDDetectionOutput" bottom: "bbox_delta" bottom: "score" bottom: "anchors" top: "out_boxnum" top: "y" ssddetectionoutput_param { num_classes: 2 share_location: true background_label_id: 0 iou_threshold: 0.45 top_k: 400 eta: 1.0 variance_encoded_in_target: false code_type: 2 keep_top_k: 200 confidence_threshold: 0.01 } }
- bottom输入中的bbox_delta对应caffe原始网络中的mbox_loc,score对应caffe原始网络中的mbox_conf_flatten,anchors对应caffe原始网络中的mbox_priorbox;num_classes取值需要与原始网络模型中的取值保持一致。
- top输出多batch场景下:
- out_boxnum输出shape是(batchnum,8),每个batchnum的第一个值是实际框的个数。
- y输出shape是(batchnum,len,8),其中len是keep_top_k 128对齐后的取值(如batch为2,keep_top_k 为200,则最后输出shape为(2,256,8)),前256*8个数据为第一个batch的结果。
参数解释请参见Caffe框架算子规格。
BatchedMatMul算子prototxt修改
本章节所有的代码样例都不能直接复制到网络模型中使用,需要用户根据使用的网络模型,自行调整相应参数,比如bottom、top中的参数要和具体网络模型中的bottom、top一一对应,并且bottom和top对应的参数顺序不能更改。
该算子用户输出两个张量的乘积:y=x1*x2(x1和x2的张量相乘,x1和x2维数必须大于2而小于等于8)。如果网络模型使用该算子,则请参见该章节,修改相应prototxt后,再进行模型转换。
参见caffe.proto文件(该文件路径为${install_path}/atc/include/proto),先在LayerParameter message中添加自定义层参数的声明(如下自定义层在caffe.proto中已经声明,用户无需再次添加):
message LayerParameter { ... optional BatchMatMulParameter batch_matmul_param = 235; ... }
参见caffe.proto文件,此算子的Type及属性定义如下:
message BatchMatMulParameter{ optional bool adj_x1 = 1 [default = false]; optional bool adj_x2 = 2 [default = false]; }
参见Caffe框架算子规格,BatchedMatMul算子有2个输入,1个输出,基于上述原则,构造的代码样例如下:
layer { name: "batchmatmul" type: "BatchedMatMul" bottom: "matmul_data_1" bottom: "matmul_data_2" top: "batchmatmul_1" batch_matmul_param { adj_x1:false adj_x2:true }
参数解释请参见Caffe框架算子规格。
SENet网络模型prototxt修改
本章节所有的代码样例都不能直接复制到网络模型中使用,需要用户根据使用的网络模型,自行调整相应参数,比如bottom、top中的参数要和具体网络模型中的bottom、top一一对应,并且bottom和top对应的参数顺序不能更改。
该网络模型中的Axpy算子,需要修改为Reshape、Scale、Eltwise三个算子,修改样例如下:
修改后的代码样例如下:
layer { name: "conv3_1_axpy_reshape" type: "Reshape" bottom: "conv3_1_1x1_up" top: "conv3_1_axpy_reshape" reshape_param { shape { dim: 0 dim: -1 } } } layer { name: "conv3_1_axpy_scale" type: "Scale" bottom: "conv3_1_1x1_increase" bottom: "conv3_1_axpy_reshape" top: "conv3_1_axpy_scale" scale_param { axis: 0 bias_term: false } } layer { name: "conv3_1_axpy_eltwise" type: "Eltwise" bottom: "conv3_1_axpy_scale" bottom: "conv3_1_1x1_proj" top: "conv3_1" }
Reshape、Scale、Eltwise算子相关参数解释请参见Caffe框架算子规格。