Object Detection--RCNN,SPPNet,Fast RCNN,FasterRCNN论文详解

物体检测

物体检测是图像处理学科的一个重要难题。再探讨物体检测之前,我们先说一下图片分类问题,在前面的blog中我们讲解了AlexNet,VGGNet等深度卷积网络。因为有着ImageNet这样的大规模高质量的数据集,在图像分类问题下深度神经网络表现出极好的效果,但是ImageNet的另一项比赛-物体检测定位Task,成绩一直不是很好,也没有什么大的起伏。这种现象直到R-CNN的出现。

图片分类和物件检测之间有很多联系,但是我觉得物体检测比图片分类更难,而且高质量的数据集更少。

图片分类和物体检测的区别

输出不同

正如下图,分类任务和检测任务在输入和输出上的不同:

这里写图片描述

任务description
分类(Classification)在固定的类别下对一张图片进行分类
输入:图片
输出:类别标签
评价标准:准确率(top1,top5)
Detection+Localization(检测和定位)在输入图片中找出存在的物体类别和位置.(可能存在多种物体)
输入:图片
输出:类别标签和bbox(x,y,w,h)
评价标准:
IoU(Intersection over Union)
mAP(Mean Average Precision)

检测的目标不同

物体检测可能会存在多个检测目标,这不仅需要我们判别出各个物体的类别,而且还要准确定位出物体的位置

下面图片上有猫,有狗,还有小黄鸭,这是多物体检测:

这里写图片描述


物体检测算法常用到的概念

下面我们讲解一下在物体检测算法中常用到的几个概念:Bbox,IoU,非极大值抑制。

Bounding Box(bbox)

bbox是包含物体的最小矩形,该物体应在最小矩形内部.

下图的包围小猫的红色矩形框:

这里写图片描述

这里注意到物体检测中关于物体位置的信息输出是一组 (x,y,w,h) 数据,其中 x,y 代表着bbox的左上角(或者其他固定点,可自定义),对应的 w,h 表示bbox的宽和高.一组 (x,y,w,h) 可以唯一的确定一个定位框。

Intersection over Union(IoU)

对于两个区域 R R,则两个区域的重叠程度overlap计算如下:

O(R,R)=|RR||RR|

这里写图片描述

在训练网络的时候,我们常依据侯选区域和标定区域的IoU值来确定正负样本。

非极大值抑制 (Non-Maximum Suppression)

非极大值抑制(NMS)可以看做是局部最大值的搜索问题,NMS是许多计算机视觉算法的部分。如何设计高效的NMS算法对许多应用是十分关键的,例如视频跟踪、数据挖掘、3D重建、物体识别以及纹理分析等。

这里我们主要针对非极大值抑制在物体检测上的应用,非极大值抑制就是把不是极大值的抑制掉,在物体检测上,就是对一个目标有多个标定框,使用极大值抑制算法滤掉多余的标定框。

下图一个小猫有多个红框标定:

这里写图片描述

我们使用非极大值抑制算法后:

这里写图片描述

算法的实现可以看Matlab下的非极大值抑制实现




R-CNN

R-CNN经典论文《Rich feature hierarchies for Accurate Object Detection and Segmentation

RGB大神的(Ross Girshick)这篇paper,改变了图像领域检测物体的实现思路,R-CNN是以深度学习为基础的物体检测的模型,以R-CNN为基点,后续的SPPNet、Fast R-CNN、Faster R-CNN模型都是照着这个思路,下面就来细致学习R-CNN模型。

在R-CNN模型出现之前,较好的物体检测模型DPM使用了一堆传统的算法模型,在VOC数据集上表现大约在30mAP左右。R-CNN开创性的提出了用深度神经网络来做物体检测。并且提出了一系列在较少标注集下的训练模型方法。

Introduction

R-CNN在物体检测上的解决方案

Created with Raphaël 2.1.0 找出图片中可能存在目标的侯选区域 通过CNN对候选区域提取特征向量 在候选区域的特征向量上训练分类器, 分类器用于判别物体并得到bbox 修正bbox,对bbox做回归微调

这里写图片描述

这里写图片描述

R-CNN模型的处理流程:

  1. 找出图片中可能存在目标的侯选区域
  2. 通过CNN对候选区域提取特征向量
  3. 在候选区域的特征向量上训练分类器,分类器用于判别物体并得到bbox
  4. 修正bbox,对bbox做回归微调

下面就来一个一个步骤讲解~

找出图片中可能存在目标的侯选区域

一张图片上存在的物体,大小/位置不固定,如果我们用滑窗的方法去寻找可能存在物体,工作量非常大,且很难实现。R-CNN模型使用的方法是先使用“传统成熟”的方法找出一组图像中可能存在目标的侯选区域(region proposals),产生侯选区域的方案可减少在一张图片上寻找物体的复杂度,且很大可能的保存了图片上所有存在物体的区域,这一方案发展的较为成熟,实现起来较为简便。

常用的产生侯选区域的方法:

这里写图片描述

R-CNN最终选择的产生候选区域产生的方法是selective search


selective search的实现过程详情参考论文Selective Search for Object Recognition

下图是selective search在图片上提取侯选区域的过程:

这里写图片描述


Selective Search在一张图片上提取出来大概2000个侯选区域,需要注意的是这些候选区域的长宽不固定。而在下一层使用CNN提取特征向量时,需要接受固定长度的输入,故我们需要对候选区域做一些长度上的修改。

论文对图片做了两种方法的比较:

  • 各向异性缩放,即直接缩放到指定大小,这可能会造成不必要的图像失真
  • 各向同性缩放,在原图上出裁剪侯选区域,在边界用固定的背景颜色(采用侯选区域的像素颜色均值)填充到指定大小

这里写图片描述

经过一系列的实验,作者发现采用各向异性缩放的实验精度最高,就采用这个方法了。

通过CNN对候选区域提取特征向量

用CNN的作用是在侯选区域的基础上提取出更高级、更抽象的特征,高级特征的作用是为下一步的分类器作为输入数据,分类器依据高级特征回归出物品的位置和种类。

在讲到CNN用作分类问题时,CNN的多个卷积层可以宽泛的认为是对原图像的特征提取,并且这样的特征提取具有平移不变性。我们把CNN当做特征提取的模板,把需要提取特征的图片塞给它,训练好我们需要的CNN,就可以获取到我们想要的特征向量。

网络的训练

CNN的训练分为以下几个过程:

  • 有监督的预训练
    一般的CNN模型层数多,模型的容量大,在标定数据少的情况下,这样的数据量是不够从新训练一个CNN模型的。故我们采用已训练好的AlexNet/VGG16模型的卷积层参数,使用这样已训练好的网络参数,可以较好的提取图片的特征。这样的操作有一个专业的名词-迁移学习(这里不做讨论)。

    这里写图片描述

  • fine-tuning
    AlexNet是针对ImageNet训练出来的模型,AlexNet的卷积部分可以作为一个好的特征提取器,后面的全连接层可以理解为一个好的分类器。这里把AlexNet的softmax层替换为一个N+1神经元的输出层(N为存在物体的种类,即正样本;1为背景,即负样本)。然后做微调训练。

    这里写图片描述


    关于fine-tuning的训练细节

    原本ImageNet的输出类别有1000个,这里把1000个替换为21个(N=20,1为背景).
    使用的SGD,每个mini-batch取128.

    样本数量描述
    正样本32候选区域与ground-truth(图片物体标注区域)的IoU>0.5
    负样本96候选区域与ground-truth(图片物体标注区域)的IoU<0.5

    这里取IoU的阈值为0.5是因为CNN模型容量大,需要的数据多,故放宽限制,获取到更多的数据,防止模型过拟合。

    需要注意的是,我们在训练CNN的时候会在网络的后面加上一个分类层,在训练完毕后,我们会移除最后的分类层,直接提取到前面的FC层,AlexNet的FC层为4096维。


对于一张图片,使用训练好的CNN基础上,将所有的图片的所有侯选区域塞到CNN里面,把得到的pool5 feature存到硬盘里面(这里一存,后面训练一取,非常耗费时间)

这里写图片描述

在候选区域的特征向量上训练分类器

前面的CNN在侯选区域上提取出了特征向量,例如2000个侯选区域,那么提取出来的就是2000*4096这样的特征向量(AlexNet的第一个FC层维度为4096,故pool5的输出为4096)。用这些特征向量训练同时训练N个二分类的SVM,SVM的权重矩阵为4096xN(N为分类种类)

这里你可能会问什么要使用SVM?而不是CNN过FC层直接softmax出来得了?

这是因为我们在训练CNN的时候选的数据比较宽泛(选择样本不够准确),直接使用softmax输出的效果不是很好,而这里在特征向量的基础上,再训练一组SVM效果会比较棒。但是需要注意的是,在训练SVM的时候,我们使用的样本是有变换的。

训练SVM时使用的样本

样本描述
正样本候选区域与ground-truth(图片物体标注区域)的IoU>0.7
负样本候选区域与ground-truth(图片物体标注区域)的IoU<0.3

这个0.7的阈值是做实验得出来的经验值。

这里写图片描述

在经过SVM分类后,会输出一堆的候选框得分(是一个2000x20的得分矩阵),这时候我们需要用的非极大值抑制得到想要的候选框了.大概步骤如下:

  • 对矩阵按列从大到小排序
  • 每列的最大值向下做非极大值抑制,遍历完所有列
  • 依据阈值,得到候选区域的类型

注意到这里,我们得到的是一组预测好类别的候选区域了。

修正bbox,对bbox做回归微调

我们使用一个简单的bounding-box回归用于提高定位的表现。这个bbox回归应用在SVM分类器给每个候选区域打分后,bbox回归认为候选区域和ground-truth之间是线性关系(因为在最后从SVM内确定出来的区域比较接近ground-truth,这里近似认为可以线性关系)

这里写图片描述


Bounding-box regression(边框回归详解)

这里写图片描述

从候选框P到预测框 G^ 的平移、放缩思路是:

  1. 先做平移 (Δx,Δy)

    Δx=Pwdx(P) , Δy=Phdy(P)

    即R-CNN论文里面的:

    Gx^=Pwdx(P)+Px , Gy^=Phdy(P)+Py

  2. 作尺度放缩 (Sw,Sh)

    Sw=Pwdw(P) , Sh=Phdh(P)

    Gw^=Pwedw(P) , Gh^=Phedh(P)

    我们要学习的是 dx(P),dy(P),dw(P),dh(P) 这四个变换.


  • 输入:

    • 样本值: 这里输入不是Proposal的 P=(Px,Py,Pw,Ph) .而是Proposal在Pool5的Feature特征向量.(这里选用的Proposal必须和Ground Truth的IoU>0.6才算是正样本.)

    • 标签值: Ground Truth : t={tx,ty,tw,th}

  • 输出:
    需要进行平移变换和尺度缩放的 dx(P),dy(P),dw(P),dh(P) ,或者说是 Δx,Δy,Sw,Sh

  • 计算过程:
    这里我们可以通过计算得到预测值 G^
    R-CNN里面:

    tx=GxPxPw , ty=GyPyPh , tw=logGwPw , th=logGhPh

    目标函数表示为:

    d(P)=wTΘ5(P)

    Θ5(P) 是输入Proposal在Pool5的特征向量, w 是要学习的参数.即 (wx,wy,ww,wh)

    故损失函数为:(带正则化)

    Loss=argminw^i=0N(tiw^TΘ5(Pi))2+λ||w^||2

注意:只有当Proposal和Ground Truth比较接近时(线性问题),我们才能将其作为训练样本训练我们的线性回归模型,否则会导致训练的回归模型不work(当Proposal跟G离得较远,就是复杂的非线性问题了,此时用线性回归建模显然不合理)


到这里,我们算是把R-CNN整个流程讲完了,后面还有一堆R-CNN的进化版~



SPPNet

SPPNet的论文《Spatial Pyramid Pooling in Deep Convolutional
Networks for Visual Recognition》

Kaiming男神的(Kaiming He)的这篇paper,是在R-CNN的基础上提出了空间金字塔变换层(Spatial Pyramid Pooling),SPPNet大幅度提高了R-CNN的训练速度和测试速度,同时算法的精度也上升了,后续的Fast R-CNN、Faster R-CNN模型也是以这个思路,下面就来细致学习SPPNet模型。

Introduction

SPPNet主要针对两点提出改进:

  • CNN的固定输入大小,导致不必要的精度损失
  • R-CNN模型候选区域在CNN内的重复计算,造成的计算冗余

为什么CNN需要固定大小的输入?

因为一个CNN一般分为两个部分,前面的部分是卷积层,后面的部分是FC层,卷积层不要求固定大小的输入;但是FC层在设计时就固定了神经元的个数,故需要固定长度的输入。这也就是CNN需要固定输入的问题所在。

R-CNN模型SPPNet模型
将侯选区域送到CNN里面提取特征向量时,因为CNN的输入图像需要固定大小,而候选区域的长宽都是不固定的,故需要对候选区域做填充到固定大小,当我们对侯选区域做cropping或者warping操作,可能会让图片不完整包含物体,一些我们不想见到的几何失真,这都会造成识别精度损失。SPPNet的解决办法是使用“空间金字塔变换层”将接收任意大小的图像输入,输出固定长度的输出向量,这样就能让SPPNet可接受任意大小的输入图片,不需要对图像做crop/wrap操作。

这里写图片描述

R-CNN模型候选区域在CNN内的重复计算

R-CNN模型SPPNet模型
在R-CNN中,每个候选区域都要塞到CNN内提取特征向量,一张图片有2000个候选区域,也就是一张图片需要经过2000次CNN的前向传播,这2000重复计算过程会有大量的计算冗余,耗费大量的时间。SPPNet提出了一种从候选区域到全图的特征映射(feature map)之间的对应关系,通过此种映射关系可以直接获取到候选区域的特征向量,不需要重复使用CNN提取特征,从而大幅度缩短训练时间。

这里写图片描述

我们通俗的理解一下R-CNN和SPPNet的实现过程:

R-CNN模型SPPNet模型
R-CNN是让每个候选区域经过crop/wrap等操作变换成固定大小的图像
固定大小的图像塞给CNN
CNN输出获得固定大小的feature map
feature map传给后面的层做训练回归分类操作。

这里每个候选区域是需要单独过一下CNN,2000个候选区域过2000次CNN,耗费时间啊
SPPNet让一张图片完整的塞给CNN得到全图的feature map
让2000个候选区域与feature map直接映射,直接得到2000个候选区域的特征向量(这里不需要再过CNN了).

但是候选区域的特征向量大小不固定,所以把候选区域的特征向量塞给SPP层,SPP层输入接收任何大小,输出固定大小的特征向量

经过这样映射+SPP转换,简化了计算,不但速度上去了,精确度也上去了

看完上面的介绍,可以定位这篇论文的两个难点了。

  • SPPNet怎么就能把候选区域从全图的feature map 直接整出来特征向量了?
  • 空间金字塔变换层怎么可以接收任意大小的输入,输出固定的向量?

空间金字塔变换层

首先我们要连接一下Spatial Pyramid Pooling,关于Spatial Pyramid Pooling详细可参考论文
Beyond bags of features: Spatial pyramid matching for recognizing natural scene categories[C]//CVPR 2006

空间金字塔变换层(Spatial Pyramid Pooling,SPP)可以对图片提取特征,例如下图就是1*1,2*2,4*4大小的bin块,将一张图片以三种方式切割并提取特征,这样我们可以得到一共1+4+16=21种特征,这就是以不同的大小的bin块来提取特征的过程就是空间金字塔变换。

这里写图片描述

将SPP应用在不同大小的侯选区域候选区域特征变换:

这里写图片描述

上图spp layer分成1x1(塔底),2x2(塔中),4x4(塔顶)三张子图,对每个子图的每个区域作max pooling(论文使用的),出来的特征再连接到一起,就是(16+4+1)x256的特征向量。

无论输入图像大小如何,出来的特征固定是(16+4+1)x256维度。这样就实现了不管图像尺寸如何,SPP层的输出永远是(16+4+1)x256特征向量。

把候选区域从全图的feature map映射出特征向量

这部分在论文的Appendix A里面有介绍,看了后非常的迷茫。

这里写图片描述

网上查了一堆资料。这里引用知乎-晓雷机器学习笔记machineLearning-blog.
并添加一些自己的理解。

感受野的计算

感受野我们在CNN里面讲过关于卷积参数计算

在CNN中感受野(receptive fields)是指某一层输出结果中一个元素所对应的上一层的区域大小.

在卷积参数计算过程中,我们给出上一层/下一层/滤波器尺寸、步长和填充大小的关系:

类型大小
输入尺寸 W1×H1
卷积核 F×F
输出尺寸 W2×H2
步长stride: S
填充大小 padding:P

关系式如下:

W2=W1F+2PS+1  ,  H2=H1F+2PS+1

这是上一层到下一层的推导,如果现在反过来,给你下一层的大小,问你上一层的感受野多大,该怎么计算?

我们把上面公式变个形式:

W1=(W21)S2P+F
H1=(H21)S2P+F

直观的感受一下从后向前计算感受野的过程.

这里写图片描述

考虑一下如何计算多层之间的感受野?

这里写图片描述

感受野计算时有下面的几个情况需要说明:

  • 第一层卷积层的输出特征图像素的感受野的大小等于滤波器的大小
  • 深层卷积层的感受野大小和它之前所有层的滤波器大小和步长有关系
  • 计算感受野大小时,忽略了图像边缘的影响,即不考虑padding的大小

这里的每一个卷积层还有一个strides的概念,这个strides是之前所有层stride的乘积。

stridesi=stride1stride2...stridei1

关于感受野大小的计算采用down to top的方式: 即先计算最深层在前一层上的感受野,然后逐渐传递到第一层,使用的公式可以表示如下:

    RF = 1 #待计算的feature map上的感受野大小
      for layer in (down layer To top layer):
        RF = ((RF -1)* stride) + fsize

例如我们计算AlexNet的第四层到第一层的感受野:

这里写图片描述

下面是一个程序计算了AlexNet、VGG16、ZF-5的输入输出尺寸的变化和感受野变化过程:

 net_struct = {'alexnet': {'net':[[11,4,0],[3,2,0],[5,1,2],[3,2,0],[3,1,1],[3,1,1],[3,1,1],[3,2,0]],
                    'name':['conv1','pool1','conv2','pool2','conv3','conv4','conv5','pool5']},
        'vgg16': {'net':[[3,1,1],[3,1,1],[2,2,0],[3,1,1],[3,1,1],[2,2,0],[3,1,1],[3,1,1],[3,1,1],
                         [2,2,0],[3,1,1],[3,1,1],[3,1,1],[2,2,0],[3,1,1],[3,1,1],[3,1,1],[2,2,0]],
                  'name':['conv1_1','conv1_2','pool1','conv2_1','conv2_2','pool2','conv3_1','conv3_2',
                          'conv3_3', 'pool3','conv4_1','conv4_2','conv4_3','pool4','conv5_1','conv5_2','conv5_3','pool5']},
        'zf-5':{'net': [[7,2,3],[3,2,1],[5,2,2],[3,2,1],[3,1,1],[3,1,1],[3,1,1]],
                'name': ['conv1','pool1','conv2','pool2','conv3','conv4','conv5']}}

 imsize = 224

 def outFromIn(isz, net, layernum):#从前向后算输出维度
     totstride = 1
     insize = isz
     for layer in range(layernum):
         fsize, stride, pad = net[layer]
         outsize = (insize - fsize + 2*pad) / stride + 1
         insize = outsize
         totstride = totstride * stride
     return outsize, totstride

 def inFromOut(net, layernum):#从后向前算感受野 返回该层元素在原始图片中的感受野
     RF = 1
     for layer in reversed(range(layernum)):
         fsize, stride, pad = net[layer]
         RF = ((RF -1)* stride) + fsize
     return RF

 if __name__ == '__main__':
     print("layer output sizes given image = %dx%d" % (imsize, imsize))

     for net in net_struct.keys():
         print( '************net structrue name is %s**************'% net)
         for i in range(len(net_struct[net]['net'])):
             p = outFromIn(imsize,net_struct[net]['net'], i+1)
             rf = inFromOut(net_struct[net]['net'], i+1)
             print( "Layer Name = %s, Output size = %3d, Stride = % 3d, RF size = %3d" % (net_struct[net]['name'][i], p[0], p[1], rf))

这里写图片描述

基于感受野的特征映射

通常,我们需要知道网络里面任意两个feature map之间的坐标映射关系(一般是中心点之间的映射),如下图,我们想得到map3上的点p3映射回map2所在的位置p2(橙色框的中心点)

这里写图片描述

计算公式:

  • 对于 Conv/Pool layer: pi=sipi+1+((ki1)/2padding)
  • 对于Neuronlayer(ReLU/Sigmoid/..) : pI=pi+1

上面是计算任意一个layer输入输出的坐标映射关系,如果是计算任意feature map之间的关系,只需要用简单的组合就可以得到,下图是一个简单的例子:

这里写图片描述

下图是Kaiming He 在ICCV15上的汇报用的PPT,讲解如何求解Receptive Field:

这里写图片描述

  • A simple solution:
    何凯明在SPP-net中采用的方法。巧妙的化简一下公式

    pi=sipi+1+((ki1)/2padding)
    令每一层的 padding 都为
    padding=ki/2pi=sipi+1+((ki1)/2ki/2)

    • ki 为奇数
      (ki1)/2ki/2)=0pi=sipi+1
    • ki 为偶数
      ((ki1)/2ki/2)=0.5pi=sipi+10.5
    • pi 是坐标值,不取小数,基本上认为 pi=sipi+1 。感受野中心点的坐标 pi 只跟前一层 pi+1 有关。
  • A general solution:
    其实就是把公式 pi=sipi+1+((ki1)/2padding) 级联消去整合一下

    这里写图片描述

候选区域到feature map的映射做法详解

SPP-net 是把原始ROI的左上角和右下角 映射到 feature map上的两个对应点。 有了feature map上的两队角点就确定了 对应的 feature map 区域(下图中橙色)。

这里写图片描述

如何映射?

左上角的点 (x,y) 映射到 feature map上的 (x,y) :使得 (x,y) 在原始图上感受野(上图绿色框)的中心点 与 (x,y) 尽可能接近。

对应点之间的映射公式是啥?

  • 就是前面每层都填充 padding/2 得到的简化公式 : pi=sipi+1
  • 需要把上面公式进行级联得到 p0=Spi+1 其中 (S=i0si)
  • 对于feature map 上的 (x,y) 它在原始图的对应点为 (x,y)=(Sx,Sy)
  • 论文中的最后做法:把原始图片中的ROI映射为 feature map中的映射区域(上图橙色区域)
    • 左上角取: x=x/S+1  ; y=y/S+1
    • 右下角取: x=x/S1  ; y=y/S1

到这里就算是把SPPNet的核心思想讲完了,SPPNet网络后面和R-CNN类似,训练SVM分类器和位置回归等。 论文里还有很多实验细节和结果,有兴趣的可以再分析分析~



Fast R-CNN

15年rgb大神单片匹马干出来一个Fast R-CNN。Fast R-CNN在SPPNet的基础再跟进,进一步提升速度和准确率,提出了RoI层代替SPP层,实现了整个物体检测模型大部分网络的end-to-end,下面就来好好学习一下。

Introduction

论文首先分析了R-CNN和SPPNet存在的问题,进而提出改进办法。

R-CNN存在的问题:

这里写图片描述

  • 检测目标速度慢.
    在测试阶段,特征来自于每张测试图片的每个候选区域.每个候选区域都需要经过CNN的前向传播计算出特征向量。速度很慢.

  • 训练分为多个阶段(multi-stage pipeline)

    • 第一阶段,从原始图片中使用selective search获取约2000个候选区域
    • 第二阶段,训练CNN,获取候选区域的特征向量
    • 第三阶段,训练SVM和bbox回归
      因为是分阶段训练,训练SVM和bbox回归时无法更新前面CNN的参数,模型精度上不去。
  • 训练花费大量的空间和时间(in space and time)
    候选区域经过CNN得到的特征向量要存在到disk内,然后在训练SVM和bbox回归再取出来,这需要大量的磁盘空间,并且很耗费时间。

R-CNN速度慢是因为每个候选区域都需要塞入CNN里面做一次前向传播,而SPPNet实现了计算共享。

在SPPNet中,把全图塞进CNN得到一个完整的feature map,在将每个候选区域映射到feature map上,获得每个候选区域的特征向量。然后用SPP(Spatial pyramid pooling)对在没个候选区域的特征向量再提取得到了固定长度的特征向量,再实现SVM分类,bbox回归等.

SPPNet存在的问题:

SPPNet也有很明显的缺点:

  • 分阶段训练网络:选取候选区域、训练CNN、训练SVM、训练bbox回归器.
  • 特征需要写入磁盘
  • 训练SVM,bbox回归时算法不能更新卷积层的参数,这会影响网络的精度

Fast RNN的改进

针对上述的问题,Fast R-CNN的想法是将整个模型分成两步:

  • 第一步是选取候选区域;
  • 第二步就是提出一个RoI层,整合了整个模型,把CNN、变换层、SVM分类器、bbox回归这几个模块整一起,大家一起训练

这里写图片描述

新的模型效果很好,因为多个训练阶段合并了,训练后面阶段的同时可以更新前面阶段的参数,模型收敛的更好了。同时因为多个阶段合并,候选区域的特征不需要在写入磁盘,一直在显存中,训练的速度大大的提升。

Fast R-CNN的架构

Fast R-CNN模型先把一张图片的候选区域整出来,整个模型的输入是全图片和一组候选区域.和SPPNet一样,首先全图片塞进一个CNN得到一个全图的feature map.

这里写图片描述

然后,把图片的候选区域映射到feature map得到对应的patch(这和SPPNet的处理类似).然后把这个patch塞给ROI层(Region of interest)得到固定大小的的特征向量(feature vector).

每个特征向量会送到FC层,最后分为两个分支层:一个层是处理softmax概率,输出类别有K个类别和”背景”类;另一个层作bbox回归,输出回归的选框数据.联合一起训练整个网络。

这里写图片描述

相比于SPPNet,Fast R-CNN简化了SPP层(RoI层是一个简化的SPP层),按论文的说法,Fast R-CNN是joint training

这里我们主要关注两个问题:

  • RoI层是个啥,怎么工作的?
  • 怎么就把几个阶段搞到一起的训练了?

RoI层是个啥

RoI层的作用和SPPNet中的SPP层作用类似:承上启下。

  • 承上: 接收在每个候选区域在feature map上投影出的特征patch,输出长度固定的特征向量。
  • 启下: 特征向量的长度固定的原因为了对付FC层的特殊要求。

说白了就是如何把不同尺寸的侯选区域提取特征变换成为固定大小的特征向量

这里写图片描述

RoI层是特殊的SPP层,RoI层是使用单个尺度的SPP层(为什么不用多个尺度的原因是多个尺度准确率提升不高,但是计算量成倍的翻)

这里写图片描述

RoI层的Forward

引用shenxiaolu1984.

RoI层将候选区域分为 H×W 块。对每个小块做max-pooling.将候选区的局部特征映射转变为大小统一的数据,送入下一层。

这里写图片描述

RoI层的Backward:

考虑到普通的的max pooling层,设 xi 为输入层的节点, yi 为输出层的节点.

Lxi=0    δ(i,j)=falseLyi  δ(i,j)=true

其中判决函数 δ(i,j) 表示 i 节点是否被j节点选为最大值输出。不被选中有两种可能: xi 不在 yj 范围内,或者 xi 不是最大值

对于RoI的max pooling,一个输入节点可能和多个输出节点相连。设 xi 为输入层的节点, yrj 为第 r 个候选区域的第j个输出节点。
这里写图片描述

Lxi=r,jδ(i,r,j)Lyrj

判决函数 δ(i,r,j) 表示 i 节点是否被候选区域r的第 j 个节点选为最大值输出。代价对于xi的梯度等于所有相关的后一层梯度之和。

把几个阶段搞到一起

前面我们讲了RoI层的反向传播,这就让整个模型能从FC层传播到卷积层了,剩下的就是把SVM分类器和bbox回归整到一起就大功告成了。

这里写图片描述

多任务损失(Multi-task loss)

Fast R-CNN在FC层后有两个分支,一个是SVM分类器,一个是bbox回归。
这里直接给结论,论文把这两个分支的损失弄到一起:

L(p,u,tu,v)=Lcls(p,u)+λ[u1]Lloc(tu,v)

Lcls(p,u) 是一个分支softmax层输出概率分布: p=(p0,...,pk) ,这是一个K个分类,加上1个背景的softmax层。

λ[u1]Lloc(tu,v) 另一个分支bbox回归的位移: tk=(tkx,tky,tkw,tkh) ,k表示类别,这里对于bbox回归的loss,是一个K个输出的regressor.每个类别都会训练出一个回归器,且这里的回归器用的损失函数为:

Lloc(tu,v)=i{x,y,w,h}smoothL1(tuivi)

其中
smoothL1(x)={0.5x2    if|x|<1|x|0.5  otherwise

使用 L1 正则损失的原因是对outliers(离群点)的敏感度低,模型更具有鲁棒性。

R**oI层加上多任务损失函数,把除了proposal以外的整个模型整到一起了,大家可以一起训练了,没有特征存/取硬盘的操作,整个训练和测试过程又全线提速了!**

Fast R-CNN的训练技巧

预训练网络

SGD的样本选取

这里针对fine-tuning阶段指出了SPPNet存在的问题。

SPPNet在使用BP算法训练效率低的原因:

  • 每个训练样本来自于不同的图片.
  • The inefficiency stems from the fact that each RoI may have a very large receptive field, often spanning the entire input image. Since the forward pass must process the entire receptive field, the training inputs are large (often the entire image).

SPPNet只能微调SPP层后面的全连接层,再采用SGD方法训练的过程中,而SPPNet的会在多张图片上选取候选区域,这里在反向传播的过程中会大量耗费内存和时间

在Fast R-CNN的做法:

Fast R-CNN采用SGD训练,每次采样在N个图片的基础上选取R个候选区域,实验选取的N=2,R=128.这样样本数据来自与2张图片,这比R-CNN和SPPNet选取的样本在训练速度上快了很多倍

这里存在一个问题,训练样本大多数取自同一张图片,样本之前关联性很大,这可能会造成训练不收敛,但是在论文的实验过程中,没有出现这种情况,所以就采用这个方法了

小批量采样(Mini-batch sampling)

在网络微调,每个SGD mini-batch是由N=2,R=128,首先加入N张完整图片,而后加入从N张图片中选取的R个候选框。从object proposal中选25%的RoI,就是和ground-truth的IoU至少为0.5的。剩下的75%取IoU至少为在0.1到0.5的样本作为背景。

N张完整图片以50%概率水平翻转。 R个候选框的构成方式如下:

类别比例方式
正例25%与Ground-Truth的IoU大于0.5
反例75%与Ground-Truth的IoU在0.1到0.5之间

使用奇异值分解为FC层提速(Truncated SVD for Fast detection)

在检测过程中,因为要处理的RoIs较多,几乎过半的时间都耗费在FC层的计算上了,这里是用SVD分解加速FC层的计算。

我们对一组尺寸 u×v 的权重矩阵 W 可分解为:使用t个特征值.

WUΣtVT=U(:,1:t)Σ(1:t,1:t)V(:,1:t)T

将原来的前向传播分为两步,降低了计算复杂度:

y=Wxy=(UΣtVT)x=Uz

计算复杂度从 u×v 变为 u×t+v×t

在实现时,相当于把一个全连接层拆分成两个,中间以一个低维数据相连。

这里写图片描述

到此,Fast R-CNN的算是分析完了,论文中还有很多实验细节,有兴趣的可以看看。



Faster R-CNN

15年,Kaiming He男神和Rgb大神强强联手,整个了这个R-CNN的最终版Fast R-CNN

Introduction

从RCNN到Fast R-CNN,再到本文的Faster R-CNN,目标检测的四个基本步骤(候选区域生成,特征提取,分类,位置精修)终于被统一到一个深度网络框架之内。剔除了大部分的计算冗余,大部分训练过程在GPU中完成,进一步提高了运行速度。

这里写图片描述

Faster R-CNN主要用两个模块组成:

  • 第一个模块是深层的全卷积网络用于区域推荐
  • 第二个模块是Fast R-CNN detector.

Faster R-CNN可以看做”区域生成网络+fast R-CNN”的系统,用区域生成网络代替Fast-RCNN中的Selective Search方法,来产生一堆候选区域。

本篇论文着重解决了下面问题:

  1. 如何设计/训练 区域生成网络
  2. 如何整合区域生成网络和Fast R-CNN网络共享特征提取网络

侯选区域生成网络

为什么要整出来侯选区域生成网络?

当前检测网络最耗时的地方在proposals选取。现在用的最多的时Selective Search,这在测试过程中会耗费较多的时间。

我们可以注意到,CNN在GPU上有着计算优势,有一个很直接的想法就是候选区域算法能从CPU上移植到GPU上,这是一个好的工程想法,但是这样的做法忽略了共享计算的可能.

论文提出了使用CNN来推荐候选区域,称之为RPNs(Region Proposal Networks)。作者观察到区域检测器(例如Fast R-CNN)的卷积层后的特征映射(feature map)可用户RPNs生成侯选区域.在特征映射的基础上向后添加几层卷积层构成区域推荐网络。这是一个FCN(fully convolutional network,全卷积网络).

这里写图片描述

侯选区域生成网络架构

RPN网络基本设想是:在提取好的特征图上,通过一个滑动窗口获取特征向量,然后输出到两个全连接层:

  • 一个是box-regression layer(reg)
  • 另一个是 box-classification layer(cls).

这里写图片描述

上图中可以看到,在feature map上会有一个sliding window,这个sliding window会遍历feature map上的每一个点,并且在每个点上配置k个anchor boxes。

这k个anchor boxes就是用于提取feature map上的特征,但是这样提取出来效果不是很好,所以后面会接一个分类器和一个bbox回归,这样就能修正检测位置了。

这里写图片描述

侯选区域生成网络(Region Proposal Networks,RPN),RPN网络接收任意大小的图片作为输入,输出一组目标侯选矩形框,并带有目标分数.

下面详细介绍一下anchor boxes的概念。

Anchors

在每一个滑动窗口的位置,我们同时预测k个推荐区域,故reg层有4k个输出(每个侯选区域是一个元素个数为4的元组)。cls层输出2k个得分(即对每个推荐区域是目标/非目标的估计概率)

k个推荐区域对应着k个参考框的参数形式,我们称之为anchors.每个anchor以当前滑动窗口的中心为中心,并与尺度和长宽比相关。默认地我们使用3种尺度和3种长宽比,对于每个滑动位置就有k=9个anchor。对于大小为 W×H (例如2,400)的卷积特征映射,总共有 WHk 个anchor。

这里写图片描述

特征可以看做一个尺度51*39的256通道图像,对于该图像的每一个位置,考虑9个可能的候选窗口:三种面积 {1282,2562,5122}× 三种长宽比例 {1:1,1:2,2:1} , 下图示出51*39个anchor中心,以及9种anchor示例。

这里写图片描述

分类层(cls_score)输出每一个位置上,9个anchor属于前景和背景的概率;窗口回归层(bbox_pred)输出每一个位置上,9个anchor对应窗口应该平移缩放的参数。
对于每一个位置来说,分类层从256维特征中输出属于前景和背景的概率;窗口回归层从256维特征中输出4个平移缩放参数。

就局部来说,这两层是全连接网络;就全局来说,由于网络在所有位置(共51*39个)的参数相同,所以实际用尺寸为1×1的卷积网络实现。

需要注意的是:并没有显式地提取任何候选窗口,完全使用网络自身完成判断和修正。

侯选区域生成网络的训练

训练数据

对每个anchor给定标签选项,认定两种anchors为正样本:

  • anchor/anchors与ground-truth box有着最高的IoU记为正样本
  • 剩下的anchor/anchors与任何ground-truth box的IoU大于0.7记为正样本,IoU小于0.3,记为负样本
  • 剩下的anchor/anchors记为非正样本,对训练没有贡献,不使用

同一个ground-truth可以确定多个anchors.

损失函数

这里使用的损失函数和Fast R-CNN内的损失函数原理类似,同时最小化两种代价:

L({pi},{ti})=1NclsiLcls(pi,pi)+λ1NregipiLreg(ti,ti)

  • RPN可以BP算法和SGD算法完成end-to-end训练。每个mini-batch的数据包含着一张图片上的多个正样本和负样本。
  • 在网络参数初始化上,前面的卷积层使用预训练的ImageNet的网络参数,新添加的层使用随机的高斯分布初始化权重.
  • 在前60K的mini-batch上我们使用0.001的学习率,后20K的mini-batch上我们使用0.0001的学习率,同时使用全职衰减,momentum=0.9,weight decay=0.0005.

共享特征

RPN和Fast R-CNN都需要一个原始特征提取网络(下图灰色方框)。这个网络使用ImageNet的分类库得到初始参数W0,但要如何精调参数,使其同时满足两方的需求呢?本文讲解了三种方法。

这里写图片描述

  • Alternating training(轮流训练)

    • 先独立训练RPN,然后用这个RPN的网络权重对Fast-RCNN网络进行初始化并且用之前RPN输出proposal作为此时Fast-RCNN的输入训练Fast R-CNN
    • 用Fast R-CNN的网络参数去初始化RPN
    • 交换a,b训练过程即可

    具体操作时,仅执行两次迭代(后面再迭代,效果没啥大的提升),并在训练时冻结了部分层。

  • Approximate joint training(近似联合训练)
    这里写图片描述

    直接在上图结构上训练。proposals是由中间的RPN层输出的,而不是从网络外部得到。需要注意的一点,名字中的”approximate”是因为反向传播阶段RPN产生的cls score能够获得梯度用以更新参数,但是proposal的坐标预测则直接把梯度舍弃了,这个设置可以使backward时该网络层能得到一个解析解,能将训练时间减少20%-25%。(这里照搬别人的blog,自己没看懂晓雷)。

  • Non-approximate training(联合训练)

    直接在上图结构上训练,上面的Approximate joint training把proposal的坐标预测梯度直接舍弃,所以被称作approximate,那么理论上如果不舍弃是不是能更好的提升RPN部分网络的性能呢?作者把这种训练方式称为“ Non-approximate joint training”,论文没有对这个方法进行讨论。

后面的网络和Fast R-CNN类似了,这里就不继续讨论了。

到此四篇论文算是分析结束了,后面我会实现一下Faster R-CNN,算是真刀实战的来一下。



参考资料

R-CNN,SPPNet,Fast R-CNN,Faster R-CNN等论文
cs231n课件
多个blog(引用地方已注明)

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页