Generalized Focal Loss v1和v2
最近由大佬推荐,看了这两篇高质量论文。其中,ECCV 2020 workshop目标检测跟踪赛道冠军深蓝团队采用了GFocal Loss v1;NanoDet,一个用于手机端的检测框架,也采用了GFocal Loss v2。
《Generalized Focal Loss: Learning Qualified and Distributed Bounding Boxes for Dense Object Detection》收录与NeurIPs 2020
PDF:https://arxiv.org/abs/2006.04388
代码:https://github.com/implus/GFocal
作者讲解:https://zhuanlan.zhihu.com/p/147691786
(猛)
《Generalized Focal Loss V2: Learning Reliable Localization Quality Estimation for Dense Object Detection》收录与CVPR2021
PDF:https://arxiv.org/abs/2011.12885
代码:https://github.com/implus/GFocalV2
作者讲解:https://zhuanlan.zhihu.com/p/313684358
(是真滴猛)
Generalized Focal Loss v1
摘要
单阶段检测器通常将目标检测任务当做密集分类和定位(bbox回归)任务。其中,分类任务通常采用Focal Loss进行优化,回归任务通常学习一个Dirac delta distribution(下面会详细解释)。最近的一些单阶段检测器添加了一个预测分支,用于对目标定位的质量的评估。得到的评估结果会对分类分支进行补充,提高检测的效果。所以网络结构有三个输出:分类、定位和质量评估。作者则在文章提出了两个问题:(1)训练时,分类分支和质量评估分支单独训练,在推理时却将二者相乘同时应用;(2)当遇到较为模糊、不确定性比较高的场景时,预测不灵活的Dirac delta分布往往不太合适。为了解决提出的两个问题,作者将分类和质量评估两个分支进行融合,输出分类和位置估计的联合表示,并且将回归分支的输出调整为一个向量,来表示位置的随机分布。这样一来,标签便从{0,1}便为了0-1,成了连续标签。于是作者便提出了Generalized Focal Loss(GFL)来对模型进行优化。最终,相同模型配置下的SAPD和ATSS的AP分别为43.5%和43.6%,而作者改进后的模型达到了45%的AP。
介绍
近来,很多密集检测器(dense detectors)通过表示目标的位置以及位置评估来提高检测效果,尤其是将目标位置的表示学习成一个Dirac delta分布。以FCOS为例,FCOS除了分类和回归分支以外,还对位置质量进行了预估,采用IOU得分或者中心度(centerness)的形式。在最终推理时,将此结果与分类得分相乘,再输入进NMS中。在现有的实验中,本文作者发现了以下问题:
1. 质量估计和分类得分在训练和推理时的使用不一致(Inconsistent usage of localization quality estimation and classification score between training and inference)
在模型训练时,这是两个独立的分支,然而在推理时,却直接将二者进行相乘,然而将结果输入NMS中。
另外,位置质量估计分支在训练时只被分配了正样本,这是很不可靠的。一些负样本,可能会有无法控制的高的分。如下图(a)中两个框,虽然有着极地的分类得分,然而它们预测的IOU得分却都在0.9以上。这种负样本随机得到高质量评估得分,在NMS中很可能便排在一些正样本之前,会对最终的跟踪效果产生负面影响。
2. Bbox表示不灵活(Inflexible representation of bounding boxes)
大多检测器都是预测一个Dirac delta分布来表示bbox的位置。虽然有些检测器将Dirac delta分布改为了Gaussian分布,却依旧无法满足bbox的真实分布,无法考虑到比较模糊不确定的场景,比如bbox有一部分的边界被遮挡。
方法
对于上述第一个问题,作者将位置的质量评估融入到了分类分支之中,形成一个联合表示,得到的向量在ground-truth类别下标处的值表示其相应的定位质量(文章中采用预测的bbox和gt的IOU得分)。这样以来,作者便将分类得分和IOU得分联合到一起(classification-IoU joint representation),可以进行端到端训练,在推理时也可以直接使用。此外,在训练时负样本的质量得分赋为0,使得整体的定位质量预测更为可靠、更稳定。然而此时,训练时的标签已经从{0,1}变成了连续的0~1的标签。虽然Focal Loss可以通过改变标准交叉熵来很好地平衡正负样本,但并不支持连续的标签,公式如下:
F
L
(
p
)
=
−
(
1
−
p
t
)
γ
log
(
p
t
)
,
p
t
=
{
p
,
when
y
=
1
1
−
p
,
when
y
=
0
\mathbf{F L}(p)=-\left(1-p_{t}\right)^{\gamma} \log \left(p_{t}\right), p_{t}=\left\{\begin{aligned} p, & \text { when } y=1 \\ 1-p, & \text { when } y=0 \end{aligned}\right.
FL(p)=−(1−pt)γlog(pt),pt={p,1−p, when y=1 when y=0
其中,
y
∈
{
1
,
0
}
y \in\{1,0\}
y∈{1,0}表示gt中的真实标签,
p
∈
[
0
,
1
]
p \in[0,1]
p∈[0,1]代表预测的
y
=
1
y=1
y=1的概率。为了解决FL无法使用的问题,作者将其魔改成了 Quality Focal Loss(QFL)。
Quality Focal Loss(QFL):
对于0~1连续的标签来说,当
y
=
0
y=0
y=0时,代表质量得分为0的负样本;当
0
<
y
≤
1
0<y≤1
0<y≤1时,代表正样本的IOU得分(预测的bbox和gt之间的IOU)。将网络的输出进行sigmoid后的值记为
σ
\sigma
σ。QFL具体公式如下:
Q
F
L
(
σ
)
=
−
∣
y
−
σ
∣
β
(
(
1
−
y
)
log
(
1
−
σ
)
+
y
log
(
σ
)
)
\mathbf{Q F L}(\sigma)=-|y-\sigma|^{\beta}((1-y) \log (1-\sigma)+y \log (\sigma))
QFL(σ)=−∣y−σ∣β((1−y)log(1−σ)+ylog(σ))
与FL不同的是:(1)FL中的交叉熵部分
−
log
(
p
t
)
-\log \left(p_{t}\right)
−log(pt)被拓展为完整的模式
−
(
(
1
−
y
)
log
(
1
−
σ
)
+
y
log
(
σ
)
)
-((1-y) \log (1-\sigma)+y \log (\sigma))
−((1−y)log(1−σ)+ylog(σ));(2)FL中的比例因子
(
1
−
p
t
)
γ
\left(1-p_{t}\right)^{\gamma}
(1−pt)γ调整为
σ
\sigma
σ和
y
y
y之间的绝对距离,即
∣
y
−
σ
∣
β
(
β
≥
0
)
|y-\sigma|^{\beta} (\beta \geq 0)
∣y−σ∣β(β≥0)。和FL相同,
∣
y
−
σ
∣
β
|y-\sigma|^{\beta}
∣y−σ∣β起到了调制因子的作用,当预测的质量估计与真实标签相差很多的时候,这部分的值便较大,使得模型更关注于这些难分类的样本;当预测的与真实标签很接近的时候,损失便也接近0,所以简单样本的损失权重便被调低了。下面是mmdetection/mmdet/models/losses/gfocal_loss.py中QFL的部分,pred是预测的联合得分(classification-IoU joint representation),大小为N×C,N为batch_size,C为类别数。从真实标签输进来的有标签(label)和IOU得分(score),最后将预测的对应类别的得分和真实得分进行计算。
# negatives are supervised by 0 quality score
pred_sigmoid = pred.sigmoid()
scale_factor = pred_sigmoid
zerolabel = scale_factor.new_zeros(pred.shape)
loss = F.binary_cross_entropy_with_logits(
pred, zerolabel, reduction='none') * scale_factor.pow(beta)
# FG cat_id: [0, num_classes -1], BG cat_id: num_classes
bg_class_ind = pred.size(1)
pos = ((label >= 0) & (label < bg_class_ind)).nonzero().squeeze(1)
pos_label = label[pos].long()
# positives are supervised by bbox quality (IoU) score
scale_factor = score[pos] - pred_sigmoid[pos, pos_label]
loss[pos, pos_label] = F.binary_cross_entropy_with_logits(
pred[pos, pos_label], score[pos],
reduction='none') * scale_factor.abs().pow(beta)
loss = loss.sum(dim=1, keepdim=False)
对于上述的第二个问题,作者用预测随机分布来代替原本的Dirac delta分布。
不难看出,Dirac delta分布其实就是在区间内,只有一个值的概率为1,其余都为0,积分形式后的值也是1,
y
=
∫
−
∞
+
∞
δ
(
x
−
y
)
d
x
=
1
y=\int_{-\infty}^{+\infty} \delta(x-y) \mathrm{d} x=1
y=∫−∞+∞δ(x−y)dx=1,就比如之前的FCOS预测中心点到边界的距离是直接输出一个预测的值。而改完之后的网络输出,并不是一个值,而是一个向量,预测其在连续空间上的离散概率分布,应该可以理解为中心点到边界距离的概率,如下图。作者还提出了Distribution Focal Loss(DFL)来优化此分支。
Distribution Focal Loss(DFL):
假设得到的随机分布为
P
(
x
)
P(x)
P(x),没有引入其他任何的先验知识。若给定的标签范围是
y
0
≤
y
≤
y
n
,
n
∈
N
+
y_{0} \leq {y} \leq y_{n},n \in \mathbb{N}^{+}
y0≤y≤yn,n∈N+,那么从预测的分布中得到的结果便为:
y
^
=
∫
−
∞
+
∞
P
(
x
)
x
d
x
=
∫
y
0
y
n
P
(
x
)
x
d
x
.
\hat{y}=\int_{-\infty}^{+\infty} P(x) x \mathrm{~d} x=\int_{y_{0}}^{y_{n}} P(x) x \mathrm{~d} x .
y^=∫−∞+∞P(x)x dx=∫y0ynP(x)x dx.为了使其和卷积神经网络一致,作者将连续分布转换为离散分布,将范围
[
y
0
,
y
n
]
\left[y_{0}, y_{n}\right]
[y0,yn]离散化为
{
y
0
,
y
1
,
…
,
y
i
,
y
i
+
1
,
…
,
y
n
−
1
,
y
n
}
\left\{y_{0}, y_{1}, \ldots, y_{i}, y_{i+1}, \ldots, y_{n-1}, y_{n}\right\}
{y0,y1,…,yi,yi+1,…,yn−1,yn},步长为1。即在离散概率分布
∑
i
=
0
n
P
(
y
i
)
=
1
\sum_{i=0}^{n} P\left(y_{i}\right)=1
∑i=0nP(yi)=1下,最终预测的结果为
y
^
=
∑
i
=
0
n
P
(
y
i
)
y
i
\hat{y}=\sum_{i=0}^{n} P\left(y_{i}\right) y_{i}
y^=∑i=0nP(yi)yi。
作者观察上述三种不同分布却积分结果相同的情况,显而易见,第三种更适合,最合适的位置如果存在,通常与标签都不会相差的太远。所以作者让模型更偏向于得到第三种情况的分布。作者给出的方案是,增大真实的
y
y
y两侧的
y
i
y_i
yi和
y
i
+
1
y_{i+1}
yi+1(
y
i
<
y
<
y
i
+
1
y_i<y<y_{i+1}
yi<y<yi+1)的概率。由于回归分支只训练正样本,所以并不需要考虑样本不均衡的问题,所以DFL的定义可以如下:
D
F
L
(
S
i
,
S
i
+
1
)
=
−
(
(
y
i
+
1
−
y
)
log
(
S
i
)
+
(
y
−
y
i
)
log
(
S
i
+
1
)
)
\mathbf{D F L}\left(\mathcal{S}_{i}, \mathcal{S}_{i+1}\right)=-\left(\left(y_{i+1}-y\right) \log \left(\mathcal{S}_{i}\right)+\left(y-y_{i}\right) \log \left(\mathcal{S}_{i+1}\right)\right)
DFL(Si,Si+1)=−((yi+1−y)log(Si)+(y−yi)log(Si+1))
其中,
S
i
S_i
Si代表着
P
(
y
i
)
P(y_i)
P(yi)。关于
S
i
S_i
Si和
S
i
+
1
S_{i+1}
Si+1的取值,作者在补充材料中进行了详细证明(有兴趣的可以自己去看证明过程)
S
i
=
y
i
+
1
−
y
y
i
+
1
−
y
i
,
S
i
+
1
=
y
−
y
i
y
i
+
1
−
y
i
\mathcal{S}_{i}=\frac{y_{i+1}-y}{y_{i+1}-y_{i}}, \mathcal{S}_{i+1}=\frac{y-y_{i}}{y_{i+1}-y_{i}}
Si=yi+1−yiyi+1−y,Si+1=yi+1−yiy−yi
y
^
=
∑
j
=
0
n
P
(
y
j
)
y
j
=
S
i
y
i
+
S
i
+
1
y
i
+
1
=
y
i
+
1
−
y
y
i
+
1
−
y
i
y
i
+
y
−
y
i
y
i
+
1
−
y
i
y
i
+
1
=
y
\hat{y}=\sum_{j=0}^{n} P\left(y_{j}\right) y_{j}=\mathcal{S}_{i} y_{i}+\mathcal{S}_{i+1} y_{i+1}=\frac{y_{i+1}-y}{y_{i+1}-y_{i}} y_{i}+\frac{y-y_{i}}{y_{i+1}-y_{i}} y_{i+1}=y
y^=j=0∑nP(yj)yj=Siyi+Si+1yi+1=yi+1−yiyi+1−yyi+yi+1−yiy−yiyi+1=y
下面是mmdetection/mmdet/models/losses/gfocal_loss.py中DFL的部分,输入模型的预测(pred)和标签(label),其中pred的大小为batc_size×(n+1),代码中默认把上述的
y
0
y_0
y0和
y
n
y_n
yn分别设为0和16(
y
n
y_n
yn可以自己输入)。
dis_left = label.long()
dis_right = dis_left + 1
weight_left = dis_right.float() - label
weight_right = label - dis_left.float()
loss = F.cross_entropy(pred, dis_left, reduction='none') * weight_left \
+ F.cross_entropy(pred, dis_right, reduction='none') * weight_right
Generalized Focal Loss(GFL):
QFL和DFL可以看成同一个形式(GFL)的两个不同特例,不仅QFL和DFL,FL也是GFL的一个特例。GFL为:
G
F
L
(
p
y
l
,
p
y
r
)
=
−
∣
y
−
(
y
l
p
y
l
+
y
r
p
y
r
)
∣
β
(
(
y
r
−
y
)
log
(
p
y
l
)
+
(
y
−
y
l
)
log
(
p
y
r
)
)
\mathbf{G F L}\left(p_{y_{l}}, p_{y_{r}}\right)=-\left|y-\left(y_{l} p_{y_{l}}+y_{r} p_{y_{r}}\right)\right|^{\beta}\left(\left(y_{r}-y\right) \log \left(p_{y_{l}}\right)+\left(y-y_{l}\right) \log \left(p_{y_{r}}\right)\right)
GFL(pyl,pyr)=−∣y−(ylpyl+yrpyr)∣β((yr−y)log(pyl)+(y−yl)log(pyr))
训练
训练时的一些配置可以去原文中查看,这里就只讲一下最终的损失函数。采用GFL训练检测器时,整体的损失函数为:
L
=
1
N
p
o
s
∑
z
L
Q
+
1
N
p
o
s
∑
z
1
{
c
z
∗
>
0
}
(
λ
0
L
B
+
λ
1
L
D
)
\mathcal{L}=\frac{1}{N_{p o s}} \sum_{z} \mathcal{L}_{\mathcal{Q}}+\frac{1}{N_{p o s}} \sum_{z} \mathbf{1}_{\left\{c_{z}^{*}>0\right\}}\left(\lambda_{0} \mathcal{L}_{\mathcal{B}}+\lambda_{1} \mathcal{L}_{\mathcal{D}}\right)
L=Npos1z∑LQ+Npos1z∑1{cz∗>0}(λ0LB+λ1LD)
其中,
L
Q
\mathcal{L}_\mathcal{Q}
LQ是QFL,
L
D
\mathcal{L}_\mathcal{D}
LD是DFL。
L
B
\mathcal{L}_\mathcal{B}
LB是GIOU损失。
N
p
o
s
N_{pos}
Npos代表正样本的数量。
λ
0
\lambda_0
λ0为2,
λ
1
\lambda_1
λ1为0.25,用来平衡QFL和DFL。在金字塔特征图上的位置
z
z
z进行计算后再求和。
1
{
c
z
∗
>
0
}
\mathbf{1}_{\left\{c_{z}^{*}>0\right\}}
1{cz∗>0}是指示函数,当
c
z
∗
>
0
c_{z}^{*}>0
cz∗>0时,值为1,否则值为0。
实验
上表是将QFL和DFL用于ATSS做的对比实验,证明两种损失都是有效的,一起使用的,能提高更多的效果。
采用本文提出的结构和损害函数的检测器与其他知名检测器的一个对比。
Generalized Focal Loss v2
在GFLv1中,通过可视化网络输出的分布,作者画了一张图,也就是上面的冲浪板和大象的那张图。再加上GFLv2论文里的图。
我们不难看出,清晰的边界,其可视化后的分布都很尖锐,而那些很模糊的边界(比如被海遮住的冲浪板,被人遮住的伞柄等等)的分布就较为平缓,甚至会出现双峰现象。在GFLv1中,这个学到的分布并没有排上用场,于是作者便思考,是否可以用能够表达分布形状的统计量去指导最终定位质量的估计,这就是GFLv2的一大出发点。
方法
先放一张论文中的v2整体结构。
Decomposed Classification-IoU Representation: 在GFLv1中,作者已将分类和质量估计模块融合在了一起,使得训练和推理时是一致的。然而,为了预测这个联合结果,GFLv1只使用了分类分支的信息,显而易见这是不够的,所以,作者在GFLv2中,同时利用分类(
C
\mathbf{C}
C)分支和回归(
I
I
I)分支的信息来得到更好的联合估计。
J
=
C
×
I
\mathbf{J}=\mathbf{C} \times I
J=C×I其中,
C
=
[
C
1
,
C
2
,
…
,
C
m
]
,
C
i
∈
[
0
,
1
]
\mathbf{C}=\left[C_{1}, C_{2}, \ldots, C_{m}\right], C_{i} \in[0,1]
C=[C1,C2,…,Cm],Ci∈[0,1]是m个类别的分类表示,
I
I
I是一个标量,代表着回归分支的信息。作者设计了一个Distribution-Guided Quality Predictor(DGQP),将回归分支中的信息传给分类分支以形成联合估计,所以
J
\mathbf{J}
J也是可以采用QFL损失进行训练的。
Distribution-Guided Quality Predictor(DGQP): DGQP是GFLv2的关键所在,即为上图中红色框中所示。与GFLv1相同,GFLv2也是预测当前位置到边界的四个距离,用
{
l
,
r
,
t
,
b
}
\{l,r,t,b\}
{l,r,t,b}来表示。最终得到的离散概率即为
[
P
w
(
y
0
)
,
P
w
(
y
1
)
,
…
,
P
w
(
y
n
)
]
,
w
∈
{
l
,
r
,
t
,
b
}
\left[P^{w}\left(y_{0}\right), P^{w}\left(y_{1}\right), \ldots, P^{w}\left(y_{n}\right)\right],w \in\{l, r, t, b\}
[Pw(y0),Pw(y1),…,Pw(yn)],w∈{l,r,t,b}。
从之前的讨论中得知,得到的分布的平坦度与最终的bbox边界的质量与很高的关联度。那有一些可以反映分布平坦度的统计量,如果应用得到,就可以简化训练过程,提高最终bbox的质量。所以作者选取了回归分支输出的分布中的topk数据以及分布的均值,将他们简单拼接后,作为要传到分类分支的原始特征,
F
∈
R
4
(
k
+
1
)
\mathbf{F} \in \mathbb{R}^{4(k+1)}
F∈R4(k+1)。选择topk和均值有以下两个优势:(1)由于输出的分布总和为1,是不变的,所以topk和均值可以很好地反应分布的平坦度。值越大,越尖锐;值越小,越平坦;(2)topk和均值的鲁棒性比较强,对于不同尺度的目标,均能很好地反应其分布,就比如下图中左边的分布,大多聚集在1这边,说明点离边界的距离较近,而右边的分布说明点离边界较远,而这两个分布有着同样的均值和topk,都能反应出两个分布比较尖锐、比较清晰。
DGQP子网络由两层全连接层组成,每层全连接后接ReLU激活函数。最终的输出
I
I
I可以表示为:
I
=
F
(
F
)
=
σ
(
W
2
δ
(
W
1
F
)
)
I=\mathcal{F}(\mathbf{F})=\sigma\left(\mathbf{W}_{2} \delta\left(\mathbf{W}_{1} \mathbf{F}\right)\right)
I=F(F)=σ(W2δ(W1F))
在作者挺的代码中,DGQP模块的构造如下:
reg_conf为DGQP子网络,stat为初始的topk和均值,stat通过DGQP后得到quality_score,最终的质量评估的得分由分类分支和输出乘以quality_score得到。
Complexity: DGQP模块是个轻量级的模块,仅带来了额外的几千参数量,与原有的检测模型相比,可以忽略不计。比如说对于一个使用了ResNet-50和FPN的检测模型,添加一个DGQP的模块只会多出~0.003%的参数量.
实验
上表是对比了采用分布的哪些统计量最为合适,最高的是选用topk和均值。
通过以上实验,选取了最合适的k和p。p是DGQP中全连接层的中间维度。
上图是对比实验,可以看出GFLv2的AP已经超过了50%,比GFLv1也要高。更为详细的数据可以去原文的表格中看。