![830fd1f7bed361813609a6df3af4d018.png](https://i-blog.csdnimg.cn/blog_migrate/80a6fee8bb9c8a74cd5559b18d40c116.jpeg)
SSD,全称Single Shot MultiBox Detector,是Wei Liu在ECCV 2016上提出的一种目标检测算法,截至目前是主要的检测框架之一,相比Faster RCNN有明显的速度优势,相比YOLO又有明显的mAP优势(不过已经被CVPR 2017的YOLO9000超越)。
![c9443e2b1c22ce2526394169098d687a.png](https://i-blog.csdnimg.cn/blog_migrate/ecf839e32892c5f963a948d65a05e138.jpeg)
SSD具有如下主要特点:
- 从YOLO中继承了将detection转化为regression的思路,一次完成目标定位与分类
- 基于Faster RCNN中的Anchor,提出了相似的Prior box;
- 加入基于特征金字塔(Pyramidal Feature Hierarchy)的检测方式,即在不同感受野的feature map上预测目标
本文接下来都以SSD 300为例进行分析。
1 SSD300网络结构
![c00224e597cdf758a328ce234bcc54b0.png](https://i-blog.csdnimg.cn/blog_migrate/ac64e5067fa1ce937db16f4b61464903.jpeg)
上图2是原论文中的SSD300与YOLO网络结构图。位什么要把SSD与YOLO对比呢?因为截止到目前目标检测分为了2种主流框架:
- Two stages:以Faster RCNN为代表,即RPN网络先生成proposals目标定位,再对proposals进行classification+bounding box regression完成目标分类。
- Single shot:以YOLO/SSD为代表,一次性完成classification+bounding box regression。
那么来看同为Single shot方式的SSD/YOLO区别:
- YOLO在卷积层后接全连接层,即检测时只利用了最高层Feature maps(包括Faster RCNN也是如此)
- SSD采用金字塔结构,即利用了conv4-3/conv-7/conv6-2/conv7-2/conv8_2/conv9_2这些大小不同的feature maps,在多个feature maps上同时进行softmax分类和位置回归
- SSD还加入了Prior box
对比如图3。
![f6a72cfdd514f63e5215511e03087fd2.png](https://i-blog.csdnimg.cn/blog_migrate/0a9c969278d872832c0739d8d0b4a719.jpeg)
2 Prior Box
在SSD300中引入了Prior Box,实际上与Faster RCNN Anchor非常类似,就是一些目标的预选框,后续通过classification+bounding box regression获得真实目标的位置。
SSD按照如下规则生成prior box:
- 以feature map上每个点的中点为中心,生成一些列同心的prior box
- 正方形prior box最小边长为和最大边长为:
![6bb9de81b1587a5a30af2905d2d1ed64.png](https://i-blog.csdnimg.cn/blog_migrate/79f516691316bacbf5dc173ba37ccf7c.jpeg)
![f28ebfca126eb65f8ef49db0ada69769.png](https://i-blog.csdnimg.cn/blog_migrate/4f85b9392efbc4ca2227c3038fc1b9ad.png)
- 每在prototxt设置一个aspect ratio,会生成2个长方形,长宽为:
![1a9817dd117e289c37587f485ef957ab.png](https://i-blog.csdnimg.cn/blog_migrate/4bf6841d419262c61486ccc965c3548a.png)
![cb61b5780bc305e83cc027b876c12e7e.png](https://i-blog.csdnimg.cn/blog_migrate/62f65ed5bb72b9c9eaf8bd0a7940994d.png)
![9d57849d171d412d445a95d635386238.png](https://i-blog.csdnimg.cn/blog_migrate/198d59eca16ffd6335a3990867cf250a.jpeg)
- 而每个feature map对应prior box的min_size和max_size由以下公式决定:
公式中的
那么:
- 对于conv4-3:
,
,
- 对于conv-7:
,
,
- ....
显然可以用上述公式推导出每个feature maps使用的Prior Box size。但是在SSD300中prior box设置并不能完全和上述公式对应:
![9a9bfc1d190b08abd1a2f96a081663a5.png](https://i-blog.csdnimg.cn/blog_migrate/8804f3ba9438bdaf7aec4c54229345cf.png)
不过依然可以看出:SSD使用感受野小的feature map检测小目标,使用感受野大的feature map检测更大目标。
更具体一点,来看SSD300在conv4_3层的Prior Box设置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
flip: true
clip: false
variance: 0.1
variance: 0.1
variance: 0.2
variance: 0.2
step: 8
offset: 0.5
}
}
知道了priorbox如何产生,接下来分析prior box如何使用。这里还是以conv4_3分析。
![0dbbb0763d38a20bd30b3c5bb201b0c5.png](https://i-blog.csdnimg.cn/blog_migrate/0754d124c3435d10b321da94453a97da.png)
从图5可以看到,在conv4_3网络分为了3条线路:
- 经过一次batch norm+一次卷积后,生成了[1, num_class*num_priorbox, layer_height, layer_width]大小的feature用于softmax分类目标和非目标(其中num_class是目标类别,SSD300中num_class = 21,即20个类别+1个背景)
- 经过一次batch norm+一次卷积后,生成了[1, 4*num_priorbox, layer_height, layer_width]大小的feature用于bounding box regression(即每个点一组[dxmin,dymin,dxmax,dymax],参考Faster R-CNN 2.5节)
- 生成了[1, 2, 4*num_priorbox*layer_height*layer_width]大小的prior box blob,其中2个channel分别存储prior box的4个点坐标(x1, y1, x2, y2)和对应的4个参数variance
后续通过softmax分类判定Prior box是否包含目标,然后再通过bounding box regression即可可获取目标的精确位置,熟悉Faster RCNN的读者应该对上述过程应该并不陌生。其实pribox box的与Faster RCNN中的anchor非常类似,都是目标的预设框,没有本质的差异。区别是每个位置的prior box一般是4~6个,少于Faster RCNN默认的9个anchor;同时prior box是设置在不同尺度的feature maps上的,而且大小不同。
还有一个细节就是上面prototxt中的4个variance,这实际上是一种bounding regression中的权重。在图4线路(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()函数见到。
3 SSD的数据流
对于新学习SSD的人,肯定有一个很大的困惑,就是这么多feature maps和Prior Box,如何组合在一起进行forwards/backwards。本节专门介绍SSD的数据流动方式,也许有点难。但是只有了解SSD的数据流动方式才能真的理解。
![34f549a1a2d4b0e0fcc32ec2f2795d48.png](https://i-blog.csdnimg.cn/blog_migrate/409d2d1b437964321203b62c0993bbd2.jpeg)
上一节以conv4_3 feature map分析了如何检测到目标的真实位置,但是SSD 300是使用包括conv4_3在内的共计6个feature maps一同检测出最终目标的。在网络运行的时候显然不能像图6一样:一个feature map单独计算一次multiclass softmax socre+box regression(虽然原理如此,但是不能如此实现)。
那么多个feature maps如何协同工作?这时候就要用到Permute,Flatten和Concat这3种层了。其中conv4_3_norm_conf_perm的prototxt定义如下:
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]
而Flattlen和Concat层都是caffe自带层,请参照caffe official documentation理解。
![4f142a53e23e7d52ebf787357bd14652.png](https://i-blog.csdnimg.cn/blog_migrate/e2bb10faa6a4ca749824e7a1d04170de.jpeg)
那么接下来以conv4_3和fc7为例分析SSD是如何将不同size的feature map组合在一起进行prediction。图7展示了conv4_3和fc7合并在一起的过程中caffe blob shape变化(其他层类似,考虑到图片大小没有画出来,请脑补)。
- 对于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,获得检测结果
可以看到,SSD一次判断priorbox到底是背景 or 是20种目标类别之一,相当于将Faster R-CNN的RPN与后续proposal再分类进行了整合。
![dd7eae7b9d3499e23efc4350f8e7d9cd.png](https://i-blog.csdnimg.cn/blog_migrate/7099bb29bc04bb013d4b018805468b28.jpeg)
4 SSD网络结构优劣分析
SSD算法的优点应该很明显:运行速度可以和YOLO媲美,检测精度可以和Faster RCNN媲美。除此之外,还有一些鸡毛蒜皮的优点,不解释了。这里谈谈缺点:
- 需要人工设置prior box的min_size,max_size和aspect_ratio值。网络中prior box的基础大小和形状不能直接通过学习获得,而是需要手工设置。而网络中每一层feature使用的prior box大小和形状恰好都不一样,导致调试过程非常依赖经验。
- 虽然采用了pyramdial feature hierarchy的思路,但是对小目标的recall依然一般,并没有达到碾压Faster RCNN的级别。作者认为,这是由于SSD使用conv4_3低级feature去检测小目标,而低级特征卷积层数少,存在特征提取不充分的问题。
5 SSD训练过程
![2fb0bc153ff69e410b32b1b73b843b2a.png](https://i-blog.csdnimg.cn/blog_migrate/f3ebe52d11fc8752a922f766a32098ce.jpeg)
对于SSD,虽然paper中指出采用了所谓的“multibox loss”,但是依然可以清晰看到SSD loss分为了confidence loss和location loss(bouding box regression loss)两部分,其中N是match到GT(Ground Truth)的prior box数量;而α参数用于调整confidence loss和location loss之间的比例,默认α=1。SSD中的confidence loss是典型的softmax loss:
![6142fe63e849fcf823853bc882f03e0e.png](https://i-blog.csdnimg.cn/blog_migrate/7793aa78725106acbcc6dd94549b5046.jpeg)
其中
![4ba677891f1460e30efce6a2f6429f5c.png](https://i-blog.csdnimg.cn/blog_migrate/ce839060c692891429f8e86875125d6c.jpeg)
代表第i个prior box匹配到了第j个class为p类别的GT box;而location loss是典型的smooth L1 loss:
![654db604853e5dd23e9c4e7b3e13c572.png](https://i-blog.csdnimg.cn/blog_migrate/526c440cc90ee96eec6921384e25b0f2.jpeg)
Matching strategy:
在训练时,groundtruth boxes 与 default boxes(就是prior boxes) 按照如下方式进行配对:
- 首先,寻找与每一个ground truth box有最大的jaccard overlap的default box,这样就能保证每一个groundtruth box与唯一的一个default box对应起来(所谓的jaccard overlap就是IoU,如图9)。
- SSD之后又将剩余还没有配对的default box与任意一个groundtruth box尝试配对,只要两者之间的jaccard overlap大于阈值,就认为match(SSD 300 阈值为0.5)。
- 显然配对到GT的default box就是positive,没有配对到GT的default box就是negative。
![ed8c0af78768cf2e3dada45683368be9.png](https://i-blog.csdnimg.cn/blog_migrate/c69b035df7f551b5212db6334e97a930.png)
![c8e55c92351dd4c5275d9957ffd82d8c.png](https://i-blog.csdnimg.cn/blog_migrate/c0876f1fbb60e15e64f2a550bfa035e7.png)
![ab0d915ee066f823b9a00edab71b8c9e.png](https://i-blog.csdnimg.cn/blog_migrate/62dff37a0f4d69408b043923bba7a558.png)
Hard negative mining:
值得注意的是,一般情况下negative default boxes数量>>positive default boxes数量,直接训练会导致网络过于重视负样本,从而loss不稳定。所以需要采取:
- 所以SSD在训练时会依据confidience score排序default box,挑选其中confidence高的box进行训练,控制
Data augmentation:
数据增广。即对每一张image进行如下之一变换获取一个patch进行训练:
- 直接使用原始的图像(即不进行变换)
- 采样一个patch,保证与GT之间最小的IoU为:0.1,0.3,0.5,0.7 或 0.9
- 完全随机的采样一个patch
![7f9c437011caec21ca1d42674ac28e97.png](https://i-blog.csdnimg.cn/blog_migrate/057e0f28c7f5f742801284abd408098a.jpeg)
同时在原文中还提到:
- 采样的patch占原始图像大小比例在
之间
- 采样的patch的长宽比在
之间
- 当 Ground truth box中心恰好在采样的patch中时,保留整个GT box
- 最后每个patch被resize到固定大小,并且以0.5的概率随机的水平翻转
最终以这些处理好的patches进行训练。
其实Matching strategy,Hard negative mining,Data augmentation,都是为了加快网络收敛而设计的。尤其是Data augmentation,翻来覆去的randomly crop,保证每一个prior box都获得充分训练而已。后续有Focal loss解决这个问题。
SSD github : https://github.com/weiliu89/caffe/tree/ssd
SSD paper : https://arxiv.org/abs/1512.02325
SSD eccv2016 slide pdf : http://www.cs.unc.edu/~wliu/papers/ssd_eccv2016_slide.pdf
Focal Loss for Dense Object Detection :https://arxiv.org/abs/1708.02002
最后多说一句,如果是新手,了解经典的Faster RCNN/YOLO/SSD三种算法肯定就是入门检测啦。