目标检测 - Generalized Focal Loss基于one-stage检测器无cost涨点
改进的Focal Loss,优于RetinaNet,FCOS,ATSS等
flyfish
《Generalized Focal Loss: Learning Qualified and Distributed Bounding Boxes for Dense Object Detection》
作者实现的源码和预训练模型地址
MMDetection实现
什么问题
FCOS v1
FCOS v2
FCOS v2 改进 FCOS v1 有以下几个方面
FCOS v1(FCOS: Fully Convolutional One-Stage Object Detection)
FCOS v2(FCOS: A Simple and Strong Anchor-free Object Detector)
边框回归(bounding box regression)模块模块,模型的监督信息只有四个值
x、y、w、h (中心点坐标与宽高),
x1、y1、x2、y2(左上角点与右下角点坐标)
t、b、l、r (采样点到上下左右四条边的距离)。
损失函数,通常为Ln范数损失,如L1,L2,Smooth L1损失或者基于IoU的损失
这里坐标用的是t、b、l、r。v1的损失用的是IoU loss,v2版改成了GIoU loss
边框回归的loss是有权重的,v1正样本点的权重相等,v2版正样本点距离GT bbox中心越小,权重越大
v1版的正样本GT bbox内点(bbox = bounding box的简写)
v2版的正样本变成了一个更小的边框 GT bbox = center bbox=radius * stride
Center-ness的label v1版使用t、b、l、r计算,v2版使用IoU计算。
v1版的Center-ness是与Classification在一起的
v2版的Center-ness是与Regression在一起的
one-stage anchor-free 检测器三个基本要素的表现形式。
- classification 分类
- localization 边框定位
- quality estimation 质量估计
作者发现的问题
1、分类得分(classification score)和质量评估即centerness是各自独立训练,在推理时将分类得分和质量评估相乘然后作为NMS过滤的依据。即训练时两者无关,推理时两者有关,存在gap。
2、回归任务中,质量评估是只考虑正样本,很多负样本在训练过程中是没有监督信号,造成推理是一个未定义的行为即某些负样本不可控。
改进
作者的解决方案
QFL(Quality Focal Loss)的提出
Focal Loss是为one-stage的检测器的分类branch服务的,它支持0或者1离散类别的label。然而,作者需要一种联合表示能够兼顾分类score和质量评估score,这样可以保证training和test一致。对于分类-质量联合表示,label变成了0~1之间的连续值。对Focal Loss在连续label上的拓展形式就是QFL(Quality Focal Loss)这样既保证了Focal Loss的平衡正负、难易样本的特性,又支持连续数值的监督。
cls score和quality score是同一个变量.
DFL(Distribution Focal Loss)的提出
bbox预测只有四个输出值,对于每一个输出值等同于优化一个狄拉克分布,狄拉克分布(下面解释该分布)太严格,缺乏对不确定度的估计。
高斯分布将模型的预测值由4个变为8个,bbox每条边的均值与方差,方差代表了不确定性的程度。
KL散度就可以用高斯分布来拟合狄拉克分布。实际的数据所满足的概率分布是任意的,因此作者想到的是用一般概率分布来建模。真实的分布通常不会距离标注的位置太远,所以又加了个loss,希望网络能够快速地聚焦到标注位置附近的数值,使得他们概率尽可能大就是Distribution Focal Loss。
wiki对于Dirac delta的描述
Dirac delta 可以松散地认为是实线上的一个函数,除了原点是无穷大外,其他地方都是零。这里注意的是Dirac delta is not a function。这只是一个启发式的描述。Dirac delta不是传统意义上的函数,因为定义在实数上的函数都不具有这些性质。Dirac delta函数可以严格定义为分布(distribution )或度量(measure)。
δ
(
x
)
=
{
+
∞
,
x
=
0
0
,
x
≠
0
\delta(x)=\left\{\begin{array}{ll} +\infty, & x=0 \\ 0, & x \neq 0 \end{array}\right.
δ(x)={+∞,0,x=0x=0
并被约束以满足
∫
−
∞
∞
δ
(
x
)
d
x
=
1
\int_{-\infty}^{\infty} \delta(x) d x=1
∫−∞∞δ(x)dx=1
可以作为measure或者distribution。
代码实现
from sympy import DiracDelta, integrate,Symbol
import numpy as np
x = Symbol('x')
print(integrate(x*DiracDelta(x-1), (x, 0, 5.0)))
Dirac delta分布 图形表示
Generalized Focal Loss是怎么来的?
交叉熵-》Focal Loss-》Generalized Focal Loss
1. 交叉熵损失
二分类的交叉熵损失:
CE
(
p
,
y
)
=
{
−
log
(
p
)
if
y
=
1
−
log
(
1
−
p
)
otherwise
\text{CE}(p, y) = \begin{cases}-\log(p) \quad &\text{if}\quad y = 1\\ -\log(1-p) &\text{otherwise}\end{cases}
CE(p,y)={−log(p)−log(1−p)ify=1otherwise
重新整理下
p
t
=
{
p
if
y
=
1
1
−
p
otherwise
p_{\mathrm{t}}=\left\{\begin{array}{ll} p & \text { if } y=1 \\ 1-p & \text { otherwise } \end{array}\right.
pt={p1−p if y=1 otherwise
CE
(
p
,
y
)
=
−
log
(
p
t
)
\text{CE}(p, y) = -\log(p_t)
CE(p,y)=−log(pt)
加上权重的交叉熵损失
用参数
α
t
\alpha_t
αt来平衡,作为比较的baseline。
CE
(
p
t
)
=
−
α
t
log
(
p
t
)
\text{CE}(p_t) = -\alpha_t\log(p_t)
CE(pt)=−αtlog(pt)
2.Focal Loss
一个自适应调节的权重即Focal Loss。 γ = 2 \gamma=2 γ=2时能够获得最佳的效果提升。 FL ( p t ) = − ( 1 − p t ) γ log ( p t ) \text{FL}(p_t) = -(1-p_t)^\gamma\log(p_t) FL(pt)=−(1−pt)γlog(pt)
加入平衡因子
α
\alpha
α的focal loss变种
FL
(
p
t
)
=
−
α
t
(
1
−
p
t
)
γ
log
(
p
t
)
\text{FL}(p_t) = -{\alpha}_t(1-p_t)^\gamma\log(p_t)
FL(pt)=−αt(1−pt)γlog(pt)
α
\alpha
α取0.25,正样本要比负样本占比小,负例易分。
3.Quality Focal Loss (QFL)
改的自适应调节权重的Focal Loss(忽略
α
t
{\alpha}_t
αt)
FL
(
p
t
)
=
−
(
1
−
p
t
)
γ
log
(
p
t
)
\text{FL}(p_t) = -(1-p_t)^\gamma\log(p_t)
FL(pt)=−(1−pt)γlog(pt)
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(σ))
魔改步骤
由于Focal Loss仅支持离散标签,为了将其思想应用到分类与定位质量结合的连续标签,对其进行了扩展。
首先将交叉熵部分
−
l
o
g
(
p
t
)
-log(p_t)
−log(pt)扩展为完整形式
−
(
(
1
−
y
)
l
o
g
(
1
−
σ
)
+
y
l
o
g
(
σ
)
)
-((1-y)log(1-\sigma) + y\ log(\sigma))
−((1−y)log(1−σ)+y log(σ)),
其次将缩放因子
(
1
−
p
t
)
γ
(1-p_t)^{\gamma}
(1−pt)γ泛化为预测值
σ
\sigma
σ与连续标签
y
y
y的绝对差值
∣
y
−
σ
∣
β
|y-\sigma|^{\beta}
∣y−σ∣β,
将其组合得到QFL:
得到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(σ))
σ
=
y
\sigma=y
σ=y为QFL的全局最小解。
QFL的代码实现
def quality_focal_loss(pred, target, beta=2.0):
r"""Quality Focal Loss (QFL) is from `Generalized Focal Loss: Learning
Qualified and Distributed Bounding Boxes for Dense Object Detection
<https://arxiv.org/abs/2006.04388>`_.
Args:
pred (torch.Tensor): Predicted joint representation of classification
and quality (IoU) estimation with shape (N, C), C is the number of
classes.
target (tuple([torch.Tensor])): Target category label with shape (N,)
and target quality label with shape (N,).
beta (float): The beta parameter for calculating the modulating factor.
Defaults to 2.0.
Returns:
torch.Tensor: Loss tensor with shape (N,).
"""
assert len(target) == 2, """target for QFL must be a tuple of two elements,
including category label and quality label, respectively"""
# label denotes the category id, score denotes the quality score
label, score = target
# 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 = torch.nonzero((label >= 0) & (label < bg_class_ind), as_tuple=False).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)
return loss
回归的目标是当前位置到目标边界的距离。常规的方法将回归目标y建模为Dirac delta分布,Dirac delta分布
δ
(
x
−
y
)
\delta(x-y)
δ(x−y)
满足
∫
−
∞
+
∞
δ
(
x
−
y
)
d
x
=
1
\int^{+\infty}_{-\infty}\delta(x-y)dx=1
∫−∞+∞δ(x−y)dx=1
,可通过积分的形式求得标签y:
y
=
∫
−
∞
+
∞
δ
(
x
−
y
)
x
d
x
y=\int_{-\infty}^{+\infty} \delta(x-y) x \mathrm{~d} x
y=∫−∞+∞δ(x−y)x dx
4.Distribution Focal Loss (DFL).
作者用general分布P(x)没有其他先验替代原来的Dirac delta或者 Gaussian。
给定标签y的取值范围
[
y
0
,
y
n
]
[y_0, y_n]
[y0,yn],
为了与神经网络兼容,将连续区域[y_0, y_n]的积分变为离散域
{
y
0
,
y
1
,
⋯
,
y
i
,
y
i
+
1
,
⋯
,
y
n
−
1
,
y
n
}
\{y_0, y_1, \cdots, y_i, y_{i+1}, \cdots, y_{n-1}, y_n \}
{y0,y1,⋯,yi,yi+1,⋯,yn−1,yn}的积分,离散区域的间隔
Δ
=
1
\Delta=1
Δ=1,预测值
y
^
\hat{y}
y^可表示为:
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
P(x)可通过softmax操作 S ( ⋅ ) \mathcal{S}(\cdot) S(⋅)获得,标记为 S i \mathcal{S}_i Si,预测值 y ^ \hat{y} y^可使用常规的方法进行后续的学习,比如Smooth L1、IoU loss或者GIoU Loss。
同一个积分结果y可由多种不同分布所得,会降低网络学习的效率。考虑到更多的分布应该集中于回归目标y的附近,正如前面所说真实的分布通常不会距离标注的位置太远,所以又加了个loss,希望网络能够快速地聚焦到标注位置附近的数值,使得他们概率尽可能大。DFL可以强制网络提高最接近y的
y
i
y_i
yi和
y
i
+
1
y_{i+1}
yi+1的概率,所以DFL的作用是在概率shape上,用于提高学习更合理概率分布的效率。由于回归预测不涉及正负样本不平衡的问题,只针对正样本,所以DFL仅需要交叉熵部分.DFL中的
P
(
x
)
P(x)
P(x)可以通过一个含n+1个单元的softmax层来实现,它是离散化的概率分布,求和为1,所以可以用softmax实现。
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))
DFL代码实现
@weighted_loss
def distribution_focal_loss(pred, label):
r"""Distribution Focal Loss (DFL) is from `Generalized Focal Loss: Learning
Qualified and Distributed Bounding Boxes for Dense Object Detection
<https://arxiv.org/abs/2006.04388>`_.
Args:
pred (torch.Tensor): Predicted general distribution of bounding boxes
(before softmax) with shape (N, n+1), n is the max value of the
integral set `{0, ..., n}` in paper.
label (torch.Tensor): Target distance label for bounding boxes with
shape (N,).
Returns:
torch.Tensor: Loss tensor with shape (N,).
"""
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
return loss
所以从交叉熵的角度来看DFL这个loss函数形式的最优解就是label。
5. QFL和DFL合并
QFL和DFL可以合并成一个式子,统一地表示为GFL也就是论文的题目Generalized Focal Loss。