[论文解读] AP-Loss for Accurate One-Stage Object Detection

文章内容

  • 论文贡献
  • 相关研究现状
    • 正负样本不平衡问题
    • AP 作为损失函数的应用
    • 感知学习算法
  • 本文工作
    • 核心工作1:ranking procedure
      • ranking label
      • AP Loss
    • 核心工作2:error-driven optimization algorithm
    • 其他细节
      • 小批量训练的分数聚拢
      • 分段阶跃函数
      • 插值AP
      • 减少复杂度,加速训练
  • 代码解读

论文链接:AP-Loss for Accurate One-Stage Object Detection
mmdet实现代码:AP-Loss for Accurate One-Stage Object Detection

论文贡献

  1. 基于排序任务实现分类任务,解决正负样本不平衡问题
  2. 提出一种新的优化算法,将感知器学习中的误差驱动更新机制与深度网络中的反向传播算法相结合,解决排序任务的不可微问题(且不可分解)和非凸性

相关研究现状

有很多工作对检测器进行简单的改进以缓解正负样本不平衡的问题,如新的加权方案Focal Loss,新的采样方案OHEM等。这些工作都没有考虑不同样本之间的分布关系,即没有对所有样本之间的关系建模的能力;此外,这些改进方案中的超参数对不同网络/数据集的泛化性能较差

正负样本不平衡问题

单阶段检测器的性能很大程度上得益于密集分布的锚框,这导致了前景/背景样本之间的极端不平衡。当前主要工作罗列如下
OHEM:在每个iteration中只选取前k个困难样本进行损失计算和反向传播
Focal Loss:为交叉熵损失添加额外的权重(对于正负样本添加常量因子,对于难易样本添加多项式因子)
A-Fast-RCNN:改进了困难样本挖掘技术,即通过对抗学习生成高质量的困难正样本
GHM:提出一种基于样本贡献平滑梯度贡献的梯度协调机制(和Focal Loss对简单样本的处理方式相仿)
Libra RCNN:从样本、特征、目标这三个角度研究不平滑问题,并分别提出解决方案

AP 作为损失函数的应用

本文相对于其他已有工作的优势如下

  • 本文提出的损失函数可用于所有线性/非线性、可微/不可微模型,而很多工作局限于线性SVM模型
  • 本文直接优化AP Loss且不会引入显著的loss gap
  • 现有工作利用期望函数和包络函数分别逼近原目标函数得到光滑的、容易逼近的曲线,但AP loss的非凸性依然会降低梯度下降的效率;而本文不对梯度进行近似,因此不会受到目标函数非凸性的影响
  • 本文可用于端到端的检测器训练,而非将AP优化过程建立在逐步训练分类的基础上

感知学习算法

本文优化算法的核心——误差驱动更新,来源于感知学习算法,它能够克服不可微的目标函数优化问题。感知学习算法就是一个用Heaviside阶跃函数作为激活函数的简单人工神经元,由于阶跃函数不可微,故梯度下降算法不可用,而是采用一种误差驱动更新方法直接对神经元的权重进行改动。如果训练数据是线性可分的,则该算法保证在有限步内收敛,目前已有很多工作在研究改进感知学习算法的稳定性和鲁棒性。

本文工作

本文工作都在分类分支上进行,没有改变模型backbone和定位分支。
[论文解读] AP-Loss for Accurate One-Stage Object Detection_第1张图片

核心工作1:ranking procedure

ranking label

传统检测器会根据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相仿,用二进制标签完成多类别目标检测任务。
[论文解读] AP-Loss for Accurate One-Stage Object Detection_第2张图片

AP Loss

[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,θ))=(sisj),其中 θ \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=1AP=1P1iPrank(i)rank+(i)=1P1iP1+jP,j=iH(xij)+jNH(xij)1+jP,j=iH(xij)=P1iPjN1+kPN,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={iti=1},N={iti=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=iPjN1+kPN,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=P1iPjNLij=P1i,jLijyij=P1L(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(θ)=1AP(θ)=P1L(x(θ)),y
AP Loss的两种理解

  1. 正负样本之间的损失 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=P1iPjNLij=P1iP1+kPN,k=iH(xik)jNH(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越大。

  2. 平均精度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=1AP=1P1iPrank(i)rank+(i)=P1iP1+kPN,k=iH(xik)jNH(xij)
    其中平均精度AP为正负样本间的排名损失/总排名损失(定值)

由上述两种定义可以发现, L i j L_{ij} Lij只考虑了正负样本之间的关系,没有对正样本集合内部的关系建模,这个问题在RS Loss中得到解决。

HighLight

  • 采用排序任务解决分类问题,其中排序任务可以显式建模样本之间的关系,降低对正负样本比例的敏感程度,解决正负样本不平衡问题。
    [论文解读] AP-Loss for Accurate One-Stage Object Detection_第3张图片

  • AP Loss的计算是对所有类别的排序结果进行计算,与AP评价指标的分类别计算略有不同。

  • 考虑到AP(average precision)能够同时反映精度和召回率,且与目标检测器的评价指标一致,故在此采用AP作为损失值而非AUC-Loss等其他实现。

  • AP Loss的计算过程中, L i j L_{ij} Lij不可微,无法使用标准的SGD反向传播算法优化网络,因此有基于误差驱动的网络优化算法,具体见核心工作2.

核心工作2:error-driven optimization algorithm

这里的主要任务是计算 ∂ L A P ∂ s i \frac{\partial L^{AP}}{\partial s_i} siLAP,进而从 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=LijLij。当 ⟨ 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=Lijyij

上述标红的三个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=P1siLAP=P1j,kxj,kLAPsixj,k=P1j,kΔxjksixjk=P1(jΔxijjΔxji)=P1(jLjiyjijLijyij)

由前文可知,分差 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>δ
[论文解读] AP-Loss for Accurate One-Stage Object Detection_第4张图片

插值AP

本文对 L i j L_{ij} Lij进行插值,使第 k k k个最小正样本的精度 ( 1 − ∑ j ∈ N L i j ) (1-\sum_{j\in N}L_{ij}) (1jNLij) k k k单调递增。插值AP作为AP的平滑近似能够稳定梯度并减少更新信号摆动的影响。

减少复杂度,加速训练

由于AP Loss需要计算成对anchors的得分差,因此其计算复杂度 O ( ( ∣ P ∣ + ∣ N ∣ ) 2 ) O((|P|+|N|)^2) O((P+N)2)比其他的分类损失更高,这对于大规模训练任务来说很致命。

  • 方法1:由于只需要计算 i ∈ P , j ∈ N i\in P,j\in N iP,jN时的 L i j L_{ij} Lij,可以只对正样本的下标形成循环回路,节省其他情况下的计算时间和过程变量占用内存。且由于大多数情况下 ∣ N ∣ ≫ ∣ P ∣ |N|\gg|P| NP,因此该策略能将计算复杂度减小至 O ( ∣ P ∣ ⋅ ∣ N ∣ ) O(|P|·|N|) O(PN)
  • 方法2:如果一个负样本 j j j对于所有正样本 i i i都有 x i j ≤ − δ x_{ij}\le-\delta xijδ,则对于该负样本来说 H ( x i j ) = = 0 H(x_{ij})==0 H(xij)==0,它对于AP Loss的贡献可忽略不计,因此在训练过程中可以忽略此类样本:找到正样本中的最小得分 s m i n s_{min} smin后令所有得分大于 s m i n − δ s_{min}-\delta sminδ的负样本构成一个新的负样本集合 N ^ \hat{N} N^。这一方法在训练初期效果不明显,但随着训练的推进它将大大缩小负样本的数量,进而减小计算复杂度,提高训练速度。

[论文解读] AP-Loss for Accurate One-Stage Object Detection_第5张图片

代码解读

该类输出一个新定义的排序损失 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=P1(1precision),与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+=P1rank(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

你可能感兴趣的:(目标检测,深度学习,神经网络,计算机视觉,卷积神经网络)