论文地址:SSD: Single Shot MultiBox Detector

1 设计理念

1.1 采用卷积进行检测

与Yolo最后采用全连接层不同,SSD直接采用卷积对不同的特征图来进行提取检测结果。对于形状为 \(m\times n \times p\) 的特征图,只需要采用 \(3\times 3 \times p\) 这样比较小的卷积核得到检测值。


1.2 设置先验框

而SSD借鉴了Faster R-CNN中anchor的理念,每个单元设置尺度或者长宽比不同的先验框,预测的边界框(bounding boxes)是以这些先验框为基准的,在一定程度上减少训练难度。一般情况下,每个单元会设置多个先验框,其尺度和长宽比存在差异,如图5所示,可以看到每个单元使用了4个不同的先验框,图片中猫和狗分别采用最适合它们形状的先验框来进行训练,后面会详细讲解训练过程中的先验框匹配原则。

![](/img/2018-07-07-SSD-1.jpg)
SSD的先验框

对于每个单元的每个先验框,都有两个不同的检验值。

第一部分是各个类别的置信度或者评分,在预测过程中,置信度最高的那个类别就是边界框所属的类别,特别地,当第一个置信度值最高时,表示边界框中并不包含目标。

值得注意的是 SSD 将背景也当做了一个特殊的类别,如果检测目标共有 \(c\) 个类别,SSD 其实需要预测 \(c+1\) 个置信度值,其中第一个置信度指的是不含目标或者属于背景的评分。后面当我们说 \(c\) 个类别置信度时,请记住里面包含背景那个特殊的类别,即真实的检测类别只有 \(c-1\) 个。

第二部分就是边界框的 location,包含4个值 \((cx, cy, w, h)\) ,分别表示边界框的中心坐标以及宽高。

但是真实预测值其实只是边界框相对于先验框的转换值。先验框位置用 \(d=(d^{cx}, d^{cy}, d^w, d^h) \) 表示,其对应边界框用 \(b=(b^{cx}, b^{cy}, b^w, b^h)\) 表示,那么边界框的预测值 \(l\) 其实是 \(b\) 相对于 \(d\) 的转换值:

$$l^{cx} = (b^{cx} - d^{cx})/d^w, \space l^{cy} = (b^{cy} - d^{cy})/d^h$$

$$l^{w} = \log(b^{w}/d^w), \space l^{h} = \log(b^{h}/d^h)$$

习惯上,我们称上面这个过程为边界框的编码(encode),预测时,你需要反向这个过程,即进行解码(decode),从预测值 l 中得到边界框的真实位置 b :

$$b^{cx}=d^w l^{cx} + d^{cx}, \space b^{cy}=d^y l^{cy} + d^{cy}$$

$$b^{w}=d^w \exp(l^{w}), \space b^{h}=d^h \exp(l^{h})$$


综上所述,对于一个大小 \(m\times n\) 的特征图,共有 \(mn\) 个单元,每个单元设置的先验框数目记为 \(k\) ,那么每个单元共需要 \((c+4)k\) 个预测值,所有的单元共需要 \((c+4)kmn\) 个预测值,由于 SSD 采用卷积做检测,所以就需要 \((c+4)k\) 个卷积核完成这个特征图的检测过程


1.3 网络结构

![](/img/2018-07-07-SSD-2.jpg)

SSD利用了多尺度的特征图做检测

对每次卷积后输出的 \(38×38,19×19\) 等大小的特征图都保存下来,并都进行进一步的操作

SSD采用VGG16作为基础模型,然后在 VGG-16 的基础上新增了卷积层来获得更多的特征图以用于检测。分别将VGG16的全连接层 fc6 和 fc7 转换成 \(3\times3\) 卷积层 conv6 和 \(1\times1 \) 卷积层 conv7,为了配合这种变化,采用了一种 Atrous Algorithm,其实就是 conv6 采用扩展卷积或带孔卷积(Dilation Conv),其在不增加参数与模型复杂度的条件下指数级扩大卷积的视野,其使用扩张率(dilation rate)参数,来表示扩张的大小,

![](/img/2018-07-07-SSD-3.jpg)
  • (a)是普通的 \( 3\times3 \) 卷积,其视野就是 \( 3\times3 \)
  • (b)是扩张率为1,此时视野变成 \(7\times7\)
  • (c)扩张率为3时,视野扩大为 \(15\times15\) ,但是视野的特征更稀疏了。

Conv6 采用 \( 3\times3 \) 大小但 \(\text{dilation rate=6}\) 的扩展卷积。

之后移除 dropout 层和 fc8 层,并新增一系列卷积层,在检测数据集上做 finetuing。其中 VGG16 中的 Conv4_3 层将作为用于检测的第一个特征图。

conv4_3层特征图大小是 38\times38 ,但是该层比较靠前,其norm较大,所以在其后面增加了一个 L2 Normalization 层,以保证和后面的检测层差异不是很大,这个和 Batch Normalization 层不太一样,其仅仅是对每个像素点在 channle 维度做归一化,而 Batch Normalization 层是在 \(\text{[batch_size, width, height]}\) 三个维度上做归一化。归一化后一般设置一个可训练的放缩变量 gamma,使用TF可以这样简单实现

1
2
3
4
5
6
7
8
9
# l2norm (not bacth norm, spatial normalization)
def l2norm(x, scale, trainable=True, scope="L2Normalization"):
n_channels = x.get_shape().as_list()[-1]
l2_norm = tf.nn.l2_normalize(x, [3], epsilon=1e-12)
with tf.variable_scope(scope):
gamma = tf.get_variable("gamma", shape=[n_channels, ], dtype=tf.float32,
initializer=tf.constant_initializer(scale),
trainable=trainable)
return l2_norm * gamma

2 训练过程

先验框匹配

在训练过程中,首先要确定训练图片中的ground truth(真实目标)与哪个先验框来进行匹配,与之匹配的先验框所对应的边界框将负责预测它。

在Yolo中,ground truth的中心落在哪个单元格,该单元格中与其IOU最大的边界框负责预测它。但是在SSD中却完全不一样,SSD的先验框与ground truth的匹配原则主要有两点。

第一个原则是:对于图片中每个ground truth,找到与其IOU最大的先验框,该先验框与其匹配,这样,可以保证每个ground truth一定与某个先验框匹配。

通常称与ground truth匹配的先验框为正样本(其实应该是先验框对应的预测box,不过由于是一一对应的就这样称呼了),反之,若一个先验框没有与任何ground truth进行匹配,那么该先验框只能与背景匹配,就是负样本。

一个图片中ground truth是非常少的, 而先验框却很多,如果仅按第一个原则匹配,很多先验框会是负样本,正负样本极其不平衡,所以需要第二个原则。

第二个原则是:对于剩余的未匹配先验框,若某个 ground truth 的 \(\text{IOU}\) 大于某个阈值(一般是0.5),那么该先验框也与这个 ground truth 进行匹配。

这意味着某个 ground truth 可能与多个先验框匹配,这是可以的。但是反过来却不可以,因为一个先验框只能匹配一个 ground truth,如果多个 ground truth 与某个先验框 \( \text{IOU} \) 大于阈值,那么先验框只与 \( \text{IOU} \) 最大的那个先验框进行匹配。

第二个原则一定在第一个原则之后进行

![](/img/2018-07-07-SSD-4.jpg)
绿色的GT是ground truth,红色为先验框,FP表示负样本,TP表示正样本

尽管一个 ground truth 可以与多个先验框匹配,但是 ground truth 相对先验框还是太少了,所以负样本相对正样本会很多。为了保证正负样本尽量平衡,SSD 采用了 hard negative mining,就是对负样本进行抽样,抽样时按照置信度误差(预测背景的置信度越小,误差越大)进行降序排列,选取误差的较大的top-k作为训练的负样本,以保证正负样本比例接近 \(1:3\) 。

损失函数

损失函数定义为位置误差(locatization loss, loc)与置信度误差(confidence loss, conf)的加权和:

$$L(x, c, l, g) = \frac{1}{N}(L_{conf}(x,c) + \alpha L_{loc}(x,l,g))$$

  • \(N\) 是先验框的正样本数量
  • \(x^p_{ij}\in { 1,0 } \) 为一个指示参数,当 \(x^p_{ij}= 1\) 时表示第 \(i\) 个先验框与第 \(j\) 个 ground truth 匹配,并且 ground truth 的类别为 \(p\)
  • \(c\) 为类别置信度预测值
  • \(l\) 为先验框的所对应边界框的位置预测值
  • \(g\) 是 ground truth 的位置参数

对于位置误差,其采用 Smooth L1 loss,定义如下:

![](/img/2018-07-07-SSD-5.jpg)
$$ smooth\_{L\_{1}}(x) = \begin{cases} 0.5x^2, & \text{if |x| < 1}\\\\ |x|-0.5, & \text{otherwise} \end{cases} $$

对于置信度误差,其采用 softmax loss:

![](/img/2018-07-07-SSD-6.jpg)

数据扩增


参考

  1. 目标检测|SSD原理与实现