SSD框架详细解读(一)_ssd默认框-程序员宅基地

技术标签: 人工智能 - 图像识别  机器学习 -基本理论  计算机视觉 - 图像处理  

目录

模型结构

Prior box默认框的产生

Prior box 的大小尺寸计算

输出层通道num_output计算。

Priorbox的使用

Permute,Flatten And Concat Layers

matching strategy:选择一系列default boxes

hard negative mining

data augmentation

技巧对比效果结论

training objective:多任务损失函数

模型结构

     论文中(下图)描述为conv4_3,conv7(原先的FC7),conv8_2,conv9_2,conv10_2,以及 pool11,这些 layer 合并起来predict location、confidence。

     实际caffe中的ssd 300*300使用conv4_3、fc7、conv6_2、conv7_2、conv8_2、conv9_2进行预测位置、置信度以及priorbox。

Prior box默认框的产生

       对于每一层的一个特征图(m*n尺寸),每个cell对应k个prior box,则该层会有m*n*k个prior box。

       SSD默认框从6层卷积层输出的特征图中产生,分别为conv4_3、fc7、conv6_2、conv7_2、conv8_2、conv9_2。这6个特征层产生的特征图的大小分别为38*38、19*19、10*10、5*5、3*3、1*1。每个n*n大小的特征图中有n*n个中心点,每个中心点产生k个默认框,六层中每层的每个中心点产生的k分别为4、6、6、6、4、4。

        上图中最后每个类会得到(38*38*4 + 19*19*6 + 10*10*6 + 5*5*6 + 3*3*4 + 1*1*4)= 8732个prior box。

Prior box 的大小尺寸计算

        每个尺度的特征图像使用哪些大小和宽高比的默认包围盒。SSD按照如下规则生成prior box:

        以feature map上每个点的中点为中心(offset=0.5),生成一些列同心的prior box(然后中心点的坐标会乘以step,相当于从feature map位置映射回原图位置)

        正方形prior box最小边长为:,最大边长为:

      在prototxt设置一个aspect ratio,会生成2个长方形,长宽为: 

其中feature map对应prior box的min_size和max_size由以下公式决定,公式中m是使用feature map的数量(SSD 300中m=6):

第一层feature map对应的min_size=S1,max_size=S2;第二层min_size=S2,max_size=S3;其他类推。

对ssd产生的默认框的大小计算首先要计算参数min_sizes和max_sizes,这些参数具体在ssd_pascal.py中有计算方法。代码如下:

#参数生成先验。  

#输入图像的最小尺寸  

min_dim = 300   #######维度  

# conv4_3 ==> 38 x 38  

# fc7 ==> 19 x 19  

# conv6_2 ==> 10 x 10  

# conv7_2 ==> 5 x 5  

# conv8_2 ==> 3 x 3  

# conv9_2 ==> 1 x 1  

mbox_source_layers = ['conv4_3', 'fc7', 'conv6_2', 'conv7_2', 'conv8_2', 'conv9_2'] #####prior_box来源层,可以更改。  

# in percent %  

####这里即是论文中所说的Smin=0.2,Smax=0.9的初始值,经过下面的运算即可得到min_sizes,max_sizes。

min_ratio = 20   

max_ratio = 90  

####取一个间距步长,即在下面for循环给ratio取值时起一个间距作用。可以用一个具体的数值代替,这里等于17。   ####math.floor()函数表示:求一个最接近它的整数,它的值小于或等于这个浮点数。  

step = int(math.floor((max_ratio - min_ratio) / (len(mbox_source_layers) - 2)))

min_sizes = []  ###经过以下运算得到min_sizes和max_sizes。  

max_sizes = []  

####从min_ratio至max_ratio+1每隔step=17取一个值赋值给ratio。注意xrange函数的作用。  

for ratio in xrange(min_ratio, max_ratio + 1, step):  #20 37 54 71 88

  min_sizes.append(min_dim * ratio / 100.)      #[60.0,111.0,162.0,213.0,264.0]

  max_sizes.append(min_dim * (ratio + step) / 100.)  

min_sizes = [min_dim * 10 / 100.] + min_sizes  #[30.0,60.0,111.0,162.0,213.0,264.0] 前面拼接

max_sizes = [min_dim * 20 / 100.] + max_sizes  

###这一步要仔细理解,即计算卷积层产生的prior_box距离原图的步长,先验框中心点的坐标会乘以step,相当于从feature map位置映射回原图位置,比如conv4_3输出特征图大小为38*38,而输入的图片为300*300,所以38*8约等于300,所以映射步长为8。这是针对300*300的训练图片。

steps = [8, 16, 32, 64, 100, 300]  

#######这里指的是横纵比,六种尺度对应六个产生prior_box的卷积层。具体可查看生成的train.prototxt文件一一对应每层的aspect_ratio参数,此参数在caffe.proto中有定义,关于aspect_ratios如何把其内容传递给了aspect_ratio,在model_libs.py文件中有详细定义。

aspect_ratios = [[2], [2, 3], [2, 3], [2, 3], [2], [2]]  

 

在原文中,Smin=0.2,Smax=0.9,同理依次可以计算出如下表结果:

    再用不同aspect ratio,用ar来表示:。因此,默认包围盒的宽度和高度计算公式为:

                                                                                

    对于aspect ratio为1时,本文还增加了一个default box(默认产生一大一小两个正方形默认框),所以最终在每个feature map location上,有6个default boxes。

    其中SSD 300在conv4_3生成prior box的conv4_3_norm_priorbox层prototxt定义如下:

layer {  
  name: "conv4_3_norm_mbox_priorbox"  
  type: "PriorBox"  
  bottom: "conv4_3_norm"  
  bottom: "data"  
  top: "conv4_3_norm_mbox_priorbox"  
  prior_box_param {  
    min_size: 30.0      #根据公式计算
    max_size: 60.0    
    aspect_ratio: 2      #包含 1、1、2、1/2四种宽高比的defaultbox(两个正方形,两个长方形)
    flip: true        #注意如果没有flip参数,aspect_ratio=2只能产生一个纵横比为1:2的默认框
    clip: false  
    variance: 0.1  
    variance: 0.1  
    variance: 0.2  
    variance: 0.2  
    step: 8            #该层特征图尺寸为38*38,38*8约等于300,用于尺度映射
    offset: 0.5  
  }  
}  
layer {
  name: "fc7_mbox_priorbox"
  type: "PriorBox"
  bottom: "fc7"
  bottom: "data"
  top: "fc7_mbox_priorbox"
  prior_box_param {
    min_size: 60.0    #根据公式计算
    max_size: 111.0
    aspect_ratio: 2    #包含 1、1、2、1/2、3、1/3六种宽高比的defaultbox
    aspect_ratio: 3
    flip: true
    clip: false
    variance: 0.1
    variance: 0.1
    variance: 0.2
    variance: 0.2
    step: 16        #该层特征图尺寸为19*19,19*16约等于300,用于尺度映射
  }
}

这种默认包围盒在不同的特征层有不同的尺度大小,在同一个特征层又有不同的宽高比,因此可以覆盖输入图像中各种目标大小和宽高比。

如上代码再结合prior_box_layer.cpp产生先验框。

先验框与ground truth框的匹配通过函数CHECK_GT()函数实现,具体在bbox_util.cpp脚本中实现

输出层通道num_output计算。

同时每个prior box要预测c类物体(即c个置信度),每个预测框需要4个offeset参数,则会产生(c+4)*k*m*n个输出结果,因此就需要(c+4)*k个卷积核(其中回归框预测层4*k个,置信度层c*k个)。

layer {
  name: "conv4_3_norm_mbox_loc"
  type: "Convolution"
  bottom: "conv4_3_norm"
  top: "conv4_3_norm_mbox_loc"
 ...
  convolution_param {
    num_output: 16     #4*4   4个位置参数*4个priorbox
    pad: 1
    kernel_size: 3
    stride: 1
    weight_filler {
      type: "xavier"
    }
  }
}
layer {
  name: "conv4_3_norm_mbox_conf"
  type: "Convolution"
  bottom: "conv4_3_norm"
  top: "conv4_3_norm_mbox_conf"
  ...
  convolution_param {
    num_output: 84    #21*4   21个类*4个priorbox
    pad: 1
    kernel_size: 3
    stride: 1
    ...
  }
}

Priorbox的使用

接下来分析prior box如何使用。这里以conv4_3为例进行分析。

从图可以看到,在conv4_3 feature map网络pipeline分为了3条线路:

  1. 经过一次batch norm+一次卷积后,生成了[1, num_class*num_priorbox, layer_height, layer_width]大小的feature用于softmax分类目标和非目标(其中num_class是目标类别,SSD 300中num_class = 21)
  2. 经过一次batch norm+一次卷积后,生成了[1, 4*num_priorbox, layer_height, layer_width]大小的feature用于bounding box regression(即每个点一组[dxmin,dymin,dxmax,dymax],参考FasterRCNN 2.5节)
  3. 生成了[1, 2, 4*num_priorbox]大小的prior box blob,其中2个channel分别存储prior box的4个点坐标和对应的4个variance

还有一个细节就是上面prototxt中的4个variance,这实际上是一种bounding regression中的权重。在图线路(2)中,网络输出[dxmin,dymin,dxmax,dymax],即对应下面代码中bbox;然后利用如下方法进行针对prior box的位置回归:

decode_bbox->set_xmin(prior_bbox.xmin() + prior_variance[0] * bbox.xmin() * prior_width);  
decode_bbox->set_ymin(prior_bbox.ymin() + prior_variance[1] * bbox.ymin() * prior_height); 
decode_bbox->set_xmax(prior_bbox.xmax() + prior_variance[2] * bbox.xmax() * prior_width);  
decode_bbox->set_ymax(prior_bbox.ymax() + prior_variance[3] * bbox.ymax() * prior_height);

上述代码可以在SSD box_utils.cpp的void DecodeBBox()函数见到。

Permute,Flatten And Concat Layers

layer {  
  name: "conv4_3_norm_mbox_conf_perm"  
  type: "Permute"  
  bottom: "conv4_3_norm_mbox_conf"  
  top: "conv4_3_norm_mbox_conf_perm"  
  permute_param {  
    order: 0  
    order: 2  
    order: 3  
    order: 1  
  }  
}  

Permute是SSD中自带的层,上面conv4_3_norm_mbox_conf_perm的的定义。Permute相当于交换caffe blob中的数据维度。在正常情况下caffe blob的顺序为:

bottom blob = [batch_num, channel, height, width]

经过conv4_3_norm_mbox_conf_perm后的caffe blob为:

top blob = [batch_num, height, width, channel]

对于conv4_3 feature map,conv4_3_norm_priorbox(priorbox层)设置了每个点共有4个prior box。由于SSD 300共有21个分类,所以conv4_3_norm_mbox_conf的channel值为num_priorbox * num_class = 4 * 21 = 84;而每个prior box都要回归出4个位置变换量,所以conv4_3_norm_mbox_loc的caffe blob channel值为4 * 4 = 16。

fc7每个点有6个prior box,其他feature map同理。

经过一系列图7展示的caffe blob shape变化后,最后拼接成mbox_conf和mbox_loc。而mbox_conf后接reshape,再进行softmax(为何在softmax前进行reshape,Faster RCNN有提及)。

最后这些值输出detection_out_layer,获得检测结果.

matching strategy:选择一系列default boxes

在训练时,groundtruth boxes 与 default boxes(就是prior boxes) 按照如下方式进行配对:

首先,寻找与每一个ground truth box有最大的jaccard overlap的default box,这样就能保证每一个groundtruth box与唯一的一个default box对应起来。

SSD之后又将剩余还没有配对的default box与任意一个groundtruth box尝试配对,只要两者之间的jaccard overlap大于阈值,就认为match(SSD 300 阈值为0.5,另外所谓的jaccard overlap就是IoU,如图8)。

显然配对到GT的default box就是positive,没有配对到GT的default box就是negative。

J为0说明两个框一点都不重合,为1说明完全重合。

hard negative mining

在生成一系列的predictions之后,会产生很多个符合ground truth box的predictions boxes,但同时,不符合ground truth boxes也很多,而且这个negative boxes,远多于positive boxes。这会造成negative boxes、positive boxes之间的不均衡,训练时难以收敛。

将prior box和grount truth box按照IOU(JaccardOverlap)进行匹配,匹配成功则这个prior box就是positive example(正样本),如果匹配不上,就是negative example(负样本),显然这样产生的负样本的数量要远远多于正样本。这里按confidence loss进行排序,选择最高的num_sel个prior box序号集合 D。那么如果Match成功后的正样本序号集合P。那么最后正样本集为 P - Dcap{P},负样本集为 D - Dcap{P}。同时可以通过规范num_sel的数量(是正样本数量的三倍)来控制使得最后正、负样本的比例在 1:3 左右。本文通过实验发现,这样的比例可以更快的优化,训练也更稳定。

1)正样本获得

我们已经在图上画出了prior box,同时也有了ground truth,那么下一步就是将prior box匹配到ground truth上,这是在 src/caffe/utlis/bbox_util.cpp的 FindMatches以及子函数MatchBBox函数里完成的。值得注意的是先是从groudtruth box出发给每个groudtruth box找到了最匹配的prior box放入候选正样本集,然后再从prior box出发为prior box集中寻找与groundtruth box满足IOU>0.5的一个IOU最大的prior box(如果有的话)放入候选正样本集,这样显然就增大了候选正样本集的数量。

2)负样本获得

本文采取,先将每一个物体位置上对应 predictions(prior boxes)loss 进行排序。 实际代码中有三种负样本挖掘方式:

如果选择HARD_EXAMPLE方式(源于论文Training Region-based Object Detectors with Online Hard Example Mining),则默认M = 64,由于无法控制正样本数量,这种方式就有点类似于分类、回归按比重不同交替训练了。

如果选择MAX_NEGATIVE方式,则M = P*neg_pos_ratio,这里当neg_pos_ratio = 3的时候,就是论文中的正负样本比例1:3了。

enum MultiBoxLossParameter_MiningType {
MultiBoxLossParameter_MiningType_NONE = 0,
MultiBoxLossParameter_MiningType_MAX_NEGATIVE = 1,
MultiBoxLossParameter_MiningType_HARD_EXAMPLE = 2};

data augmentation

每一张训练图像,随机的进行如下几种选择:

  •     使用原始的图像;
  •     采样一个patch,与物体之间最小的 jaccard overlap 为:0.1,0.3,0.5,0.7 与 0.9;
  •     随机的采样一个patch;
  •     采样的patch是原始图像大小比例是 [0.1,1],aspect ratio 在1/2与2之间。
  •     当groundtruth box的中心(center)在采样的patch中时,我们保留重叠部分。
  •     在这些采样步骤之后,每一个采样的patch被resize到固定的大小,并且以0.5的概率随机的水平翻转(horizontally flipped)

    实验结果证明,对数据集进行扩大能够高精度;使用更多的特征图像能够提高精度;使用更多的包围盒能够提高精度。

SSD中的数据增强的顺序是:

  • DistortImage: 这个主要是修改图片的brightness,contrast,saturation,hue,reordering channels,并没改变标签bbox
  • ExpandImage: 缩小图片,达到zoom out的效果:先做一个比原图大的画布,然后随机找一个放原图的位置将原图镶嵌进去,像天安门上挂了一个画像。这是为了增加多尺度信息,多进行小尺度物体训练。
  •     BatchSampler: 对图像选取一个满足限制条件的区域(注意这个区域是随机抓取的)。限制条件就是抓取的patch和GT(Ground Truth)的IOU的值。步骤是:先在区间[min_scale,max_sacle]内随机生成一个值,这个值作为patch的高Height,然后在[min_aspect_ratio,max_aspect_ratio]范围内生成ratio,从而得到patch的Width。到此为止patch的宽和高随机得到,然后在图像中进行一次patch,要求满足与GT的最小IOU是0.9,也就是IOU>=0.9。如果随机patch满足这个条件,那么张图会被resize到300*300(在SSD300*300中)送进网络训练。如下图。
batch_sampler {
      sampler {
        min_scale: 0.3       #scale是patch随机框和原图的面积比
        max_scale: 1
        min_aspect_ratio: 0.5   #长宽比
        max_aspect_ratio: 2
      }
      sample_constraint {
        min_jaccard_overlap: 0.9    ##随机框和原ground truth的jaccard overlap
      }
      max_sample: 1
      max_trials: 50       #迭代次数
    }
  • Resize:放缩到300x300,最后将图片放缩到300x300,标签框也是线性放缩坐标而已。
  • Crop:原本data_transformer还会crop的,这个参数是配在prototxt中,默认是原图 所以就和没crop一样。如果要crop的话标签也是会和之前BatchSampler那样处理。

技巧对比效果结论

  1. 数据增广(Data augmentation)对于结果的提升非常明显 
  2. 使用更多的 feature maps 对结果提升更大 
  3. 使用更多的 default boxes,结果也越好 
  4. Atrous 使得 SSD 又好又快 

training objective:多任务损失函数

    SSD训练的目标函数(training objective)源自于MultiBox的目标函数,但是本文将其拓展,使其可以处理多个目标类别。指示变量表示第i个默认包围盒和第个j真实包围盒对于目标类型是否匹配。

    根据上面的匹配策略,一定有 ∑i≥1,意味着对于第j个ground truth box,有可能有多个default box i与其相匹配。

    在训练时,需要将真实的目标包围盒与默认包围盒匹配起来,即每个默认包围盒是否真的代表了一个目标。损失函数定义为:

其中N为与真实包围盒匹配的默认包围盒的数量。是一个人工设定的参数,用于平衡定位损失和置信度损失,默认为1。如果N=0,损失函数被设置为0。

置信度损失confidence loss(Lconf)是对所有类的置信度的softmax损失,输入为每一类的置信度c,定义为:

定位损失函数Lloc是一个光滑的损失函数(fast rcnn中Smooth L1 loss),定义预测的包围盒和真实的包围盒之间(中心坐标、w、h)的误差。假设默认包围盒的中心点坐标为,宽度和高度分别为和。定位损失函数定义为:

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/rainforestgreen/article/details/82762274

智能推荐

【JavaScript】——正则表达式-程序员宅基地

文章浏览阅读177次。JavaScript中刚刚接触到一个个人觉得非常新颖的东西——正则表达式。觉得 有必要总结一下。首先一张图,把正则表达式分为一下几个部分。 定义——干什么用的? 正则表达式(regular expression)简写为Regex:是对..._正则的替换功能较差;容易引起性能问题像.*这种贪婪匹配符号很容易造成大量的

css中margin和padding的用法_margin-top: 40px; padding-bottom: 20px; back-程序员宅基地

文章浏览阅读659次。在CSS中margin是指从自身边框到另一个容器边框之间的距离,就是容器外距离。在CSS中padding是指自身边框到自身内部另一个容器边框之间的距离,就是容器内距离。 下面讲解 padding和margin常用的用法一、padding1、语法结构(1)padding-left:10px; 左内边距(2)padding-right:10px; 右内_margin-top: 40px; padding-bottom: 20px; background: #f8f8f8; border-bottom:

STM32中,对GPIO_Init(GPIOB, &GPIO_InitStructure)的理解(转)_gpio_init(gpiob,&gpio_initstructure)-程序员宅基地

文章浏览阅读7.2k次,点赞3次,收藏22次。今天学习stm32流水灯程序的时候,看到了“GPIO_Init(GPIOB, &GPIO_InitStructure)”这个函数,参数1”GPIOB“很好理解,就是GPIO的外设口B(也可以是A,C,D,E),第二个参数有点不理解,于是查看了下库函数手册,该函数原型是这样的:void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GP..._gpio_init(gpiob,&gpio_initstructure)

Vue实例的属性和方法_在vue实例中可以定义方法的是-程序员宅基地

文章浏览阅读1w次,点赞9次,收藏55次。一、Vue之实例属性Vue实例暴露了一些有用的实例属性与方法。这些属性与方法都有前缀$,以便与代理的数据属性区分组件树$parent:用来访问组件实例的父实例 $root: 用来访问当前组件树的根实例 $children:用来访问当前组件实例的直接子组件实例 $refs:用来访问v-ref指令的子组件DOM访问$el:用来挂载当前组件实例的dom元素 $els..._在vue实例中可以定义方法的是

总线仲裁器电路的设计与验证Verilog_仲裁器是电路中-一个常见的模块,来自上游的多路请求经过仲裁器之后汇聚成一路送往-程序员宅基地

文章浏览阅读2.4k次,点赞2次,收藏33次。共享总线是一种常见的总线结构,多个总线上的设备拥有共同的地址线和数据线。当-一个总线设备希望占据总线进行数据收发操作时,需要通过属于自己的areq信号向仲裁器发出申请,只有得到仲裁器的许可(对应的agnt置1 )时才能进行数据收发操作,没有得到许可的总线设备不能发起数据操作,否则将会出现多个设备同时驱动总线的错误。下图是有两个总线设备的总线仲裁器电路,areqO 和areq1以及agnt0和agnt1分别是master1和master2的请求和确认信号,rid是仲裁方式选择信号。当多个总线设备同时发出请求时_仲裁器是电路中-一个常见的模块,来自上游的多路请求经过仲裁器之后汇聚成一路送往

ES6 模块与 CommonJS 模块的差异_commonjs 模块的require()是同步加载模块,es6 模块的import命令是异步加载,-程序员宅基地

文章浏览阅读176次。ES6 模块与 CommonJS 模块的差异讨论 Node.js 加载 ES6 模块之前,必须了解 ES6 模块与 CommonJS 模块完全不同它们有三个重大差异。CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。CommonJS 模块的 require() 是同步加载模块,ES6 模块的 import 命令是异步加载,有一个独立的模块依赖的解析阶段。第二个差异是因为 CommonJS 加载的是一_commonjs 模块的require()是同步加载模块,es6 模块的import命令是异步加载,有一个

随便推点

鸿蒙HarmonyOS应用开发之Node-API简介-程序员宅基地

文章浏览阅读747次,点赞11次,收藏11次。OpenHarmony Node-API是基于Node.js 8.x LTS的 Node-API 规范扩展开发的机制,为开发者提供了ArkTS/JS与C/C++模块之间的交互能力。它提供了一组稳定的、跨平台的API,可以在不同的操作系统上使用。本文中如无特别说明,后续均使用Node-API指代OpenHarmony Node-API能力。OpenHarmony Node-API与Node.js 8.x LTS的Node-API规范的接口异同点,详见Node-API参考。

图像融合中多尺度变换方法总结(下)-程序员宅基地

文章浏览阅读8.5k次,点赞7次,收藏92次。为了选取融合效果较好的多尺度变换方法来提高多波段图像融合质量,现用七种多尺度变换方法结合高频绝对值取大,低频加权平均的融合规则对可见光、红外短波和红外长波图像进行融合,通过主观人眼视觉的角度与客观评价中的信息量、统计特性和人眼视觉特性对融合效果进行分析比较,找到融合效果较好的多尺度变换方法。多尺度变换方法特点分析金字塔变换(1)拉普拉斯金字塔变换LP变换能够很好的表示图像不同分辨率上的高频..._多尺度变换

爬取B站评论和弹幕_哔哩哔哩评论读取工具-程序员宅基地

文章浏览阅读2.2k次。记录一下爬取B站数据_哔哩哔哩评论读取工具

Android activity间的数据回传_数据回传android-程序员宅基地

文章浏览阅读8.3k次,点赞8次,收藏30次。在开发的时候我们经常有需要用到数据回传比如说 我们有这样一个需求:我们点击一个充值按钮 跳转到第二个界面进行充值 然后要把结果返回给第一个界面这里 我们需要用到 startActivityForResult 这个方法 一样是使用 intent进行的首先 我们在第一个界面做跳转的时候这样写 Intent intent=new Intent(MainActivity.this,TowAc..._数据回传android

【elementUI+vue+el-table】树形数据使用表格呈现+表格自定义合并_树结构列表化用table展示-程序员宅基地

文章浏览阅读3.7k次。我需要合并样式:后端数据(树形)及我应展示的思路:获取树形数据并变成列表数据:getOrganizationTree().then((res) => { let that = this; if (res.code == 200) { console.log(res, "准备对接列表的属性接口"); let yqName = res.data.YuanName let yqData = res.data.data // 因为我第一层园区只有一_树结构列表化用table展示

Mongodb $lookup 多表关联查询_mongodb lookup out-程序员宅基地

文章浏览阅读2.3k次。http://www.cnblogs.com/huangxincheng/p/5728791.html_mongodb lookup out

推荐文章

热门文章

相关标签