自从2012年的ILSVRC竞赛中基于CNN的方法一鸣惊人之后,CNN已成为图像分类、检测和分割的神器。其中在图像检测的任务中,R-CNN系列是一套经典的方法,从最初的R-CNN到后来的Fast R-CNN, Faster R-CNN 和今年的Mask R-CNN, 我们可以看到CNN在图像检测中是如何一点一点提高的。和本文来一道回顾R-CNN家族的发展史,了解这些方法的演变和这个演变过程中的那些富有创意的想法。

R-CNN 系列的四篇文章如下:

  1. R-CNN: https://arxiv.org/abs/1311.2524

  2. Fast R-CNN: https://arxiv.org/abs/1504.08083

  3. Faster R-CNN: https://arxiv.org/abs/1506.01497

  4. Mask R-CNN: https://arxiv.org/abs/1703.06870

图像的检测任务是从一个复杂场景的图像中找到不同的物体,并且给出各个物体的边界框。图像检测的三个著名的数据集是PASCAL VOC,ImageNet和微软COCO. PASCAL VOC包含20个物体的类别,而ImageNet包含一千多种物体类别,COCO有80中物体类别和150万个物体实例。

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)

PASCAL VOC目标检测

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)

COCO目标检测和实例分割

1, R-CNN

R-CNN的思路是很直观的三步曲:1,得到若干候选区域;2, 对每个候选区域分别用CNN分类;3,对每个候选区域分别进行边框预测。

在R-CNN出现之前,目标检测的流行思路是先从图像中得到一些候选区域,再从候选区域中提取一些特征,然后利用一个分类器对这些特征进行分类。分类的结果和候选区域的边界框就可以作为目标检测的输出。一种得到候选区域的方法是Selective Search, 该方法可以得到不同尺度的候选区域,每个候选区域是一个联通的区域。如下图中,左边得到的是较小的候选区域,右边是较大的候选区域,在该尺度下包含了整个人的区域。

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)Selective Search得到不同尺度的候选区域

R-CNN的想法是,既然CNN在图像分类任务中的表现很好,可以自动学习特征,何不用它来对每个候选区域进行特征提取呢?于是R-CNN在Selective Search得到的候选区域的基础上,将每个候选区域缩放到一个固定的大小,并且作为AlexNet(ImageNet 2012图像分类竞赛的冠军)的输入,依次对这些区域进行特征提取,然后再使用支持向量机对各个区域的特征分别进行分类。R-CNN的过程如下:

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)

R-CNN示意图

这样就能得到一个检测的结果了。但是Slelective Search得到的候选区域并不一定和目标物体的真实边界相吻合,因此R-CNN提出对物体的边界框做进一步的调整,使用一个线性回归器来预测一个候选区域中物体的真实边界。该回归器的输入就是候选区域的特征,而输出是边界框的坐标。

R-CNN的效果很不错,比VOC 2012的最好的结果提高了30%的准确度。但是问题就是太慢,主要有三方面原因:1,候选区域的生成是一个耗时的过程;2,对候选区域特征提取需要在单张图像上使用AlexNet 2000多次; 3, 特征提取、图像分类、边框回归是三个独立的步骤,要分别进行训练,测试过程中的效率也较低。

 

2, Fast R-CNN

为了解决R-CNN中效率低的问题,Fast R-CNN想,一张图像上要使用AlexNet 2000多次来分别得到各个区域的特征,但很多区域都是重合的,可否避免这些重复计算,只在一张图像上使用一次AlexNet,然后再得到不同区域的特征呢?

于是Fast R-CNN提出了一个ROI Pooling的方法,先对输入图像使用一次CNN前向计算,得到整个图像的特征图,再在这个特征图中分别取提取各个候选区域的特征。由于候选区域的大小不一样,而对应的特征需要要具有固定的大小,因此该方法对各个候选区域分别使用

Pooling, 其做法是:假设第 i个候选区域ROI的大小为hi * wi, 要使输出的大小为h*w,那么就将该ROI分成h*w 个格子,每一个格子的大小为(hi/h)*(wi/w), 然后对每一格子使用max-pooling得到大小为w*w的特征图像。

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)Fast R-CNN示意图, 将每个候选区域分成h x w大小的格子做pooling

Fast R-CNN的第二点创意是把之前独立的三个步骤(特征提取、分类和回归)放到一个统一的网络结构中。该网络结构同时预测一个候选区域的物体类别和该物体的边界框,使用两个全连接的输出层分别进行类别预测和边框预测(如下图所示),将这两个任务进行同时训练,利用一个联合代价函数:

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)

公式中的两项分别是classification loss 和regression loss。

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)特征提取-分类-回归联合网络

        使用VGG16作为特征提取网络,Fast R-CNN在测试图像上的处理时间比R-CNN快了200多倍,并且精度更高。如果不考虑生成候选区域的时间,可以达到实时检测。生成候选区域的Selective Search算法处理一张图像大概需要2s的时间,因此成为该方法的一个瓶颈。

为了改进这个缺点,RBG借鉴何恺明的SPP-Net提出了fast R-CNN。Fast R-CNN与R-CNN最大的区别就是fast R-CNN不是对每个候选框单独进行特征提取,而是对整个图像进行特征提取,在提取特征之后才进行候选框的划分,这就避免了对重叠候选框的重复计算。另外,fast R-CNN提出了ROI pooling层概念,ROI pooling层可以看作单层的SPP-net。在R-CNN中,对候选框进行卷积操作时,由于卷积操作需要固定大小的输入图像,而候选框的大小又是不确定的,所以需要对候选框进行变形操作以满足需求,这不仅导致多余的操作,而且变形可能导致特征提取效果不够理想。而SPP-net可以直接对不同尺寸的候选框进行处理,这就保证了很好的分类效果。

但是,fast R-CNN还是不够快,找出所有的候选框还是需要耗费数秒的时间,不能满足实时分类的性能要求。于是,RBG与何恺明合作提出了性能更好的faster R-CNN。既然对单幅图像用selective search方法提取proposal就要数秒的时间,那就设计新的方法提取proposal。这种新的方法就是RPN网络(Region Proposal Networks)。

3, Faster R-CNN

上面两种方法都依赖于Selective Search生成候选区域,十分耗时。考虑到CNN如此强大,Faster R-CNN提出使用CNN来得到候选区域。假设有两个卷积神经网络,一个是区域生成网络,得到图像中的各个候选区域,另一个是候选区域的分类和边框回归网路。这两个网络的前几层都要计算卷积,如果让它们在这几层共享参数,只是在末尾的几层分别实现各自的特定的目标任务,那么对一幅图像只需用这几个共享的卷积层进行一次前向卷积计算,就能同时得到候选区域和各候选区域的类别及边框。

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)Faster R-CNN:在卷积后的特征图上使用Region Proposal Network

候选区域生成网络(Region Proposal Network, RPN)如下,先通过对输入图像的数层卷积得到一个特征图像,然后在特征图像上生成候选区域。它使用一个n*n n=3的滑动窗口,将局部的特征图像转换成一个低维特征, 预测k个的区域(cls层,2k个输出)是否为候选区域和对应的k个边框(reg层,4k个输出)。这里的K个区域被称为锚(anchor), 对应着与滑动窗口具有相同的中心的不同大小和不同长宽比的矩形框。假设卷积后的特征图像大小为W*H,那么一共有WHk个锚。这种特征提取和候选区域生成的方法具有位移不变性。

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)对一个滑动窗口中的anchor预测候选区域

使用RPN得到候选区域后,对候选区域的分类和边框回归仍然使用Fast R-CNN。这两个网络使用共同的卷积层。 由于Fast R-CNN的训练过程中需要使用固定的候选区域生成方法,不能同时对RPN和Fast R-CNN使用反向传播算法进行训练。该文章使用了四个步骤完成训练过程:1,单独训练RPN;2,使用步骤中1得到的区域生成方法单独训练Fast R-CNN; 3, 使用步骤2得到的网络作为初始网络训练RPN;4, 再次训练Fast R-CNN, 微调参数。

Faster R-CNN的精度和Fast R-CNN差不多,但是训练时间和测试时间都缩短了10倍。

总的来说,R-CNN,fast R-CNN,faster R-CNN这一系列的成果,使得深度学习在目标检测领域得到广泛的应用,算法的流程也日趋简单,精度不断提高,可以说这一系列基于region proposal的目标检测方法仍然是目标检测领域最主要的一个分支。

基于region proposal的算法都是two-stage的,他们的主要缺点就是速度不够快,尽管每年都有非常新颖的算法提出,但是在速度方面并没有质的飞跃。而相对而言,one-stage的主要优势就是网络简单,速度够快,那么有没有精度能与two-stage算法匹敌的one-stage算法呢?答案是有的,这就是接下来要介绍的YOLO和SSD算法。

 基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)

 YOLO流程图

 

YOLO(You Only Look Once)是一个可以一次性预测多个Box位置和类别的卷积神经网络,能够实现端到端的目标检测和识别,其最大的优势就是速度快。YOLO有着极为简单的模型,它没有选择滑窗或者提取proposal的方式进行网络的训练,而是直接选用整幅图训练模型。这种方式可以更好地区分背景区域和目标区域,而不会出现proposal方法中将背景区域误判为目标的情况。当然,速度上的提升也导致了精度上的一些牺牲,YOLO简单粗暴地对图像进行网格划分,然后再对网格进行处理,这就会导致定位不精确的问题,YOLO的识别精度并比不上当时精度最高的faster R-CNN方法。

Faster R-CNN的定位相比于YOLO要精确得多,那把YOLO和faster R-CNN中关于定位的部分结合起来会怎样呢?这就有了SSD(Single Shot MultiBox Detector),其结果相比YOLO提高了很多。

4, Mask R-CNN

Faster R-CNN 在物体检测中已达到非常好的性能,Mask R-CNN在此基础上更进一步:得到像素级别的检测结果。 对每一个目标物体,不仅给出其边界框,并且对边界框内的各个像素是否属于该物体进行标记。

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)

Mask R-CNN: 像素级别的目标检测

Mask R-CNN利用Faster R-CNN中已有的网络结构,再添加了一个头部分支,使用FCN对每个区域做二值分割。

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)

Mask R-CNN还提出了两个小的改进使分割的结果更好。第一,对各个区域分割时,解除不同类之间的耦合。假设有K类物体,一般的分割方法直接预测一个有K个通道的输出,其中每个通道代表对应的类别。而Mask R-CNN预测K个有2个通道(前景和背景)的输出,这样各个类别的预测是独立的。第二,Faster R-CNN中使用的ROI Pooling将每个ROI映射到一个固定的大小,在pooling时有取整操作,这样会导致pooling 前后的特征图没有连续的对应关系。例如,如果pooling前的大小是112x112,pooling之后的大小是7x7,对于pooling之前的一个像素,其横坐标位置是 X ,那么pooling后对应的横坐标是 x/16 , 再取整就得到了其在7x7格子中的位置。由于取整操作会带来误差,Faster R-CNN不取整,使用双线性插值得到 X/16处的真实数值,该方法称作ROIAlign.


三、Focal Loss:速度上一马当先


 

YOLO和SSD可以算one-stage算法里的佼佼者,加上R-CNN系列算法,这几种算法可以说是目标检测领域非常经典的算法了。这几种算法在提出之后经过数次改进,都得到了很高的精确度,但是one-stage的算法总是稍逊two-stage算法一筹,于是就有了Focal Loss来找场子。

在Focal Loss这篇论文中中,作者认为one-stage精确度不如two-stage是因为下面的原因:

①  正负样本比例极度不平衡。由于one-stage detector没有专门生成候选框的子网络,无法将候选框的数量减小到一个比较小的数量级(主流方法可以将候选框的数目减小到数千),导致了绝大多数候选框都是背景类,大大分散了放在非背景类上的精力;

②  梯度被简单负样本主导。我们将背景类称为负样本。尽管单个负样本造成的loss很小,但是由于它们的数量极其巨大,对loss的总体贡献还是占优的,而真正应该主导loss的正样本由于数量较少,无法真正发挥作用。这样就导致收敛不到一个好的结果。

既然负样本数量众多,one-stage detector又不能减小负样本的数量,那么很自然的,作者就想到减小负样本所占的权重,使正样本占据更多的权重,这样就会使训练集中在真正有意义的样本上去,这也就是Focal Loss这个题目的由来。

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)

 

其实在Focal Loss之前,就有人提出了OHEM(online hard example mining)方法。OHEM的核心思想就是增加错分类样本的权重,但是OHEM却忽略了易分类样本,而我们知道这一部分是所有样本中的绝大部分。

 

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)

 

与OHEM不同,Focal Loss把注意力放在了易分类样本上,它的形式如图所示。Focal Loss是一种可变比例的交叉熵损失,当正确分类可能性提高时比例系数会趋近于0。这样一来,即使再多的易分类样本也不会主导梯度下降的过程,于是训练网络自然可以自动对易分类样本降权,从而快速地集中处理难分类样本。

 

基于深度学习的目标检测算法综述(从R-CNN到Mask R-CNN)

 

可以看出,Focal Loss打败了所有state-of-the-art的算法,而且竟然在速度上也是一马当先,可以说相当有说服力。但是作者为了证明Focal Loss的有效性,并没有设计更新颖的网络,这与其他算法提高精确度的做法是不一样的——他们要么改造原有算法的网络结构,要么另辟蹊径。另外,Focal Loss函数的形式并不是不可变的,只要可以达到对易分类样本降权的目的,可以在形式上有所变化。

总之,Class imbalance是阻碍one-stage方法提高准确率的主要障碍,过多的easy negative examples会在训练过程中占据主导地位,使训练结果恶化,所以要用Focal Loss对easy negative examples进行降权,而把更多的注意力集中在hard examples上。 

 

上述几种方法的代码:

R-CNN

  • Caffe版本:rbgirshick/rcnn

Fast R-CNN

  • Caffe版本: rbgirshick/fast-rcnn

Faster R-CNN

  • Caffe版本: https://github.com/rbgirshick/py-faster-rcnn

  • PyTorch版本: https://github.com/longcw/faster_rcnn_pytorch

  • MatLab版本: https://github.com/ShaoqingRen/faster_rcnn

Mask R-CNN

  • PyTorch版本: https://github.com/felixgwu/mask_rcnn_pytorch

  • TensorFlow版本: https://github.com/CharlesShang/FastMaskRCNN

注:R-CNN, Fast R-CNN和Faster R-CNN已在之前的文章总结过,这里添上Mask R-CNN。更多目标检测的方法在《深度卷积神经网络在目标检测中的进展》这篇文章中。另外,《A Brief History of CNNs in Image Segmentation: From R-CNN to Mask R-CNN》这篇文章也做了详细的介绍。