目标检测 RetinaNet 算法

1. 概述

YOLO v1[1] 的提出,验证了 one-stage 的目标检测算法的可行性,诸多因素(如只用了一个语义特征层、CNN 网络的性能以及对候选框的预测等等),最终导致 YOLO v1 相比较于 Faster R-CNN[2] 这样的 two-stage 算法的效果要差一些。在 YOLO v2[3] 中借鉴了 Faster R-CNN 中初始锚框 Anchor 的设计,引入了先验框的概念,同时也在 CNN 网络中增加了优化、在候选框的预测上也尽量设计得让模型更容易预测,效果上得到了明显的提升。然而,在 one-stage 模式下,如在 YOLO v2 中,在语义特征层的每一个位置上都生成了大量的先验框,绝大部分的先验框都是负样本,正样本只占了很小的一部分,这样就导致了正负样本的不均衡。在 two-stage 中,得益于流程上的设计,正负样本不均衡的问题就不是那么严重。

正负样本的不均衡问题,严重影响到了目标检测算法的检测效果,2017 年提出的 RetinaNet[4] 算法就着眼于正负样本不均衡问题,模型结构与前面 one-stage 的 YOLO 差不了多少,重点是在训练的过程中使用了 Focal Loss,着眼于缓解正负样本不均衡问题。

2. 正负样本不均衡问题

抛开其他的影响因素和问题,我们来看一下在 one-stage 和 two-stage 的分类下,典型的算法为什么会出现正负样本不均衡的问题,同时,这些算法又是如何解决的。

2.1. one-stage

先看一下 one-stage,这里我们以 YOLO v1 为例。回顾下,在 YOLO v1 中[5],其具体的过程如下:

  1. 首先,对于原始图像(假设为 448×448×3448\times 448\times 3),经过一系列的卷积+池化,得到了多个通道的语义特征层(假设通道为 10241024),这个时候每个通道就被划分成了 S×SS\times S(假设每个通道为 7×77\times 7);
  2. 对于上述的 7×77\times 7 个格子,每个网格都要预测 BB 个 Bounding box,每个 Bounding box 要预测 (x,y,w,h)\left(x,y,w,h \right) 和是否存在目标的置信度 confidence,一共是 55 个值。除此之外,每个网格还要预测一个类别信息,记为 CC 个类,网络输出就是一个 S×S×(5×B+C)S\times S\times \left (5\times B+C \right ) 的张量。在文献[1]中,YOLO v1 把一张图片划分为了 7×77\times 7 个网格,并且每个网格预测 22 个 Bounding Box,2020 个类别,也就是 S=7,B=2,C=20S=7,B=2,C=20。在这种情况下,总共有 7×7×2=987\times 7\times 2=98 个 Bounding Box。以下图为例:

其中,正样本是 33 个,剩下的 98−3=9598-3=95 个都是负样本。那么在 YOLO v1 是如何解决这样的样本不均衡的问题的呢?答案藏在损失函数中,来看下 YOLO v1 的损失函数:

λcoord∑i=0S2∑j=0B1ijobj[(xi−x^i)2+(yi−y^i)2]+λcoord∑i=0S2∑j=0B1ijobj[(wi−w^i)2+(hi−h^i)2]+∑i=0S2∑j=0B1ijobj(Ci−C^i)2+λnoobj∑i=0S2∑j=0B1ijnoobj(Ci−C^i)2+∑i=0S21iobj∑c∈classes(pi(c)−p^i(c))2\lambda _{coord}\sum_{i=0}^{S^2}\sum _{j=0}^{B}\mathbb{1}_{ij}^{obj}\left [ \left ( x_i-\hat{x}_i \right )^2+\left ( y_i-\hat{y}_i \right )^2 \right ]\\ +\lambda _{coord}\sum_{i=0}^{S^2}\sum _{j=0}^{B}\mathbb{1}_{ij}^{obj}\left [ \left ( \sqrt{w_i}-\sqrt{\hat{w}_i} \right )^2+\left ( \sqrt{h_i}-\sqrt{\hat{h}_i} \right )^2\right ]\\ +\sum_{i=0}^{S^2}\sum _{j=0}^{B}\mathbb{1}_{ij}^{obj}\left ( C_i-\hat{C}_i \right )^2\\ +\lambda _{noobj}\sum_{i=0}^{S^2}\sum _{j=0}^{B}\mathbb{1}_{ij}^{noobj}\left ( C_i-\hat{C}_i \right )^2\\ +\sum_{i=0}^{S^2}\mathbb{1}_{i}^{obj}\sum_{c\in classes}\left ( p_i\left ( c \right )-\hat{p}_i\left ( c \right ) \right )^2

其中,对于正负样本有影响的是分类的损失:

∑i=0S2∑j=0B1ijobj(Ci−C^i)2+λnoobj∑i=0S2∑j=0B1ijnoobj(Ci−C^i)2\sum_{i=0}^{S^2}\sum _{j=0}^{B}\mathbb{1}_{ij}^{obj}\left ( C_i-\hat{C}_i \right )^2 +\lambda _{noobj}\sum_{i=0}^{S^2}\sum _{j=0}^{B}\mathbb{1}_{ij}^{noobj}\left ( C_i-\hat{C}_i \right )^2

加号前面那部分代表的是正样本,加号后面那部分代表的是负样本,如果两者的权重一样的话,那么大量负样本的 loss 就会很容易淹没少量正样本的 loss,因此在 YOLO v1 中,在负样本的损失前面增加了权重 λnoobj=0.5\lambda _{noobj}=0.5,以此来降低负样本的损失对整个损失函数的影响。

##2.2. two-stage
在 two-stage 算法中,最典型的算法是 Faster R-CNN。Faster R-CNN 算法的整个流程会被分成多个阶段,第一阶段是区域候选网络 RPN。RPN 的主要任务是生成可能存在目标的候选框,为后续的流程起到了负样本过滤的作用,这两者之间的关系如下图所示:

接下来,我们分别来看这两个过程。

首先是区域候选网络 RPN,其作用是为后续的 detector 提供 Proposals,RPN 网络的输入是 Anchor,在 Faster R-CNN 中的 Anchor 首先是在特征图的每一个位置 cell,以该 cell 的中心,映射回原图,在原图上以一定的宽高,生成初始的 Anchor,在参考文献[2]中,每个位置生成99个 Anchor,这个的具体过程如下图所示:

有了这些 Anchor 后,RPN 网络需要对 Anchor 做分类和回归,以生成接下来使用的 Proposals,这里就涉及到第一个正负样本的均衡,也就是 Anchor 的正负样本如何均衡。在此有一种分类正负样本的方法:

  • Anchor 与 Ground Truth 之间的 IoU 大于等于 0.70.7 为正样本,也就是有目标
  • Anchor 与 Ground Truth 之间的 IoU 小于等于 0.30.3 为负样本,也就是无目标,是背景

这其中,0.3<IoU<0.70.3<\text{IoU}<0.7 则不参与 RPN 中 loss 的计算,这在一定程度上减少了负样本,但是这样依然还是会有很多的负样本,Faster R-CNN 中采用的方法是采样 Sampling,正负样本按照一定的比例在 Batch 内采样。

在 RPN 产生了 Proposals 后,哪些 Proposal 应该送入到后续的分类和回归中呢?当分类的阈值低于指定的值 threshold 后,这些都会被丢弃。有了 Proposals 后,进入第二次的正负样本不均衡问题,因为真正有用的目标其实相较于背景来说还是很少的。这时候区分正负样本的规则可以如下:

  • Proposal 与 Ground Truth 之间的 IoU 大于等于 0.50.5 为正样本
  • Anchor 与 Ground Truth 之间的 IoU 小于 0.50.5 为负样本

然后依旧是按照正负比例采样出正样本和负样本,比例如 1:31:3。

3. RetinaNet 的算法原理

RetinaNet 在算法原理上并没有太多的不一样,相当于是 one-stage 算法和 two-stage 算法的缝合,接下来我们细细看一下。

首先,先对 RetinaNet 做一个定性的描述:RetinaNet 是基于 Anchor 的 one-stage 算法,损失函数采用了 Focal Loss。这里有三个元素:Anchor,one-stege 和 Focal Loss。

3.1. RetinaNet 的网络架构

在 RetinaNet 网络中,网络架构采用的是 Backbone + FPN + 分类回归双头子网络的结构,其中:

  • 第一和第二部分,Backbone 与特征金字塔 FPN,主要作用是提取图片特征,用 FPN 能够兼顾大目标和小目标
  • 第三部分是任务头,RetinaNet 附加了两个结构简单的全卷积网络 FCN 子网络,分别负责分类和边界框回归,其中,分类子网络负责预测每个锚框在各类别上的概率,边界框回归子网络负责预测每个锚框相对于真实框的位置偏移量。

这一部分相对于其他 one-stage 的网络结构也没有太大的变化。

3.2. Anchor 的生成

RetinaNet 算法中的 Anchor 的生成逻辑与 Faster R-CNN 中是一致的(估计主要原因是同一个作者吧),都是在特征图的每一个位置 cell,以该 cell 的中心,映射回原图,在原图上以一定的宽高,生成初始的 Anchor,这里一般采用不同 scale 和不同 aspect ratio 的组合形式,每个位置也是生成 99 个 Anchor。以 80×8080\times 80 的特征图图为例,最终共生成 80×80×9=5760080\times 80\times 9 = 57600 个 Anchor。不同算法中对边框的表示形式也不一样,在 RetinaNet 中也是延续了 Faster R-CNN 中的 box encoding 形式。具体来说,首先,Anchor 表示成: B=(x,y,w,h)B= \left ( x,y,w,h \right ),其中,(x,y)\left ( x,y \right ) 表示的是中心点的坐标,w,hw,h表示的是候选框的宽高。对于真实的目标框也需要转换成中心点的表示形式:B∗=(x∗,y∗,w∗,h∗)B^{\ast}=\left ( x^{\ast},y^{\ast},w^{\ast},h^{\ast} \right )。

回顾下,在 YOLO v2 中,只有最匹配的 Anchor 才负责对应的目标框,而在 RetinaNet 中,则是将 Anchor 与 Ground Truth 计算 IoU,并对其排序,IoU 较大的为正样本,IoU 较小的为负样本。

3.3. 回归参数的训练

有了上面的 Anchor 和 Ground Truth 的表示方法,对于边框的学习,不直接学习 x∗,y∗,w∗,h∗x^{\ast},y^{\ast},w^{\ast},h^{\ast} 这四个参数,而是学习如何从 (x,y,w,h)\left ( x,y,w,h \right ) 变到 (x∗,y∗,w∗,h∗)\left ( x^{\ast},y^{\ast},w^{\ast},h^{\ast} \right ),这里用到了四个参数 tx,ty,tw,tht_x,t_y,t_w,t_h,先上公式:

tx=x∗−xw,ty=y∗−yht_x=\frac{x^*-x}{w},\quad t_y=\frac{y^*-y}{h}

tw=log⁡w∗w,th=log⁡h∗ht_w=\log\frac{w^*}{w},\quad t_h=\log\frac{h^*}{h}

4. Focal Loss

Focal Loss 是 RetinaNet 的灵魂,它是对标准交叉熵损失(Cross Entropy, CE)的改进,旨在解决类别不平衡问题。标准交叉熵损失为:

CE(pt)=−log(pt)\text{CE}\left(p_t\right) = -log\left(p_t\right)

其中,ptp_t 是模型对真实类别的预测概率。

Focal Loss 在交叉熵的基础上引入了一个调节因子(Modulating Factor)(1−pt)γ\left(1-p_t\right)^\gamma 和一个平衡因子 αt\alpha_t,其公式为:

FL(pt)=−αt(1−pt)γlog(pt)\text{FL}\left(p_t\right) = -\alpha_t \left(1 - p_t\right)^\gamma log\left(p_t\right)

来看下这两者之间的关系以及不同的参数对损失函数的影响:

我们发现当样本被正确分类且概率 ptp_t 很高时,也就是容易的样本,此时,1−pt1-p_t 趋近于 00,该样本的损失被大幅降低,对整体损失函数的贡献就会比较小。而对于难样本,也就是 ptp_t 较小的样本,此时调节因子 (1−pt)γ\left(1-p_t\right)^\gamma 接近 11,对整体损失函数贡献比较大。参数 γ\gamma 控制着对容易样本的抑制程度。

而平衡因子 αt\alpha_t 则是用于调节正负样本之间的整体权重,通常设置为正样本权重较高(如 α=0.25\alpha=0.25),以进一步平衡正负样本的贡献。通过这种方式,Focal Loss 让模型在训练时自动聚焦于少量“困难”的样本,并大幅降低海量“容易”负样本的权重,从而有效解决了单阶段检测中的类别不平衡问题。

5. 总结

RetinaNet 的网络和运行机制也是结合了 YOLO 和 Faster R-CNN,以及在此基础上增加的特征金字塔 FPN,但实际上,更大的贡献在于 Focal Loss 损失函数的设计,更优雅的解决了单阶段目标检测算法的正负样本问题,Focal Loss 的成功也深刻影响了后续许多单阶段目标检测算法的设计。

参考文献

[1] Redmon J, Divvala S, Girshick R, et al. You only look once: Unified, real-time object detection[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2016: 779-788.

[2] Ren S, He K, Girshick R, et al. Faster r-cnn: Towards real-time object detection with region proposal networks[J]. Advances in neural information processing systems, 2015, 28.

[3] Redmon J, Farhadi A. YOLO9000: better, faster, stronger[C]//2017 IEEE conference on computer vision and pattern recognition (CVPR). Ieee, 2017: 6517-6525.

[4] Lin T Y, Goyal P, Girshick R, et al. Focal loss for dense object detection[C]//Proceedings of the IEEE international conference on computer vision. 2017: 2980-2988.

[5] 目标检测 YOLO v1 算法