The Single Shot Detector
SSD算法Pytorch
实现:https://github.com/codecat0/CV/tree/main/Object_Detection/SSD
1 Model


1.1 Multi-scale feature maps for detection
我们在基础网络(VGG)的后面增加了不同大小的卷积层,使得特征图经过这些卷积层的大小逐渐减少,从而使得网络能够在不同尺度进行检测。
具体来说:
- VGG网络
Conv5_3
之前的称为基础网络,用来提取图像特征 - 将VGG网络中
MaxPool5
的大小从2x2-s2
改为3x3-s1
- 将VGG网络中的
FC6
和FC7
分别改为卷积层Conv6
和Conv7
Conv6
使用的是空洞卷积。卷积核kernel
为3,padding
为6,dilation
为6。
- 在
Conv7
后面增加Conv8
、Conv9
、Conv10
、Conv11
这样做的目的:使得大特征图(感受野小)用来检测小物体,小特征图(感受野大)用来检测大物体
1.2 Convolutional predictors for detection
对于每一个特征图单元,我们通过
3
×
3
C
o
n
v
3 \times 3 Conv
3×3Conv产生类别分数class score
即类别参数c
和4
个偏移量相对于ground truth box
即回归参数。所以对于一个
m
×
n
m \times n
m×n的特征图有
(
c
+
4
)
m
n
(c+4)mn
(c+4)mn
2. Training
2.1 Matching strategy
在训练过程中,我们需要确定默认边界框对应的真实边界框。对于每个真实边界框,我们从默认边界框中选择,这些默认边界框会在位置,长宽比和尺度上发生变化。
我们将每个真实边界框与具有最好的Jaccard重叠的默认边界框相匹配,然后将默认边界框匹配到与之Jaccard重叠高于阈值0.5的任何真实边界框。
注意:本文的默认边界框default box
对应于Faster-RCNN中的anchor
2.2 Training objective
SSD训练的目标函数与Faster-RCNN相似。总损失函数为定位损失和置信度损失:
L
(
x
,
c
,
l
,
g
)
=
1
N
(
L
c
o
n
f
(
x
,
c
)
+
α
L
l
o
c
(
x
,
l
,
g
)
)
L(x,c,l,g)=\frac {1} {N}(L_{conf}(x,c) + \alpha L_{loc}(x,l,g))
L(x,c,l,g)=N1(Lconf(x,c)+αLloc(x,l,g))
其中 N N N是匹配的默认边界框的数量,如果 N = 0 N=0 N=0,则将损失设为 0 0 0。
定位损失是预测框
l
l
l与真实框
g
g
g参数之间的 Smooth L1
损失:
L
l
o
c
(
x
,
l
,
g
)
=
∑
i
∈
P
o
s
N
∑
m
∈
{
c
x
,
c
y
,
w
,
h
}
x
i
j
k
s
m
o
o
t
h
L
1
(
l
i
m
−
g
^
j
m
)
L_{loc}(x,l,g)=\sum_{i \in Pos}^N \sum_{m\in\{cx,cy,w,h\}}x_{ij}^ksmoothL_1(l_i^m-\hat g_j^m)
Lloc(x,l,g)=i∈Pos∑Nm∈{cx,cy,w,h}∑xijksmoothL1(lim−g^jm)
g ^ j c x = ( g j c x − d i c x ) / d i w g ^ j c y = ( g j c y − d i c y ) / d i h g ^ j w = l o g ( g j w d i w ) g ^ j h = l o g ( g j h d i h ) \hat g_j^{cx}=(g_j^{cx}-d_i^{cx})/d_i^w \quad \hat g_j^{cy}=(g_j^{cy}-d_i^{cy})/d_i^h \\ \hat g^w_j=log(\frac {g_j^w} {d_i^w}) \quad \hat g^h_j=log(\frac {g_j^h} {d_i^h}) g^jcx=(gjcx−dicx)/diwg^jcy=(gjcy−dicy)/dihg^jw=log(diwgjw)g^jh=log(dihgjh)
其中 x i j k = { 0 , 1 } x_{ij}^k=\{0, 1\} xijk={0,1}表示第 i i i个默认边界框匹配到类别为 k k k的第 j j j个默认边界框
置信度损失是在多类别的Softmax
损失:
L
c
o
n
f
(
x
,
c
)
=
−
∑
i
∈
P
o
s
N
x
i
j
p
l
o
g
(
c
^
i
p
)
−
∑
i
∈
N
e
g
l
o
g
(
c
^
i
0
)
w
h
e
r
e
c
^
i
p
=
e
x
p
(
c
i
p
)
∑
p
e
x
p
(
c
i
p
)
L_{conf}(x,c)=-\sum_{i \in Pos}^N x_{ij}^plog(\hat c_i^p)-\sum_{i \in Neg}log(\hat c_i^0) \quad where \quad \hat c_i^p=\frac {exp(c_i^p)} {\sum_pexp(c_i^p)}
Lconf(x,c)=−i∈Pos∑Nxijplog(c^ip)−i∈Neg∑log(c^i0)wherec^ip=∑pexp(cip)exp(cip)
2.3 Choosing scales and aspect ratios for default boxes
假设我们要使用
m
m
m个特征图进行预测。每个特征映射默认边界框的尺度计算如下:
s
k
=
s
m
i
n
+
s
m
a
x
−
s
m
i
n
m
−
1
(
k
−
1
)
,
k
∈
[
1
,
m
]
s_k=s_{min} + \frac {s_{max}-s_{min}} {m-1}(k-1), \quad k \in [1,m]
sk=smin+m−1smax−smin(k−1),k∈[1,m]
其中 s m i n s_{min} smin为原始尺度的0.2, s m a x s_{max} smax为原始尺度的0.9
我们还为默认边界框添加不同的长宽比,并将其表示为 a r ∈ { 1 , 2 , 3 , 1 / 2 , 1 / 3 } a_r \in \{1, 2, 3, 1/2, 1/3\} ar∈{1,2,3,1/2,1/3}。对于长宽比为1时,我们还为其添加一个默认边界框,尺度为 s k ′ = s k s k + 1 s^{'}_k=\sqrt {s_ks_{k+1}} sk′=sksk+1。对于每一个默认边界框,我们可以计算宽度 w k a = s k a r w_k^a=s_k\sqrt a_r wka=skar和高度 h k a = s k / a r h_k^a=s_k/\sqrt a_r hka=sk/ar
官方源码设置为:
先验框大小: [ 30 , 60 , 111 , 162 , 213 , 264 , 315 ] [30,60,111,162,213,264,315] [30,60,111,162,213,264,315]
Layer Name | s k 、 s k ′ s_k、s_k^{'} sk、sk′ | default box num |
---|---|---|
Conv4_3 | 30、42 | 4 |
FC7 | 60、82 | 6 |
Conv8_2 | 111、134 | 6 |
Conv9_2 | 162、186 | 6 |
Conv10_2 | 213、237 | 4 |
Conv11_2 | 264、288 | 4 |
2.4 Hard negative mining
在匹配步骤之后,大多数默认边界框为负例,尤其是当可能的默认边界框数量较多时。这在正的训练实例和负的训练实例之间引入了显著的不平衡。我们不使用所有负例,而是使用每个默认边界框的最高置信度损失来排序他们,并挑选最高的置信度,以便负例和正例之间的比例至多为3:1,我们发现这会导致更快的优化和更稳定的训练。
2.5 Data augmentation
- 水平翻转
- 随机裁剪+颜色扭曲
- 随机采集块域
3. Predict
预测过程比较简单,对于每个预测框,首先根据类别置信度确定其类别(置信度最大者)与置信度值,并过滤属于背景的预测框。然后根据置信度阈值(如0.5)过滤掉阈值较低的预测框。对于留下的预测框进行解码,根据先验框得到其真实的位置参数(解码后一般还需要做clip,防止预测框位置超出图片)。解码之后,一般需要根据置信度进行降序排列,然后仅保留 top-k(如 400)个预测框。最后就是进行NMS算法,过滤掉哪些重叠度较大的预测框。最后剩余的预测框就是检测结果了。
4. 总结
对于一张3x300x300
经过SSD网络会得到6个不同尺度的特征图:512x38x38
、1024x19x19
、512x10x10
、256x5x5
、256x3x3
和256x1x1
。
其中对于每个不同尺度特征图,我们会对应在每个特征图上的每个特征点生成不同数目的先验框,对应关系为[4, 6, 6, 6, 4, 4]
。在不同尺度的特征图生成的先验框不仅数目不一样,而且大小和宽高比也不一样,其中大小设置见2.3,这样我们就获得了38x38x4+19x19x6+10x10x6+5x5x6+3x3x4+1x1x4=8732
个先验框。
接下来需要对这8732个先验框匹配与之对应的真实框,匹配策略是
- 对于每个真实框,匹配IOU值最大的先验框,保证每个真实框都至少有一个先验框与之匹配
- 对每个先验框,匹配IOU值大于0.5的真实框
对于匹配到真实框的先验框,我们设置为正样本;对于没有匹配到的,设置为负样本。由于存在大量先验框是负样本,没有匹配到真实框,所以我们在训练时选取正负样本比例为1:3。假设在这8732个先验框中只有300个正样本,则总的训练样本数为300+900=1200
。
接下来开始训练:
我们的网络输出分为2部分:
- 一部分为回归参数的预测,其输出形状为:
(1200,4)
; - 另一部分是置信度参数的预测,其输出形状为:
(1200, num_classes+1
)。
标签文件与之对应分为两部分:
- 一部分是回归的标签,其形状为:
(1200,4)
,其中1200
代表训练时的样本数,4
代表训练样本与真实框的回归系数; - 另一部分是置信度的标签,其形状为:
(1200,num_classes+1)
,其中1200
代表训练时的样本数,num_classes
代表训练样本与真实框的匹配关系,若匹配到即正样本,其值表示为:在匹配的真实框对应类别的索引值为1,其他索引处的值为0;若未匹配到即负样本,其值表示为:在索引0处的值为1,其他索引处为0
然后计算损失,对回归进行SmoothL1损失,对置信度进行多分类的softmax损失。再进行反向传播
更新SSD模型参数