目标检测 FCOS(FCOS: Fully Convolutional One-Stage Object Detection)
flyfish
Anchor-based的模式
有两个超参数 aspect ratio 和scale来生成 anchor box
FCOS 不用生成anchor box,该算法是一种基于FCN的逐像素目标检测算法,实现了无锚点(anchor-free)、无提议(proposal free)的解决方案,并且提出了中心度(Center-ness)的思想
论文名称:FCOS:Fully Convolutional One-Stage Object Detection
论文链接:https://arxiv.org/abs/1904.01355
代码链接:https://github.com/tianzhi0549/FCOS/
本文叙述的是v1版本,v2版本(FCOS: A Simple and Strong Anchor-free Object Detector)有多处改进。
架构
FCOS目标检测器
设
F
i
∈
R
H
×
W
×
C
F_i \in \R^{H×W×C}
Fi∈RH×W×C 是 backbone CNN的第
i
i
i 层的特征图,
s
s
s 是该层之前的 total stride。
输入图像的 GT box 定义为
{
B
i
}
\{B_i\}
{Bi},其中
B
i
=
(
x
0
(
i
)
,
y
0
(
i
)
,
x
1
(
i
)
,
y
1
(
i
)
,
c
(
i
)
∈
R
4
×
{
1
,
2
,
…
,
C
}
B_i = (x^{(i)}_0,y^{(i)}_0, x^{(i)}_1, y^{(i)}_1, c^{(i)} \in \R^4 \times \{1, 2, …, C\}
Bi=(x0(i),y0(i),x1(i),y1(i),c(i)∈R4×{1,2,…,C}. 其中
(
x
0
(
i
)
,
y
0
(
i
)
)
(x^{(i)}_0, y^{(i)}_0)
(x0(i),y0(i)) 和
(
x
1
(
i
)
,
y
1
(
i
)
)
(x^{(i)}_1, y^{(i)}_1)
(x1(i),y1(i)) 表示边界框的左上角和右下角的坐标。
c
(
i
)
c^(i)
c(i) 是边界框中的对象所属的类。 C是类的数量,COCO数据集的类别为80。
对于 feature map F i F_i Fi 上的每个位置 ( x , y ) (x,y) (x,y),作者可以将其映射回输入图像的坐标 ( s 2 + x s , s 2 + y s ) (\frac{s}{2}+xs, \frac{s}{2}+ys) (2s+xs,2s+ys),它差不多刚好位于位置 ( x , y ) (x, y) (x,y) 的感受野中心附近。与基于Anchor的检测器不同,基于Anchor的检测器将输入图像上的位置作为(多个)anchor box的中心,并以这些anchor box为参考回归目标边框。回归的是Anchor box 与 GT box之间的偏移即Anchor box 与 GT box之间相差多少Anchor box 就能等于 GT box。
作者在该位置直接回归目标边框。换言之,作者的检测器直接将位置视为训练样本(training samples这俩单词论文中用斜体),而不是基于anchor的检测器中的anchor,准确点的说是anchor box 与 GT box之间的高IoU作为正样本。这与作为FCN进行语义分割是相同的。
具体而言,如果位置
(
x
,
y
)
(x,y)
(x,y) 落入到任何 GT Box 内部, 那么就将其视为正样本, 并且该位置的类标签
c
∗
c^\ast
c∗ 就是
B
i
B_i
Bi 的类标签。 否则它就是负样本并且
c
∗
=
0
c^\ast = 0
c∗=0(背景类)。 除了用于分类的标签之外,作者还有一个 4D 的实数向量
t
∗
=
(
l
∗
,
t
∗
,
r
∗
,
b
∗
)
t^\ast = (l^\ast,t^\ast,r^\ast,b^\ast)
t∗=(l∗,t∗,r∗,b∗), 该向量是每个样本的回归目标。 这里
l
∗
,
t
∗
,
r
∗
,
b
∗
l^\ast,t^\ast,r^\ast,b^\ast
l∗,t∗,r∗,b∗ 是从 location 到 bbox 四条边的距离,如下图所示。
如果某个位置属于多个边界框,则会将其视为模糊样本。现在,作者只选择具有最小面积的边界框作为其回归目标(最简单的策略)。
定位(x,y) 为正样本的条件:
定位(x,y) 落在GT box中
定位(x,y) 的类别 == 该GTbox的类别
加上阈值详细些
在特征图
F
i
F_i
Fi的每个定位(location)
classification score
p
x
,
y
p_{x,y}
px,y
regression prediction
t
x
,
y
t_{x,y}
tx,y
p
x
,
y
>
0.5
p_{x,y} > 0.5
px,y>0.5的定位,作为正样本(positive sample)
在下一节中,作者将 展示通过多级预测,可以显著减少模糊样本的数量。 形式上,如果位置
(
x
,
y
)
(x,y)
(x,y) 与边界框
B
i
B_i
Bi 相关联,则该位置的训练回归目标可以表示为:
{
l
∗
=
x
−
x
0
(
i
)
,
t
∗
=
y
−
y
0
(
i
)
r
∗
=
x
1
(
i
)
−
x
,
b
∗
=
y
1
(
i
)
−
y
\begin{cases}l^{\ast} = x - x^{(i)}_0, t^\ast = y - y^{(i)}_0 \\ r^\ast = x^{(i)}_1 - x, b^\ast = y^{(i)}_1 - y \end{cases}
{l∗=x−x0(i),t∗=y−y0(i)r∗=x1(i)−x,b∗=y1(i)−y
值得注意的是,FCOS可以利用尽可能多的前景样本来训练回归器(regressor :regress这个单词加了or 变名词就翻译成回归器吧)即GT box 内的每个像素点都是正样本。基于anchor的检测器将anchor box 与 GT box之间的高IoU作为正样本。作者认为这可能是FCOS优于基于anchor的原因之一。。
Network Outputs(网络输出)
对应于 training targets,作者网络的最后一层会预测用于分类的 80D 向量 p ⃗ \vec p p 和 bounding box 坐标 4D 向量 t ⃗ = ( l , t , r , b ) \vec t =(l,t,r,b) t=(l,t,r,b)。跟随 RetinaNet(Focal loss for dense object detection) 的做法,作者不是训练多类分类器,而是训练 C C C 个二元分类器。与 RetinaNet 类似,作者在 backbone 网络的特征图谱之后分别为分类和回归分支添加了 四个卷积层。此外,由于回归目标总是正的,作者使用 e x p ( x ) exp(x) exp(x) 将任意的实数都映射到回归分支顶部的 ( 0 , ∞ ) (0, \infty) (0,∞)。值得注意的是,FCOS 的网络输出变量比常用的 anchor based detectors(RetinaNet、 Faster R-CNN) 少 9 倍,其中每个位置有 9 个 anchor boxes.
损失函数(Loss Function):
向量字母顶上加一小箭头→, * 号 可以换成gt,加箭头没别的原因,只为看着方便。
L
(
p
⃗
x
,
y
,
t
⃗
x
,
y
,
centernes
s
x
,
y
)
=
1
N
p
o
s
∑
x
,
y
L
c
l
s
(
p
⃗
x
,
y
,
c
x
,
y
∗
)
+
λ
N
p
o
s
∑
x
,
y
1
c
x
,
y
∗
>
0
L
r
e
g
(
t
⃗
x
,
y
,
t
x
,
y
∗
)
\begin{aligned} L\left(\vec p_{x, y}, \vec t_{x, y}, \text { centernes } s_{x, y}\right)=& \frac{1}{N_{p o s}} \sum_{x, y} L_{c l s}\left(\vec p_{x, y}, c_{x, y}^{*}\right)+\\ & \frac{\lambda}{N_{p o s}} \sum_{x, y} 1_{c_{x, y}^{*}>0} L_{r e g}\left(\vec t_{x, y}, t_{x, y}^{*}\right)\\ \end{aligned}
L(px,y,tx,y, centernes sx,y)=Npos1x,y∑Lcls(px,y,cx,y∗)+Nposλx,y∑1cx,y∗>0Lreg(tx,y,tx,y∗)
上式中,
L
c
l
s
L_{cls}
Lcls 是 Focal Loss,
L
r
e
g
L_{reg}
Lreg 是 IOU loss (正如 UnitBox 中的一样).
N
p
o
s
N_{pos}
Npos 代表 positive samples 的数量,
λ
\lambda
λ 在本文中均为 1.
论文中的损失函数没有写全,这里把损失函数补全
L
(
p
⃗
x
,
y
,
t
⃗
x
,
y
,
c
e
n
t
e
r
n
e
s
s
⃗
x
,
y
)
=
1
N
p
o
s
∑
x
,
y
L
c
l
s
(
p
⃗
x
,
y
,
c
x
,
y
∗
)
+
λ
1
N
p
o
s
∑
x
,
y
1
c
x
,
y
∗
>
0
L
r
e
g
(
t
⃗
x
,
y
,
t
x
,
y
∗
)
+
λ
2
N
p
o
s
∑
x
,
y
1
c
x
,
y
∗
>
0
L
center-ness
(
c
e
n
t
e
r
n
e
s
s
⃗
x
,
y
,
centerness
x
,
y
∗
)
\begin{aligned} L\left(\vec p_{x, y}, \vec t_{x, y}, \vec { centerness} _{x, y}\right)=& \frac{1}{N_{p o s}} \sum_{x, y} L_{c l s}\left(\vec p_{x, y}, c_{x, y}^{*}\right)+\\ & \frac{\lambda_{1}}{N_{p o s}} \sum_{x, y} 1_{c_{x, y}^{*}>0} L_{r e g}\left(\vec t_{x, y}, t_{x, y}^{*}\right)+\\ & \frac{\lambda_{2}}{N_{p o s}} \sum_{x, y} 1_{c_{x, y}^{*}>0} L_{\text {center-ness}}\left(\vec {centerness}_{x, y}, \text {centerness}_{x, y}^{*}\right) \end{aligned}
L(px,y,tx,y,centernessx,y)=Npos1x,y∑Lcls(px,y,cx,y∗)+Nposλ1x,y∑1cx,y∗>0Lreg(tx,y,tx,y∗)+Nposλ2x,y∑1cx,y∗>0Lcenter-ness(centernessx,y,centernessx,y∗)
(1)类别
L d e t = − α ( 1 − p k ) γ l o g ( p k ) L_{det} = -\alpha(1-p_k)^\gamma\mathrm{log}(p_k) Ldet=−α(1−pk)γlog(pk)
(2)边框
UnitBox 中提出的 IoU Loss
L
b
o
x
=
−
l
n
(
I
o
U
k
)
L_{box} = -\mathrm{ln}(IoU_k)
Lbox=−ln(IoUk)
(3)Center-ness
图中红色和蓝色值分别1和0,其它颜色介于两者之间,从物体中心向外,center-ness从1递减为0
在 FCOS 中使用多级预测后,FCOS 和 anchor based 的检测器之间仍存在性能差距。 作者观察到这是由于 远离物体中心的位置产生的许多低质量预测边界框造成的
作者提出了一种简单而有效的策略来抑制这些低质量的检测边界框而不引入任何超参数。 具体来说,作者添加一个单层分支,与分类分支并行,以预测一个位置的 “中心度(center-ness)”(即,从该位置到该位置所负责的对象的中心的距离), 给定位置的回归目标
l
∗
,
t
∗
,
r
∗
l^\ast,t^\ast,r^\ast
l∗,t∗,r∗ 和
b
∗
b^\ast
b∗,center-ness target 定义为
c
e
n
t
e
r
n
e
s
s
∗
=
min
(
l
∗
,
r
∗
)
max
(
l
∗
,
r
∗
)
×
min
(
t
∗
,
b
∗
)
max
(
t
∗
,
b
∗
)
centerness^\ast = \sqrt{\frac{\min(l^\ast, r^\ast)}{\max(l^\ast, r^\ast)} \times \frac{\min(t^\ast, b^\ast)}{\max(t^\ast, b^\ast)}}
centerness∗=max(l∗,r∗)min(l∗,r∗)×max(t∗,b∗)min(t∗,b∗)
换成 gt,只为看着方便
c
e
n
t
e
r
n
e
s
s
g
t
=
m
i
n
(
l
g
t
,
r
g
t
)
m
a
x
(
l
g
t
,
r
g
t
)
×
m
i
n
(
t
g
t
,
b
g
t
)
m
a
x
(
t
g
t
,
b
g
t
)
centerness^{gt} = \sqrt{\frac{\mathrm{min}(l^{gt},r^{gt})}{\mathrm{max}(l^{gt},r^{gt})} \times \frac{\mathrm{min}(t^{gt},b^{gt})}{\mathrm{max}(t^{gt},b^{gt})}}
centernessgt=max(lgt,rgt)min(lgt,rgt)×max(tgt,bgt)min(tgt,bgt)
作者在这里使用 sqrt 来减缓中心的衰减。center-ness 从0到1,因此用 二元交叉熵(BCE)损失训练。 损失被添加到损失函数公式中。 在测试时,通过将预测的 center-ness 与相应的分类得分相乘来计算最终得分(用于对检测到的边界框进行排名)。 因此, center-ness 可以使远离物体中心的边界框的 scores 减小。 结果,这些低质量的边界框很可能被最终的非最大抑制(NMS)过程滤除,从而显著提高了检测性能。
计算score的方法
Score
=
Classification Score
×
Center-ness
\text{ Score} = \text{Classification Score} × \text{Center-ness}
Score=Classification Score×Center-ness
使用NMS删除了不合格的bounding box
推理(Inference)
给定输入图像,作者将其放入网络进行一次 forward 计算, 并获得 feature map F i F_i Fi 上的每个位置的分类分数 p ⃗ x , y \vec p_{x,y} px,y 和回归预测值 t ⃗ x , y \vec t_{x,y} tx,y。 跟随 RetinaNet 的设定,作者选择 p ⃗ x , y > 0.05 \vec p_{x,y} > 0.05 px,y>0.05 的位置作为正样本并通过反转公式来获得预测的边界框。
使用FPN进行多级预测
FPN使用
P
3
,
P
4
,
P
5
,
P
6
,
P
7
{P_3,P_4,P_5,P_6,P_7 }
P3,P4,P5,P6,P7层特征,其中
P
3
P_3
P3、
P
4
P_4
P4和
P
5
P_5
P5分别通过
C
3
C_3
C3、
C
4
C_4
C4和
C
5
C_5
C5的
1
×
1
1\times 1
1×1卷积以及top-down connection生成。
P
6
P_6
P6和
P
7
P_7
P7则是分别通过
P
5
P_5
P5和
P
6
P_6
P6进行stride为2的
1
×
1
1\times1
1×1卷积生成。
各特征的stride分别为8,16,32,64和128。
anchor-based方法对不同的层使用不同的大小,论文则直接限制每层的bbox回归范围。首先计算
l
∗
l^*
l∗,
t
∗
t^*
t∗,
r
∗
r^*
r∗和
b
∗
b^*
b∗,如果满足
m
a
x
(
l
∗
,
t
∗
,
r
∗
,
b
∗
)
>
m
i
max(l^*,t^*,r^*,b^*)>m_i
max(l∗,t∗,r∗,b∗)>mi或
m
a
x
(
l
∗
,
t
∗
,
r
∗
,
b
∗
)
<
m
i
−
1
max(l^*,t^*,r^*,b^*)<m_{i-1}
max(l∗,t∗,r∗,b∗)<mi−1,则设为负样本,不需要进行bbox回归。
m
m
m为层
i
i
i的最大回归距离,
m
2
m_2
m2,
m
3
m_3
m3,
m
4
m_4
m4,
m
5
m_5
m5,
m
6
m_6
m6和
m
7
m_7
m7分别为0,64,128,256,512和
∞
\infty
∞。如果在这样设置下,像素仍存在歧义,则选择区域最小的作为回归目标,从实验来看,这样设定的结果很好。
根据feature level的最大回归距离(maximum regress distance),筛选正样本
m
a
x
(
l
∗
,
t
∗
,
r
∗
,
b
∗
)
>
m
i
或
者
m
a
x
(
l
∗
,
t
∗
,
r
∗
,
b
∗
)
<
m
i
−
1
max(l^*,t^*,r^*,b^*)>m_i 或者 max(l^*,t^*,r^*,b^*)<m_{i-1}
max(l∗,t∗,r∗,b∗)>mi或者max(l∗,t∗,r∗,b∗)<mi−1
m
i
m_i
mi 是feature level
i
i
i 需要回归的最大距离
m
2
,
m
3
,
m
4
,
m
5
,
m
6
,
m
7
=
0
,
64
,
128
,
256
,
512
,
∞
{m_2, m_3, m_4, m_5, m_6, m_7} = { 0,64,128,256,512,\infty }
m2,m3,m4,m5,m6,m7=0,64,128,256,512,∞
最后,不同层间共享head,不仅减少参数,还能提高准确率。而由于不同的层负责不同的尺寸,所以不应该使用相同的head,因此,论文将
e
x
p
(
x
)
exp(x)
exp(x)改为
e
x
p
(
s
i
x
)
exp(s_ix)
exp(six),添加可训练的标量
s
i
s_i
si来自动调整不同层的指数基底 。
different feature level:
exp
(
x
)
改
为
exp
(
s
i
x
)
\text{exp}(x) 改为 \text{exp}(s_ix)
exp(x)改为exp(six)
s i s_i si :可训练的标量,用来自动调整exp的base
输入到输出了解框架
一、输入
维度是 [B, H, W, 3]
B表示batch size,H表示图片高度,W表示图片宽度,3表示通道数
二、ResNet50
我们从stage1到stage5提取最后的特征图。
C1: [B, H/2, W/2, 64]
C2: [B, H/4, W/4, 256]
C3: [B, H/8, W/8, 512]
C4: [B, H/16, W/16, 1024]
C5: [B, H/32, W/32, 2048]
框架中输入是H=800,W=1024
选择下C3:[B,800/8,1024/8,512]=[B,100,128,512 和图上的一样
三、FPN
fpn_stride = [8, 16, 32, 64, 128]
P3: [B, H/8, W/8, 256]
P4: [B, H/16, W/16, 256]
P5: [B, H/32, W/32, 256]
P6: [B, H/64, W/64, 256]
P7: [B, H/128, W/128, 256]
四、Header
(1)共享头部分支
head = [[Conv2d, GroupNormalization, relu],
[Conv2d, GroupNormalization, relu],
[Conv2d, GroupNormalization, relu],
[Conv2d, GroupNormalization, relu]]
对应到代码
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(gn): GroupNorm(32, 256, eps=1e-05, affine=True)
(activate): ReLU(inplace=True)
(2)Centerness head
P3_ctrness: sigmoid(head(P3)) # [B, H/8, W/8, 1]
P4_ctrness: sigmoid(head(P4)) # [B, H/16, W/16, 1]
P5_ctrness: sigmoid(head(P5)) # [B, H/32, W/32, 1]
P6_ctrness: sigmoid(head(P6)) # [B, H/64, W/64, 1]
P7_ctrness: sigmoid(head(P7)) # [B, H/128, W/128, 1]
(3)Class predictions head:
P3_class_prob: sigmoid(head(P3)) * p3_ctrness # [B, H/8, W/8, C]
P4_class_prob: sigmoid(head(P4)) * p4_ctrness # [B, H/16, W/16, C]
P5_class_prob: sigmoid(head(P5)) * p5_ctrness # [B, H/32, W/32, C]
P6_class_prob: sigmoid(head(P6)) * p6_ctrness # [B, H/64, W/64, C]
P7_class_prob: sigmoid(head(P7)) * p7_ctrness # [B, H/128, W/128, C]
(4)Box regression head
从位置中心预测(l,t,r,b)
P3_reg: conv2d(head(P3)) # [B, H/8, W/8, 4]
P4_reg: conv2d(head(P4)) # [B, H/16, W/16, 4]
P5_reg: conv2d(head(P5)) # [B, H/32, W/32, 4]
P6_reg: conv2d(head(P6)) # [B, H/64, W/64, 4]
P7_reg: conv2d(head(P7)) # [B, H/128, W/128, 4]