目标检测算法SSD 原理-对内容做分类-对边界做回归。

对框中的内容做分类-对边界做回归。

 

SSD效果为什么这么好
虽然SSD这个算法出来已经两年了,但是至今依旧是目标检测中应用最广泛的算法,虽然后面有很多基于SSD改进的算法,但至今也没有哪一种检测算法在速度和精度上能够完全碾压SSD的。那么为什么SSD效果这么好?SSD效果好主要有三点原因:

多尺度
设置了多种宽高比的anchor
数据增强
下面一一对他们进行分析。

注:

anchor,default box,prior box表示的是同一个意思,本文统一使用更加常用的anchor来表示。实际上,anchor技术的鼻祖是DeepMultiBox(2014年CVPR:Scalable Object Detection using Deep Neural Networks),这篇论文里首次提出使用prior(先验框),并且提出使用prior做匹配。后面的众多工作,比如RCNN系列,YOLO系列都使用了anchor这个术语,而在SSD中anchor又叫default box,本质上都是表示的同一个东西。
原因1:多尺度
由SSD的网络结构可以看出,SSD使用6个不同特征图检测不同尺度的目标。低层预测小目标,高层预测大目标。

作者在论文中通过实验验证了,采用多个特征图做检测能够大大提高检测精度,从上面的表格可以看出,采用6个特征图检测的时候,mAP为74.3%,如果只采用conv7做检测,mAP只有62.4%。

原因2:设置了多种宽高比的anchor
在特征图的每个像素点处,生成不同宽高比的anchor,论文中设置的宽高比为{1,2,3,1/2,1/3}。假设每个像素点有k个anchor,需要对每个anchor进行分类和回归,其中用于分类的卷积核个数为ck(c表示类别数),回归的卷积核个数为4k。

SSD300中anchor的数量:(38384 + 19196 + 10106 + 556 + 334 + 114)= 8732

讲到这里,我想对于刚学习SSD的朋友,一定有这些疑惑:

为什么要设置anchor?
为什么要设置多种宽高比的anchor?
为什么在6个特征图上使用3×3的卷积核进行卷积就可以做检测了呢?
这些问题曾经困恼我很长时间,当我看完SSD的源码,并通过很长时间的实践,对这些问题豁然开朗,下面分享自己对这些问题的一些理解,希望对你理解SSD能够提供一些帮助。

理论感受野和有效感受野
这里先简单说明一下理论感受野和有效感受野的概念,更加详细的介绍参考论文:Understanding the Effective Receptive Field in Deep Convolutional Neural Networks[1]。这两个概念的理解对于理解anchor非常重要。

影响某个神经元输出的输入区域就是理论感受野,也就是我们平时说的感受野,但该输入区域的每个像素点对输出的重要性不同,越靠近中心的像素点影响越大,呈高斯分布,也就是说只有中间的一小部分区域对最后的输出有重要的影响,这个中间的一小部分区域就是有效感受野。

有效感受野在训练过程中是会发生变化的,影响有效感受野的因素:

数据集
层的类型(下采样,扩张卷积,跳层连接,非线性激活函数)
卷积层参数初始化方式(Uniform(参数全部设置为1), Random)
卷积层的个数
下图展示了不同因素对有效感受野的影响

卷积层层数,权值初始化方式以及非线性激活对ERF的影响
下采样和扩张卷积可以增大感受野
不同数据集对感受野的影响

为什么要设置anchor?
在分类/识别问题中,通常整张图就包含一个目标,所以只需要对一个目标直接分类就好了,所以最后直接使用全连接层提取整幅图像的特征就可以了(全连接层理论感受野大小就是输入大小)。但是检测问题中,输入图像会包含有很多个目标,所以需要对多个目标进行特征提取,这个时候就不能使用全连接层了,只能使用卷积层,卷积层的输出特征图上每个位置对应一个理论感受野,该位置提取的是这个理论感受野对应区域的特征。然后我们只需要对每个感受野进行分类和回归就可以了。是否每一层只能对理论感受野响应呢?有效感受野理论表明,每一层实际响应的区域其实是有效感受野区域,但是训练过程中并不知道有效感受野大小,怎么办呢?这个时候就出现了anchor技术。

anchor作用:通过anchor设置每一层实际响应的区域,使得某一层对特定大小的目标响应。

论文中也提到:
Feature maps from different levels within a network are known to have different (empirical) receptive field sizes. Fortunately,
within the SSD framework, the default boxes do not necessary need to correspond to the actual receptive fields of each layer. We design the tiling of default boxes so that specific feature maps learn to be responsive to particular scales of the objects.
通过设计anchor的平铺可以使得特定的特征图对特定大小的目标进行响应。

下图可以更加形象的表示anchor的作用

图b是实际训练后的效果,整个黑色区域就是理论感受野(TRF),中间呈高斯分布的白色点云区域就是有效感受野(ERF)
图a中黑色虚线区域对应图b中的理论感受野,红色实线框是anchor大小,对应了图b中有效感受野区域。我们可以看到通过在图a中设置anchor可以设置每一层实际响应的区域,使得某一层对特定大小的目标响应。

这里还有几个问题需要说明一下。

为什么在同一个特征图上可以设置多个anchor检测到不同尺度的目标
刚开始学SSD的朋友一定有这样的疑惑,同一层的感受野是一样的,为什么在同一层可以设置多个anchor,然后在分类和回归两个分支上只需要使用不同通道的3×3卷积核就可以实现对不同anchor的检测?虽然分类和回归使用的是同一个特征图,但是不同通道的3×3卷积核会学习到那块区域的不同的特征,所以不同通道对应的anchor可以检测到不同尺度的目标。
anchor本身不参与网络的实际训练,anchor影响的是classification和regression分支如何进行encode box(训练阶段)和decode box(测试阶段)。测试的时候,anchor就像滑动窗口一样,在图像中滑动,对每个anchor做分类和回归得到最终的结果。
为什么anchor可以设置每一层实际响应的区域呢?
因为每一层实际响应的区域其实是有效感受野区域,而有效感受野理论表明有效感受野在训练过程中会发生变化,所以每一层实际响应的区域其实是会发生变化的,正是由于有效感受野大小会发生变化,所以可以通过anchor设置每一层实际响应的区域。
关于anchor的进一步探讨,见另一篇博客:深入理解anchor,欢迎大家畅所欲言
anchor的匹配
既然anchor是实际响应的区域,训练的时候就需要知道每个anchor的分类和回归的label,如何确定呢?SSD通过anchor与groundtruth匹配来确定label。
在训练阶段,SSD会先寻找与每个anchor的IOU最大的那个ground truth(大于IOU阈值0.5),这个过程叫做匹配。如果一个anchor找到了匹配的ground truth,则该anchor就是正样本,该anchor的类别就是该ground truth的类别,如果没有找到,该anchor就是负样本。图1(b)中8×8特征图中的两个蓝色的anchor匹配到了猫,该anchor的类别为猫,图1©中4×4特征图中的一个红色的anchor匹配到了狗,该anchor的类别为狗。图2显示了实际的匹配过程,两个红色的anchor分别匹配到了猫和狗,左上角的anchor没有匹配,即为负样本。
图1
图 2(图中红色框表示anchor,绿色框表示groundtruth)

关于匹配更多的细节,参考Caffe源码multibox_loss_layer.cpp中的FindMatches()函数,前面的博客:SSD源码解读3-MultiBoxLossLayer中也讲到了该函数。

为什么要设置多种宽高比的anchor?
由于现实中的目标会有各种宽高比(比如行人),设置多个宽高比可以检测到不同宽高比的目标。
作者实验结果表明,增加宽高比为1/2,2,1/3,3的default box,mAP从71.6%提高到了74.3%。

如何选择anchor的scale和aspect ratio?
假设我们用m个feature maps做预测,那么对于每个featuer map而言其anchor的scale是按以下公式计算的。
Sk=Smin+Smax−Sminm−1(k−1)S_k=S_{min}+{{S_{max}-S_{min}} \over {m-1}}(k-1)
S
k

=S
min

+
m−1
S
max

−S
min


(k−1)

这里SminS_{min}S
min

是0.2,表示最低层的scale是0.2,SmaxS_{max}S
max

是0.9,表示最高层的scale是0.9。宽高比αr=1,2,3,1/2,1/3{\alpha}_r={1,2,3,1/2,1/3}α
r

=1,2,3,1/2,1/3,因此每个anchor的宽wαk=Skαr−−√w^{\alpha}_{k}=S_k \sqrt{{\alpha}_r}w
k
α

=S
k

α
r


,高hαk=Sk/αr−−√h^{\alpha}_{k}={S_k / \sqrt{{\alpha}_r}}h
k
α

=S
k

/
α
r


,当aspect ratio为1时,作者还增加一种scale的anchor:S′k=SkSk+1−−−−−−−√S^{‘}_k= \sqrt{S_kS_k+1}S
k


=
S
k

S
k

+1

,因此,对于每个feature map cell而言,一共有6种anchor。

示例:
假设m=6,即使用6个特征图做预测, 则每一层的scale:0.2,0.34,0.48,0.62,0.76,0.9
对于第一层,scale=0.2,对应的6个anchor为:

宽高比 宽 高
1 0.200000 0.200000
2 0.282843 0.141421
3 0.346410 0.115470
1/2 0.141421 0.282843
1/3 0.115412 0.346583
最后增加的default box 0.260768 0.260768
注:表格中每个宽高比的anchor的实际宽和高需要乘以输入图像的大小,如SSD300,则需要使用上面的数值乘以300得到anchor实际大小。

Caffe源码中anchor的宽高比以及scale的设置参考prior_box_layer.cpp,前面的博客:SSD源码解读2-PriorBoxLayer也对该层进行过解读。

原因3:数据增强
SSD中使用了两种数据增强的方式
1. 放大操作: 随机crop,patch与任意一个目标的IOU为0.1,0.3,0.5,0.7,0.9,每个patch的大小为原图大小的[0.1,1],宽高比在1/2到2之间。能够生成更多的尺度较大的目标
2. 缩小操作: 首先创建16倍原图大小的画布,然后将原图放置其中,然后随机crop,能够生成更多尺度较小的目标

作者实验表明,增加了数据增强后,mAP从65.5提高到了74.3!

数据增强对应Caffe源码annotated_data_layer.cpp,前面的博客:SSD源码解读1-数据层AnnotatedDataLayer也对该层进行过解读。

SSD的缺点及改进
1. SSD主要缺点:SSD对小目标的检测效果一般,作者认为小目标在高层没有足够的信息。

论文原文:
This is not surprising because those small objects may not even have any information at the very top layers. Increasing the input size (e.g. from 300× 300 to 512× 512) can help improve detecting small objects, but there is still a lot of room to improve.

对小目标检测的改进可以从下面几个方面考虑:
1. 增大输入尺寸
2. 使用更低的特征图做检测(比如S3FD中使用更低的conv3_3检测)
3. FPN(已经是检测网络的标配了)

2. 关于anchor的设置的优化

An alternative way of improving SSD is to design a better tiling of default boxes so that its position and scale are better aligned with the receptive field of each position on a feature map. We leave this for future work. P12
论文中提到的anchor设置没有对齐感受野,通常几个像素的中心位置偏移,对大目标来说IOU变化不会很大,但对小目标IOU变化剧烈,尤其感受野不够大的时候,anchor很可能偏移出感受野区域,影响性能。
关于anchor的设计,作者还提到了
In practice, one can also design a distribution of default boxes to best fit a specific dataset. How to design the optimal tiling is an open question as well
论文提到根据特定数据集设计default box,在YOLOV2中使用聚类的方式初始化anchor,能够更好的匹配到ground truth,帮助网络更好的训练

SSD中的Mining机制
在视觉任务中经常遇到两个问题:
1. 类别不均衡
2. 简单样本和困难样本不均衡 (easy sample overwhelming)。easy sample如果太多,可能会将有效梯度稀释掉。

为了解决上述问题,研究人员提出了一些解决方案:
1. Online Hard Example Mining, OHEM(2016)。将所有sample根据当前loss排序,选出loss最大的N个,其余的抛弃。这个方法就只处理了easy sample的问题。
2. Focal Loss(2017), 最近提出来的。不会像OHEM那样抛弃一部分样本,focal loss考虑了每个样本, 不同的是难易样本上的loss权重是根据样本难度计算出来的。

SSD中采用了一种新的Mining机制,OHNM(Online Hard Negative Mining),在Focal Loss里代号为OHEM 1:3,是对OHEM的一种改进。OHNM在计算loss时, 使用所有的positive anchor, 使用OHEM选择3倍于positive anchor的negative anchor。同时考虑了类间平衡与easy sample。通过OHNM让训练更快收敛同时也更加稳定。

注意,SSD中mining具体实现的时候,MultiBoxLoss层的 mining_type可以选择MAX_NEGATIVE或者HARD_EXAMPL

MAX_NEGATIVE对应OHNM, 只计算分类loss,不计算定位loss,只针对负样本选择loss最大的3倍于正样本数量的负样本
HARD_EXAMPL对应OHEM ,会同时计算分类和定位loss,选择出loss最大的前topN个样本
具体实现参考MineHardExamples()函数。
SSD与MTCNN
这里为什么会提到MTCNN[2]呢?如果你了解过MTCNN这个算法,一定对PNet这个网络不陌生,仔细比较SSD与PNet,你就会发现SSD与PNet之间有着千丝万缕的联系。
其实我对SSD的理解就是源于MTCNN中的PNet,实际上SSD可以看成是由6个不同的PNet组合而成。

这里用原论文中的SSD300的结构与MTCNN作比较
SSD与MTCNN对比
生成训练数据的方式不同
MTCNN需要事先手动将所有的训练样本生成好,然后输入到网络中训练, 而SSD不需要,SSD在训练过程中自动生成所有训练样本。SSD中实际的训练样本就是所有anchor,每个anchor的label由anchor与ground truth匹配来确定。SSD实现了真正意义上端到端的训练。
MTCNN和SSD采用了两种不同的多尺度检测策略
MTCNN:首先构建图像金字塔,然后使用固定大小的滑动窗口在金字塔每一级滑动,对每个滑动窗口分类回归。
SSD: 在原图中设置了不同大小的滑动窗口,对不同大小的滑动窗口进行分类和回归。
不管是MTCNN,还是SSD,本质上是对所有滑动窗口的分类。这与传统的目标检测方法本质上是一样的。
Mining的方式不同
MTCNN需要手动做mining,而SSD采用了OHNM训练过程中自动完成负样本的mining,解决了简单样本的问题和类别不平衡问题。
其实MTCNN中也是有anchor的,MTCNN中的anchor就是PNet的滑动窗口
MTCNN的训练样本就是滑动窗口图像,而生成训练样本的时候使用滑动窗口与groundtruth进行匹配,得到分类和回归的label,所以anchor就是PNet的滑动窗口。不过与SSD的区别在于这个匹配过程不是训练过程中自动完成的,而是事先手动完成。
判断什么是anchor的方法:使用什么匹配groundtruth的,那个就是anchor
结束语
一个人的时间精力有限,不可能深入理解SSD的每一个细节,文中有什么不妥的地方,欢迎大家批评指正,也欢迎留言一起交流讨论。
————————————————
版权声明:本文为CSDN博主「qianqing13579」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qianqing13579/java/article/details/82106664

发表评论

电子邮件地址不会被公开。 必填项已用*标注