论文链接:AP-Loss for Accurate One-Stage Object Detection
mmdet实现代码:AP-Loss for Accurate One-Stage Object Detection
有很多工作对检测器进行简单的改进以缓解正负样本不平衡的问题,如新的加权方案Focal Loss,新的采样方案OHEM等。这些工作都没有考虑不同样本之间的分布关系,即没有对所有样本之间的关系建模的能力;此外,这些改进方案中的超参数对不同网络/数据集的泛化性能较差。
单阶段检测器的性能很大程度上得益于密集分布的锚框,这导致了前景/背景样本之间的极端不平衡。当前主要工作罗列如下
OHEM:在每个iteration中只选取前k个困难样本进行损失计算和反向传播
Focal Loss:为交叉熵损失添加额外的权重(对于正负样本添加常量因子,对于难易样本添加多项式因子)
A-Fast-RCNN:改进了困难样本挖掘技术,即通过对抗学习生成高质量的困难正样本
GHM:提出一种基于样本贡献平滑梯度贡献的梯度协调机制(和Focal Loss对简单样本的处理方式相仿)
Libra RCNN:从样本、特征、目标这三个角度研究不平滑问题,并分别提出解决方案
本文相对于其他已有工作的优势如下
本文优化算法的核心——误差驱动更新,来源于感知学习算法,它能够克服不可微的目标函数优化问题。感知学习算法就是一个用Heaviside阶跃函数作为激活函数的简单人工神经元,由于阶跃函数不可微,故梯度下降算法不可用,而是采用一种误差驱动更新方法直接对神经元的权重进行改动。如果训练数据是线性可分的,则该算法保证在有限步内收敛,目前已有很多工作在研究改进感知学习算法的稳定性和鲁棒性。
本文工作都在分类分支上进行,没有改变模型backbone和定位分支。
传统检测器会根据IoU对每个anchor输出一个分数向量 ( s 0 , . . . , s K ) (s^0,...,s^K) (s0,...,sK),其中1~K代表K个类别标签,0表示背景。而本文将每个anchor复制K份,第k个anchor根据同样的IoU值得到输出标签 t k ∈ { − 1 , 0 , 1 } t^k \in \{-1,0,1\} tk∈{−1,0,1},其中-1代表忽略。该思路与Retinanet相仿,用二进制标签完成多类别目标检测任务。
[Step 1] 首先计算anchor对之间的差异值 x i j = − ( s ( b i , θ ) − s ( b j , θ ) ) = − ( s i − s j ) x_{ij}=-(s(b_i, \theta)-s(b_j, \theta))=-(s_i-s_j) xij=−(s(bi,θ)−s(bj,θ))=−(si−sj),其中 θ \theta θ是神经网络的参数, s ( b i , θ ) s(b_i, \theta) s(bi,θ)是一个基于神经网络对锚框评估得分的函数。
[Step 2] 使用 x i j x_{ij} xij对每对anchors的AP Loss进行计算:
L A P = 1 − A P = 1 − 1 ∣ P ∣ ∑ i ∈ P r a n k + ( i ) r a n k ( i ) = 1 − 1 ∣ P ∣ ∑ i ∈ P 1 + ∑ j ∈ P , j ≠ i H ( x i j ) 1 + ∑ j ∈ P , j ≠ i H ( x i j ) + ∑ j ∈ N H ( x i j ) = 1 ∣ P ∣ ∑ i ∈ P ∑ j ∈ N H ( x i j ) 1 + ∑ k ∈ P ∪ N , k ≠ i H ( x i k ) \begin{aligned} L_{AP}&=1-AP=1-\frac{1}{|P|}\sum_{i\in P}\frac{rank^+(i)}{rank(i)} \\&=1-\frac{1}{|P|}\sum_{i\in P}\frac{1+\sum_{j\in P, j\neq i}H(x_{ij})}{1+\sum_{j\in P, j\neq i}H(x_{ij})+\sum_{j\in N}H(x_{ij})} \\&=\frac{1}{|P|}\sum_{i\in P}\sum_{j\in N}\frac{H(x_{ij})}{1+\sum_{k\in P\cup N, k\neq i}H(x_{ik})} \end{aligned} LAP=1−AP=1−∣P∣1i∈P∑rank(i)rank+(i)=1−∣P∣1i∈P∑1+∑j∈P,j=iH(xij)+∑j∈NH(xij)1+∑j∈P,j=iH(xij)=∣P∣1i∈P∑j∈N∑1+∑k∈P∪N,k=iH(xik)H(xij)
其中 r a n k ( i ) rank(i) rank(i)和 r a n k + i rank^+{i} rank+i分别表示第i个anchor在全部样本和正样本中的排名;P和N分别表示正负样本集合,即 P = { i ∣ t i = 1 } , N = { i ∣ t i = 0 } P=\{i|t_i=1\}, N=\{i|t_i=0\} P={i∣ti=1},N={i∣ti=0}。
令 L i j = ∑ i ∈ P ∑ j ∈ N H ( x i j ) 1 + ∑ k ∈ P ∪ N , k ≠ i H ( x i k ) L_{ij}=\sum_{i\in P}\sum_{j\in N}\frac{H(x_{ij})}{1+\sum_{k\in P\cup N, k\neq i}H(x_{ik})} Lij=∑i∈P∑j∈N1+∑k∈P∪N,k=iH(xik)H(xij),并定义 y i j = { 1 t i = 1 , t j = 0 0 e l s e y_{ij}=\begin{cases} 1& t_i=1, t_j=0\\ 0& else \end{cases} yij={10ti=1,tj=0else
[Step 3] 则总体 AP Loss 归一化表示如下:
L A P = 1 ∣ P ∣ ∑ i ∈ P ∑ j ∈ N L i j = 1 ∣ P ∣ ∑ i , j L i j ⋅ y i j = 1 ∣ P ∣ ⟨ L ( x ) , y ⟩ L_{AP}=\frac{1}{|P|}\sum_{i\in P}\sum_{j\in N}L_{ij}=\frac{1}{|P|}\sum_{i,j}L_{ij}·y_{ij}=\frac{1}{|P|}\langle L(x),y\rangle LAP=∣P∣1i∈P∑j∈N∑Lij=∣P∣1i,j∑Lij⋅yij=∣P∣1⟨L(x),y⟩
因此,网络优化问题可以被写为如下形式,其中 θ \theta θ代表检测器权重参数:
m i n θ L A P ( θ ) = 1 − A P ( θ ) = 1 ∣ P ∣ ⟨ L ( x ( θ ) ) , y ⟩ min_{\theta}L_{AP}(\theta)=1-AP(\theta)=\frac{1}{|P|}\langle L(x(\theta)),y\rangle minθLAP(θ)=1−AP(θ)=∣P∣1⟨L(x(θ)),y⟩
AP Loss的两种理解
正负样本之间的损失 L i j L_{ij} Lij之和
L A P = 1 ∣ P ∣ ∑ i ∈ P ∑ j ∈ N L i j = 1 ∣ P ∣ ∑ i ∈ P ∑ j ∈ N H ( x i j ) 1 + ∑ k ∈ P ∪ N , k ≠ i H ( x i k ) L_{AP}=\frac{1}{|P|}\sum_{i\in P}\sum_{j\in N}L_{ij}=\frac{1}{|P|}\sum_{i\in P}\frac{\sum_{\color{red} {j\in N}}H(x_{ij})}{1+\sum_{k\in P\cup N,k\neq i}H(x_{ik})} LAP=∣P∣1i∈P∑j∈N∑Lij=∣P∣1i∈P∑1+∑k∈P∪N,k=iH(xik)∑j∈NH(xij)
L i j L_{ij} Lij分子表示正负样本 i , j i,j i,j之间的排名损失,如果负样本 j j j得分高于正样本 i i i, H = 1 H=1 H=1,否则为0; L i j L_{ij} Lij分母表示样本 i i i在所有样本中的正确排名,对于指定 i i i来说是定值。即得分高于正样本 i i i的负样本越多, L A P L_{AP} LAP越大。
平均精度AP关于1的补数
L A P = 1 − A P = 1 − 1 ∣ P ∣ ∑ i ∈ P r a n k + ( i ) r a n k ( i ) = 1 ∣ P ∣ ∑ i ∈ P ∑ j ∈ N H ( x i j ) 1 + ∑ k ∈ P ∪ N , k ≠ i H ( x i k ) L_{AP}=1-AP=1-\frac{1}{|P|}\sum_{i\in P}\frac{rank^+(i)}{rank(i)}=\frac{1}{|P|}\sum_{i\in P}\frac{\sum_{\color{red}{j\in N}}H(x_{ij})}{1+\sum_{k\in P\cup N, k\neq i}H(x_{ik})} LAP=1−AP=1−∣P∣1i∈P∑rank(i)rank+(i)=∣P∣1i∈P∑1+∑k∈P∪N,k=iH(xik)∑j∈NH(xij)
其中平均精度AP为正负样本间的排名损失/总排名损失(定值)
由上述两种定义可以发现, L i j L_{ij} Lij只考虑了正负样本之间的关系,没有对正样本集合内部的关系建模,这个问题在RS Loss中得到解决。
HighLight:
采用排序任务解决分类问题,其中排序任务可以显式建模样本之间的关系,降低对正负样本比例的敏感程度,解决正负样本不平衡问题。
AP Loss的计算是对所有类别的排序结果进行计算,与AP评价指标的分类别计算略有不同。
考虑到AP(average precision)能够同时反映精度和召回率,且与目标检测器的评价指标一致,故在此采用AP作为损失值而非AUC-Loss等其他实现。
AP Loss的计算过程中, L i j L_{ij} Lij不可微,无法使用标准的SGD反向传播算法优化网络,因此有基于误差驱动的网络优化算法,具体见核心工作2.
这里的主要任务是计算 ∂ L A P ∂ s i \frac{\partial L^{AP}}{\partial s_i} ∂si∂LAP,进而从 s i s_i si出发对网络参数 θ \theta θ进行反向传播。
对于 Δ x i j \Delta x_{ij} Δxij的计算,引入感知器中的误差驱动算法求解。定义近似更新规则,将 x i j x_{ij} xij看作输入, L i j L_{ij} Lij看作输出,理想输出为 L i j ∗ L^*_{ij} Lij∗,定义 Δ x i j = L i j ∗ − L i j \Delta x_{ij}=L^*_{ij}-L_{ij} Δxij=Lij∗−Lij。当 ⟨ L , y ⟩ = 0 \langle L,y\rangle=0 ⟨L,y⟩=0时AP Loss有最小值,因此当 y i j = 1 y_{ij}=1 yij=1时 L i j ∗ = 0 L^*_{ij}=0 Lij∗=0, y i j = 0 y_{ij}=0 yij=0时 L i j L_{ij} Lij不会对AP Loss产生影响,因此理想更新值为 Δ x i j = − L i j ⋅ y i j \Delta x_{ij}=-L_{ij}·y_{ij} Δxij=−Lij⋅yij。
上述标红的三个AP Loss计算步骤中第一步和第三步不可微,即损失基本项 L i j L_{ij} Lij不可微。根据链式法则可以求出得分 s i s_i si的反向传播梯度 g i g_i gi为
g i = − 1 ∣ P ∣ ∂ L A P ∂ s i = − 1 ∣ P ∣ ∑ j , k ∂ L A P ∂ x j , k ∂ x j , k ∂ s i = 1 ∣ P ∣ ∑ j , k Δ x j k ⋅ ∂ x j k ∂ s i = 1 ∣ P ∣ ( ∑ j Δ x i j − ∑ j Δ x j i ) = 1 ∣ P ∣ ( ∑ j L j i ⋅ y j i − ∑ j L i j ⋅ y i j ) \begin{aligned} g_i=-\frac{1}{|P|}\frac{\partial L^{AP}}{\partial s_i}&=-\frac{1}{|P|}\sum_{j,k}\frac{\partial L^{AP}}{\partial x_{j,k}}\frac{\partial x_{j,k}}{\partial s_i} \\&=\frac{1}{|P|}\sum_{j,k}\Delta x_{jk}·\frac{\partial x_{jk}}{\partial s_i} \\&=\frac{1}{|P|}(\sum_j\Delta x_{ij}-\sum_j\Delta x_{ji}) \\&=\frac{1}{|P|}(\sum_j L_{ji}·y_{ji}-\sum_j L_{ij}·y_{ij}) \end{aligned} gi=−∣P∣1∂si∂LAP=−∣P∣1j,k∑∂xj,k∂LAP∂si∂xj,k=∣P∣1j,k∑Δxjk⋅∂si∂xjk=∣P∣1(j∑Δxij−j∑Δxji)=∣P∣1(j∑Lji⋅yji−j∑Lij⋅yij)
由前文可知,分差 x x x由成对的anchor和网络参数 θ \theta θ共同决定,而网络的训练目标就是不断逼近最合适的网络参数 θ \theta θ,因此需要寻找能产生最接近上述理想更新值 Δ x \Delta x Δx的的模型参数更新值 Δ θ \Delta\theta Δθ。在此用点乘衡量参数更新与理想更新的相似度,并为网络参数增加一个L2正则化项,该优化过程表示如下:
a r g m i n Δ θ { − ⟨ Δ x , x ( θ ( n ) + Δ θ ) − x ( θ ( n ) ) ⟩ + λ ∣ ∣ Δ θ ∣ ∣ 2 2 } arg min_{\Delta\theta}\{-\langle\Delta x,x(\theta^{(n)}+\Delta\theta)-x(\theta^{(n)})\rangle+\lambda||\Delta\theta||_2^2\} argminΔθ{−⟨Δx,x(θ(n)+Δθ)−x(θ(n))⟩+λ∣∣Δθ∣∣22}
θ \theta θ更新带来的 x x x变化(一阶)可表示如下
x ( θ ) = x ( θ ( n ) ) + ∂ x ( θ ( n ) ) ∂ θ ⋅ ( θ − θ ( n ) ) + o ( ∣ ∣ θ − θ ( n ) ∣ ∣ ) x(\theta)=x(\theta^{(n)})+\frac{\partial x(\theta^{(n)})}{\partial\theta}·(\theta-\theta^{(n)})+o(||\theta-\theta^{(n)}||) x(θ)=x(θ(n))+∂θ∂x(θ(n))⋅(θ−θ(n))+o(∣∣θ−θ(n)∣∣)
忽略高阶无穷小后代回上式,最佳网络权重更新步长为
θ ( n + 1 ) − θ ( n ) = a r g m i n Δ θ { − ⟨ Δ x , ∂ x ( θ ( n ) ) ∂ θ ∂ θ ⟩ + λ ∣ ∣ Δ θ ∣ ∣ 2 2 } \theta^{(n+1)}-\theta^{(n)}=argmin_{\Delta\theta}\{-\langle\Delta x,\frac{\partial x(\theta^{(n)})}{\partial\theta}\partial\theta\rangle+\lambda||\Delta\theta||_2^2\} θ(n+1)−θ(n)=argminΔθ{−⟨Δx,∂θ∂x(θ(n))∂θ⟩+λ∣∣Δθ∣∣22}
由此得到最优化更新解
θ ( n + 1 ) = θ ( n ) + 1 2 λ ( ∂ x ( θ ( n ) ) ∂ θ ) T Δ x \theta^{(n+1)}=\theta^{(n)}+\frac{1}{2\lambda}(\frac{\partial x(\theta^{(n)})}{\partial\theta})^T\Delta x θ(n+1)=θ(n)+2λ1(∂θ∂x(θ(n)))TΔx
在一个mini-batch中,若检测器对图像I1中样本的最高得分依然比图像I2中样本的最低得分低,即这两幅图之间出现了score-shift,检测器计算AP Loss时性能会很差。在小批量中对图像进行分数聚合(aggregating score)可以避免这一问题,因此小批量训练对于良好的收敛和良好的性能至关重要。
在训练初期,所有样本的得分 s i s_i si都很接近(在阶跃函数的跳变点附近),因此很小的输入变动都会造成结果产生较大的变化,网络更新的稳定性较差。因此将阶跃函数软化为如下分段函数(不局限于此,其他单调对称平滑函数也可以),其中参数 δ \delta δ的选择与权值衰减超参数密切相关,它直观地决定了正样本和负样本之间决策边界的宽度。
f ( x ) = { 0 x < − δ x 2 δ + 0.5 − δ ≤ x ≤ δ 1 x > δ f(x)=\begin{cases} 0& x<-\delta\\ \frac{x}{2\delta}+0.5 & -\delta\le x\le\delta \\ 1& x>\delta \end{cases} f(x)=⎩⎪⎨⎪⎧02δx+0.51x<−δ−δ≤x≤δx>δ
本文对 L i j L_{ij} Lij进行插值,使第 k k k个最小正样本的精度 ( 1 − ∑ j ∈ N L i j ) (1-\sum_{j\in N}L_{ij}) (1−∑j∈NLij)随 k k k单调递增。插值AP作为AP的平滑近似能够稳定梯度并减少更新信号摆动的影响。
由于AP Loss需要计算成对anchors的得分差,因此其计算复杂度 O ( ( ∣ P ∣ + ∣ N ∣ ) 2 ) O((|P|+|N|)^2) O((∣P∣+∣N∣)2)比其他的分类损失更高,这对于大规模训练任务来说很致命。
该类输出一个新定义的排序损失 c l a s s i f i c a t i o n _ g r a d s classification\_grads classification_grads作为反向传播的依据。
由于AP Loss只对正样本进行计算,并只着眼于正负样本之间的排序损失。因此,正样本的梯度根据该正样本 i i i计算得到, f g _ g r a d = − 1 ∣ P ∣ ( 1 − p r e c i s i o n ) fg\_grad=-\frac{1}{|P|}(1-precision) fg_grad=−∣P∣1(1−precision),与AP Loss的定义一致,其中 p r e c i s i o n precision precision是经过插值平滑的精度值;而负样本的梯度根据所有正样本计算平滑求和得到, r e l e v a n t _ b g _ g r a d + = 1 ∣ P ∣ ⋅ x i j r a n k ( i ) relevant\_bg\_grad+=\frac{1}{|P|}·\frac{x_{ij}}{rank(i)} relevant_bg_grad+=∣P∣1⋅rank(i)xij,即正负样本之间的差异值 x i j x_{ij} xij越大,该正样本正确的排序越小(样本置信度越高),该负样本的损失值越大。
具体代码如下:
class APLoss(torch.autograd.Function):
@staticmethod
def forward(ctx, logits, targets, delta=1.):
classification_grads = torch.zeros(logits.shape).cuda()
# ---------------------#
# Filter fg logits
# ---------------------#
fg_labels = (targets == 1)
fg_logits = logits[fg_labels]
fg_num = len(fg_logits)
rank = torch.zeros(fg_num).cuda()
prec = torch.zeros(fg_num).cuda()
fg_grad = torch.zeros(fg_num).cuda()
# --------------------------------------#
# Filter non-trivial negative samples
# --------------------------------------#
# Do not use bg with scores less than minimum fg logit since changing its score does not have an effect on precision
threshold_logit = torch.min(fg_logits) - delta
# Get valid bg logits
relevant_bg_labels = ((targets == 0) & (logits >= threshold_logit))
relevant_bg_logits = logits[relevant_bg_labels]
relevant_bg_grad = torch.zeros(len(relevant_bg_logits)).cuda()
# -----------------------------#
# Loop on posivite indices
# -----------------------------#
max_prec = 0
# sort the fg logits
order = torch.argsort(fg_logits)
# loop over each positive following the order
for ii in order:
# ---------------------------------------------------------#
# Compute the differences between fg and limit to [0,1]
# ---------------------------------------------------------#
# x_ij s as score differences with fgs
fg_relations = fg_logits - fg_logits[ii]
# Apply piecewise linear function and determine relations with fgs H(x_{ij})
fg_relations = torch.clamp(fg_relations/(2*delta)+0.5, min=0, max=1)
# Discard i=j in the summation in rank_pos
fg_relations[ii] = 0
# ------------------------------------------------------#
# Compute the differences with bg and limit to [0,1]
# ------------------------------------------------------#
# x_ij s as score differences with bgs
bg_relations = relevant_bg_logits - fg_logits[ii]
# Apply piecewise linear function and determine relations with bgs H(x_{ij})
bg_relations = torch.clamp(bg_relations/(2*delta)+0.5, min=0, max=1)
# Compute the rank of the example within fgs and number of bgs with larger scores (rank^+(i))
rank_pos = 1 + torch.sum(fg_relations)
FP_num = torch.sum(bg_relations)
# Store the total since it is normalizer also for aLRP Regression error (rank(i))
rank[ii] = rank_pos + FP_num
# Compute precision for this example (AP)
current_prec = rank_pos/rank[ii]
# Compute interpolated AP and store gradients for relevant bg examples
if max_prec <= current_prec:
max_prec = current_prec
relevant_bg_grad += (bg_relations/rank[ii])
else:
relevant_bg_grad += (bg_relations/rank[ii]) * ((1-max_prec)/(1-current_prec))
# Store fg gradients with interpolated AP
fg_grad[ii] = -(1 - max_prec)
# Store precision for calculating average-precision
prec[ii] = max_prec
# aLRP with grad formulation
classification_grads[fg_labels] = fg_grad
classification_grads[relevant_bg_labels] = relevant_bg_grad
classification_grads /= fg_num
# L_{AP} = 1 - AP
cls_loss = 1 - prec.mean()
ctx.save_for_backward(classification_grads)
return cls_loss
@staticmethod
def backward(ctx, out_grad1):
g1, = ctx.saved_tensors
return g1*out_grad1, None, None