记录深度学习的detection系列过程--RCNN系列

reference

做一些比较有条理的梳理,尽管网上已经有很多梳理成文的博客,不过静心沉气的理解一下也是很有必要的。方便日后在脑海里形成比较有条理的知识系统。

RCNN系列

过程

先后经历了RCNN(region proposals +CNN)—> SPP net—> Fast RCNN—> Faster RCNN —>Mask RCNN

RCNN

整体架构

记录深度学习的detection系列过程--RCNN系列_第1张图片
RCNN的整体过程如上图所示,首先是通过选择性搜索算法SS(selective serch)算法在输入图像中执行图像分割算法,在不同的色块上生成可靠的候选区域(region proposals)。大致生成2000个候选区域,然后将每个候选区域缩放成227×227的大小输入到CNN特征提取网络中,对每个候选区域的特征输入到SVM(二分类)进行分类,每个类别分别对应一个SVM分类器。接着是对图像特征进行边框回归,对区域的边界信息(x,y,h,w)进行调整。最后对每个候选区域都对应的输出检测目标的可信度,再通过非极大抑制NMS选取可能性最大的候选区域。

目标检测问题的衡量标准是重叠面积:许多分类准确的检测结果,往往因为候选框不够准确,导致重叠面积很小。故需要一个边框调整步骤。 判定为本类的候选框需要和真实矩形框重叠面积大于0.7才行。 回归器对每一类目标,使用一个线性回归器进行调整,输入为深度网络pool5层的4096维特征,输出为x, y方向的缩放和平移。

RCNN流程

记录深度学习的detection系列过程--RCNN系列_第2张图片
这里根据知乎的博文继续写文章,针对上面的图片我们觉得

  • 上诉为测试的流程图,在测试之前,需要训练好CNN特征提取网络,SVM分类器和边框回归的网络。
  • 可以在Imagnet上与训练的分类模型进行fine-tune得到CNN提取模型,CNN提取到的特征用于训练SVM分类器和边框回归器
  • 在测试阶段,把输入的SVM分类器的图像特征里候选区域里的物体进行分类,然后通过回归器调整候选框的位置。
  • 对SVM分好类的region proposals 做边框回归,边框回归是对region proposal修补的线性方法,是region proposal更加准确和包含更少的背景区域。
  • IOU的值很重要,即便是分类器分类正确,但是如果IOU值小于0.5也是会被舍弃的。

SS(selective search)选择搜索算法

传统的目标检测算法是使用滑动窗口,每滑一个窗口检测一次,相邻窗口信息重叠高,检测速度慢。R-CNN使用传统启发式方法来解决滑动窗口问题。步骤:

  • 在图像同首先分割出目标可能出现的尽可能多和尽可能少的候选区域
  • 使用聚类算法自底向上合并相邻并且特征相似的区域,最终得到2000个区域。可以得到冗余率低,召回率高的区域。
    需要知道的是,在合并过程中,基于所有产生的区域给出对应的矩形框,于是得到用于CNN特征提取的候选框。
    记录深度学习的detection系列过程--RCNN系列_第3张图片
    上图表示的是SS方法的过程,该方法没有训练过程,不需要带标注的数据,根据图像的特征自动生成候选区域。

R-CNN存在的问题

  • SS方法很耗时
  • 对于2000个region proposals均需要分别采用CNN进行卷积特征提取,计算量很大,而且对于重叠地方的卷积操作是冗余的。
  • 训练测试分成多步进行(SS—CNN—SVM—回归),在训练中都是需要独立训练的,需要保存很多中间信息。
  • CNN的输入是固定裁剪到227*227大小

SPP net(Spatial Pyramid Pooling)

对R-CNN的改进

主要的改进在于添加了一个金字塔池化层,在CNN卷积操作时,只需要一次卷积即可。很可啊。。因为对于R-CNN来说对2000个region proposals都需要进行卷积操作是很冗余和耗时的
改进的思路是:

  • 对整张图像做一个卷积运算得到特征映射
  • 在该特征映射上划分出候选区域
    先验知识
  • 对图像卷积层的可视化可以发现,图片某个位置的特征,经过卷积后该特征也会反映在特征图上相同的位置。如下图

记录深度学习的detection系列过程--RCNN系列_第4张图片
基于这个先验知识,我们可以这么操作:

  • 先使用SS得到2000个候选区域,记录每个框对应的位置
  • 对整张图像进行卷积操作,得到整个图像的feature map
  • 根据比例,将候选区域的位置映射到卷积层输出的feature map上,进行像素裁剪
  • 得到2000个候选区域的feature,再将这些特征图分别送入金字塔池化层进行进一步特征提取。
    SPP net通过上诉的方法只需要对原图进行一次卷积操作,然后得到每个区域的特征图,没有重复的卷积运算

大体结构

记录深度学习的detection系列过程--RCNN系列_第5张图片
上图的算法流程为:

  • 和R-CNN一样得到了2000个候选区域
  • 将整张图片传入CNN网络,得到通道为256的特征图
  • 根据候选区域从该特征图的对应位置提取2000个小特征图,进行金字塔池化。
金字塔池化操作如下:

 - 2000个对应的小特征图分被输入三种不同大小网格划分的池化核(4*4,2*2,1*1)
 - 每个网格进行的都是最大池化操作,不管输入特征图的长度是多少,经过池化层后都得到16+4+1=21个值
 - 所以经过SPP金字塔池化后的尺寸都为256*21的特征向量,将这个作为FC的输入进行后续操作。

由于R-CNN的FC需要固定输入的维度,所以候选区域需要先被crop或者warp到固定尺寸,在很大程度上丢失和更改了图片的原有信息导致训练的效果不好;SPP的优点在于可以直接将图像输入到CNN,在输入FC前通过SPP,SPP可以将任意尺度映射为固定维度输出,再输入到FC中,所以其一可以减少计算量,其二可以打破固定尺寸这一限制。如下图所示:
记录深度学习的detection系列过程--RCNN系列_第6张图片
这里做一下为什么可以固定输出维度,因为池化的参数ker_size和stride都是可选参数,因此当固定了输入的feture map和输出的维度大小后,可以直接根据对应的计算出pool_size和 stride.

SPP优势

  • 对整个图像进行CNN特征提取,是每个层的共享中间表示,速度显著提升
  • 适用于不同尺寸的输入图像大小,进过SPP层后都可以直接输入到FC
  • 图像特征具有更好的尺度不变性,降低训练过程中过拟合的可能性

仍然存在的问题

  • 训练仍然需要分阶段进行,需要保存很多数据
  • SS方法依旧没有改变,耗时任然比较长
  • SPP-NET在微调网络时固定了卷积层,只对全连接层进行微调,而对于一个新的任务,有必要对卷积层也进行微调

Fast R-CNN

上述的R-CNN和 SPP-net存在的统一问题在于训练pipeline的时候是隔离的,即是:提取region proposal,训练CNN,SVM,Bbox regression。

主要贡献点

  • 除去提proposals过程外,其余部分训练时end-to-end的:这说明不需要中间的磁盘空间储存暂时的特征。
  • joint training(SVM分类,BBOX回归联合在CNN训练阶段),最后一层的softmax输出两个内容,一个是对区域的分类Softmax(包含背景),另外一个是对bbox的微调。网络同样有两个输入,整张图片和候选proposals算法产生的可能proposals的坐标。联合训练同时利用了分类的监督信息和回归的监督信息,使得网络的训练更加鲁棒,效果更好。
  • 提出了一个ROI层,这相当于SPP的变种,SPP是pooling成多个固定尺度,RoI只pooling到单个固定的尺度 (论文通过实验得到的结论是多尺度学习能提高一点点mAP,不过计算量成倍的增加,故单尺度训练的效果更好)
  • 指出SPP-net训练时的不足之处,并提出新的训练方式,就是把同张图片的prososals作为一批进行学习,而proposals的坐标直接映射到conv5层上,这样相当于一个batch一张图片的所有训练样本只卷积了一次。文章提出他们通过这样的训练方式或许存在不收敛的情况,不过实验发现,这种情况并没有发生。这样加快了训练速度。 (实际训练时,一个batch训练两张图片,每张图片训练64个RoIs(Region of Interest))

需要注意的点

  • 论文并没有采用常见的二范数进行回归,而是使用了所谓鲁棒性最好的L1范数作为损失函数
  • 论文将较大的FC采用SVD分解使得检测的时候速度更快???

网络结构

  • 通用模型:

记录深度学习的detection系列过程--RCNN系列_第7张图片
记录深度学习的detection系列过程--RCNN系列_第8张图片

  • 一个具体的网络
    -记录深度学习的detection系列过程--RCNN系列_第9张图片
    从上面两个图可以看出输入的是原图和在原图上提取到的ROI 5 ∗ P 5*P 5P,其中这里的5个量分别表示一个类别加上4个BBOX的几何参数,ROI的产生还是使用的是SS。
    这里我们提出两个问题:

  • 上图的操作中我们可以看到只有原图经历了CNN的特征提取,我们要如何通过ROIs去定位到对应的原图的feature map上去呢?

  • 找到后,不同维度上的ROIs对应的特征区域的维度不一样,我们如何转化为固定额维度特征向量?

解答上面的两个问题

  • 在原图提取到的feature map中找ROI对应区域: x ′ = f l o o r ( x / S ) + 1 x'=floor(x/S)+1 x=floor(x/S)+1 (注 floor() 是向下取整,其中 x ′ x' x是ROI在feature map中的横坐标, x x x是ROI在原图中的横坐标,S是convs中所有的strides的乘积。例如下面,在ZF-5中S=222*2=16(包括conv和pool中的stride)
  • 找到ROI在feature Map中对应的区域后,再经过金字塔池化就得到了21k维(k是之前卷积 核的个数)
    Fast R-CNN中对金字塔池化进行改进,使用了其特例(只使用了一层),变成了ROI pooling。它的输入维度不定h
    w,输出维度固定H*W。只需要根据h/H和w/W来调整池化框的大小即可。H和W的设置是根据后面连接的全连接层以及之前的卷积核数量而定。这样就只经过了一次卷积,就可以获得一张图所有ROI的特征向量(当然ROI pooling还是进行多次,每个ROI进行一次)
    记录深度学习的detection系列过程--RCNN系列_第10张图片

ROI POOLing

与SPP的目的相同,都是把不同尺度的ROI映射为固定大小的特征。ROI就是特殊的SPP,它不考虑多尺度空间,只使用单个尺度。如下:
记录深度学习的detection系列过程--RCNN系列_第11张图片

具体实现

具体实现可以看做是针对ROI区域的普通整个图像feature map的Pooling,只不过不是固定尺寸的输入,因此每次的pooling网格大小需要计算。假设某个ROI区域的坐标为 ( x 1 , y 1 , x 2 , y 2 ) (x_1,y_1,x_2,y_2) (x1,y1,x2,y2),那么呢输入的size就应该是 ( y 2 − y 1 ) × ( x 2 − x 1 ) (y_2-y_1)\times(x_2-x_1) (y2y1)×(x2x1),假设需要的pooling的size为 p o o l e d h e i g h t × p o o l e d w i d t h pooledheight\times{pooledwidth} pooledheight×pooledwidth,那么每个网格的size就是 ( y 2 − y 1 ) / p o o l e d h e i g h t × ( x 2 − x 1 ) / p o o l e d w i d t h {(y_2-y_1)/pooledheight}\times{(x_2-x_1)/pooledwidth} (y2y1)/pooledheight×(x2x1)/pooledwidth

BBox regression

整个过程是先用SS等proposals提取一组bbox坐标,而后输入网络对每一个bbox所包含的对象进行预测,此时,神经网络也依然仅仅是一个图片分类工具而已,只不过是ROI区域的图像分类;然后作者进一步把bbox放入网络进行优化。因此,在Fast-rcnn中存在两个输出层,第一个是针对每个ROI的分类概率,第二个是针对每个ROI区域坐标的坐标偏移优化 ( t x k , t y k , t w k , t h k ) (t_x^k,t_y^k,t_w^k,t_h^k) (txk,tyk,twk,thk).具体的两个Loss的操作过程可以看下面我盗的图:
记录深度学习的detection系列过程--RCNN系列_第12张图片

偏移优化

假设对于一个类别 k ∗ k^* k,在图片中标注了一个ground_truth坐标: t ∗ = ( t x ∗ , t y ∗ , t w ∗ , t h ∗ ) t^*=(t_x^*,t_y^*,t_w^*,t_h^*) t=(tx,ty,tw,th),而预测值为 t = ( t x , t y , t w , t h ) t=(t_x,t_y,t_w,t_h) t=(tx,ty,tw,th).因此定义Loss:
记录深度学习的detection系列过程--RCNN系列_第13张图片
where the s m o o t h L 1 ( x ) smooth_L{_1}(x) smoothL1(x) denotes t i − t i ∗ t_i-t_i^* titi,即是对应坐标的差距。该函数在(-1,1)之间为二次函数,其他地方为线性的,这样可以做啥?可以增强对异常数据的鲁棒性。

Faster- R-CNN

reference

参考知乎的大佬回答一文读懂Faster RCNN

基本结构

记录深度学习的detection系列过程--RCNN系列_第14张图片
faster-RCNNk可以分成四部分

  • Conv layers。作为一种CNN网络目标检测方法,Faster RCNN首先使用一组基础的conv+relu+pooling层提取image的feature maps。该feature maps被共享用于后续RPN层和全连接层。
  • Region Proposal Networks。RPN网络用于生成region proposals。该层通过softmax判断anchors属于positive或者negative,再利用bounding box regression修正anchors获得精确的proposals。
  • Roi Pooling。该层收集输入的feature maps和proposals,综合这些信息后提取proposal feature maps,送入后续全连接层判定目标类别。
  • Classification。利用proposal feature maps计算proposal的类别,同时再次bounding box regression获得检测框最终的精确位置。
    下图展示了python版本中的VGG16模型中的faster_rcnn_test.pt的网络结构,可以清晰的看到该网络对于一副任意大小PxQ的图像,首先缩放至固定大小MxN,然后将MxN图像送入网络;而Conv layers中包含了13个conv层+13个relu层+4个pooling层;RPN网络首先经过3x3卷积,再分别生成positive anchors和对应bounding box regression偏移量,然后计算出proposals;而Roi Pooling层则利用proposals从feature maps中提取proposal feature送入后续全连接和softmax网络作classification(即分类proposal到底是什么object)。
    记录深度学习的detection系列过程--RCNN系列_第15张图片

Conv layers

Faster RCNN Conv layers中对所有的卷积都做了扩边处理( pad=1,即填充一圈0),导致原图变为 (M+2)x(N+2)大小,再做3x3卷积后输出MxN 。正是这种设置,导致Conv layers中的conv层不改变输入和输出矩阵大小。如下图:
记录深度学习的detection系列过程--RCNN系列_第16张图片
类似的是,Conv layers中的pooling层kernel_size=2,stride=2。这样每个经过pooling层的MxN矩阵,都会变为(M/2)x(N/2)大小。综上所述,在整个Conv layers中,conv和relu层不改变输入输出大小,只有pooling层使输出长宽都变为输入的1/2。

那么,一个MxN大小的矩阵经过Conv layers固定变为(M/16)x(N/16)!这样Conv layers生成的feature map中都可以和原图对应起来。

region proposal networks

经典的检测方法生成检测框都非常耗时,如OpenCV adaboost使用滑动窗口+图像金字塔生成检测框;或如R-CNN使用SS(Selective Search)方法生成检测框。而Faster RCNN则抛弃了传统的滑动窗口和SS方法,直接使用RPN生成检测框,这也是Faster R-CNN的巨大优势,能极大提升检测框的生成速度。
记录深度学习的detection系列过程--RCNN系列_第17张图片
RPN网络实际分为2条线,上面一条通过softmax分类anchors获得positive和negative分类,下面一条用于计算对于anchors的bounding box regression偏移量,以获得精确的proposal。而最后的Proposal层则负责综合positive anchors和对应bounding box regression偏移量获取proposals,同时剔除太小和超出边界的proposals。其实整个网络到了Proposal Layer这里,就完成了相当于目标定位的功能。

多通道图像卷积

单通道卷积的求和就可以了
记录深度学习的detection系列过程--RCNN系列_第18张图片

anchors

anchors,实际上就是一组由矩形.9个矩形共有3种形状,长宽比为大约为 w i d t h : h e i g h t = { 1 : 1 , 1 : 2 , 2 : 1 } width:height={\{ 1:1,1:2,2:1\}{}} width:height={1:1,1:2,2:1}三种,如下图。实际上通过anchors就引入了检测中常用到的多尺度方法。
记录深度学习的detection系列过程--RCNN系列_第19张图片
那么这9个anchors是做什么的呢?借用Faster RCNN论文中的原图,如下图,遍历Conv layers计算获得的feature maps,为每一个点都配备这9种anchors作为初始的检测框。这样做获得检测框很不准确,不用担心,后面还有2次bounding box regression可以修正检测框位置。
记录深度学习的detection系列过程--RCNN系列_第20张图片
上图解释如下:

  • 在原文中使用的是ZF model中,其Conv Layers中最后的conv5层num_output=256,对应生成256张特征图,所以相当于feature map每个点都是256-dimensions
  • 在conv5之后,做了rpn_conv/3x3卷积且num_output=256,相当于每个点又融合了周围3x3的空间信息(猜测这样做也许更鲁棒?反正我没测试),同时256-d不变(红框)
  • 假设在conv5 feature map中每个点上有k个anchor(默认k=9),而每个anhcor要分positive和negative,所以每个点由256d feature转化为cls=2k scores;而每个anchor都有(x, y, w, h)对应4个偏移量,所以reg=4k coordinates
  • 补充一点,全部anchors拿去训练太多了,训练程序会在合适的anchors中随机选取128个postive anchors+128个negative anchors进行训练(什么是合适的anchors下文5.1有解释)
    那么Anchor一共有多少个?原图800x600,VGG下采样16倍,feature map每个点设置9个Anchor,所以:
    在这里插入图片描述
    记录深度学习的detection系列过程--RCNN系列_第21张图片

softmax 判定positive 或者negative

一副MxN大小的矩阵送入Faster RCNN网络后,到RPN网络变为(M/16)x(N/16),不妨设 W=M/16,H=N/16。在进入reshape与softmax之前,先做了1x1卷积,如下图:
记录深度学习的detection系列过程--RCNN系列_第22张图片

layer {
  name: "rpn_cls_score"
  type: "Convolution"
  bottom: "rpn/output"
  top: "rpn_cls_score"
  convolution_param {
    num_output: 18   # 2(positive/negative) * 9(anchors)
    kernel_size: 1 pad: 0 stride: 1
  }
}

原文代码中可以看到其num_output=18,也就是经过该卷积的输出图像为WxHx18大小(注意第二章开头提到的卷积计算方式)。这也就刚好对应了feature maps每一个点都有9个anchors,同时每个anchors又有可能是positive和negative,所有这些信息都保存WxHx(9*2)大小的矩阵。为何这样做?后面接softmax分类获得positive anchors,也就相当于初步提取了检测目标候选区域box(一般认为目标在positive anchors中)。
那么为何要在softmax前后都接一个reshape layer?其实只是为了便于softmax分类,至于具体原因这就要从caffe的实现形式说起了。在caffe基本数据结构blob中以如下形式保存数据:

blob=[batch_size, channel,height,width]

对应至上面的保存positive/negative anchors的矩阵,其在caffe blob中的存储形式为[1, 2x9, H, W]。而在softmax分类时需要进行positive/negative二分类,所以reshape layer会将其变为[1, 2, 9xH, W]大小,即单独“腾空”出来一个维度以便softmax分类,之后再reshape回复原状。贴一段caffe softmax_loss_layer.cpp的reshape函数的解释,非常精辟:

"Number of labels must match number of predictions; "
"e.g., if softmax axis == 1 and prediction shape is (N, C, H, W), "
"label count (number of labels) must be N*H*W, "
"with integer values in {0, 1, ..., C-1}.";

上面的意思就是说在caffe的channel通道中必须要和label的种类数量一致。

bounding box regression原理

学习一个变换关系,即平移变换+尺度变换。
目标优化函数为:
在这里插入图片描述

对proposals进行bbox回归

在了解bounding box regression后,再回头来看RPN网络第二条线路,如图:

记录深度学习的detection系列过程--RCNN系列_第23张图片
上图中的卷积定义为:

layer {
  name: "rpn_bbox_pred"
  type: "Convolution"
  bottom: "rpn/output"
  top: "rpn_bbox_pred"
  convolution_param {
    num_output: 36   # 4 * 9(anchors)
    kernel_size: 1 pad: 0 stride: 1
  }
}

可以看到其 num_output=36,即经过该卷积输出图像为WxHx36,在caffe blob存储为[1, 4x9, H, W],这里相当于feature maps每个点都有9个anchors,每个anchors又都有4个用于回归的 [ d x ( A ) , d y ( A ) , d w ( A ) , d h ( A ) ] [d_x(A),d_y(A),d_w(A),d_h(A)] [dx(A),dy(A),dw(A),dh(A)]的变换量。
VGG输出 50 ∗ 38 ∗ 512 50*38*512 5038512 的特征,对应anchors设置 50 ∗ 38 ∗ k 50*38*k 5038k个anchors,而RPN输出:

  • 大小为 50 ∗ 38 ∗ 2 k 50*38*2k 50382k个positive/negative的softmax的分类特征矩阵
  • 大小为 50 ∗ 38 ∗ 4 k 50*38*4k 50384k的regression坐标回归矩阵

proposal layer

Proposal Layer负责综合所有回归尺度变换量和positive anchors,计算出精准的proposal,送入后续RoI Pooling Layer。还是先来看看Proposal Layer的caffe prototxt定义:

layer {
  name: 'proposal'
  type: 'Python'
  bottom: 'rpn_cls_prob_reshape'
  bottom: 'rpn_bbox_pred'
  bottom: 'im_info'
  top: 'rois'
  python_param {
    module: 'rpn.proposal_layer'
    layer: 'ProposalLayer'
    param_str: "'feat_stride': 16"
  }
}

Proposal Layer有3个输入:positive vs negative anchors分类器结果rpn_cls_prob_reshape,对应的bbox reg的变换量rpn_bbox_pred,以及im_info;另外还有参数feat_stride=16,这和图4是对应的。
首先解释im_info。对于一副任意大小PxQ图像,传入Faster RCNN前首先reshape到固定MxN,im_info=[M, N, scale_factor]则保存了此次缩放的所有信息。然后经过Conv Layers,经过4次pooling变为WxH=(M/16)x(N/16)大小,其中feature_stride=16则保存了该信息,用于计算anchor偏移量。
Proposal Layer forward(caffe layer的前传函数)按照以下顺序依次处理:

  • 生成anchors,利用回归矩阵对所有的anchors做bbox regression回归(这里的anchors生成和训练时完全一致)
  • 按照输入的positive softmax scores由大到小排序anchors,提取前pre_nms_topN(e.g. 6000)个anchors,即提取修正位置后的positive anchors。
  • 限定超出图像边界的positive anchors为图像边界(防止后续roi pooling时proposal超出图像边界)
  • 剔除非常小(width
  • 进行nonmaximum suppression
  • Proposal Layer有3个输入:positive和negative anchors分类器结果rpn_cls_prob_reshape,对应的bbox reg的(e.g. 300)结果作为proposal输出。
    之后输出proposal=[x1, y1, x2, y2],注意,由于在第三步中将anchors映射回原图判断是否超出边界,所以这里输出的proposal是对应MxN输入图像尺度的,这点在后续网络中有用。另外我认为,严格意义上的检测应该到此就结束了,后续部分应该属于识别了。
    RPN网络结构就介绍到这里,总结起来就是:
    生成anchors -> softmax分类器提取positvie anchors -> bbox reg回归positive anchors -> Proposal Layer生成proposals

ROI Pooling

h和前文中fast-rcnn一致。

Classification

Classification部分利用已经获得的proposal feature maps,通过full connect层与softmax计算每个proposal具体属于那个类别(如人,车,电视等),输出cls_prob概率向量;同时再次利用bounding box regression获得每个proposal的位置偏移量bbox_pred,用于回归更加精确的目标检测框。Classification部分网络结构如下图。
记录深度学习的detection系列过程--RCNN系列_第24张图片
从RoI Pooling获取到7x7=49大小的proposal feature maps后,送入后续网络,可以看到做了如下2件事:

  • 通过全连接和softmax对proposals进行分类,这实际上已经是识别的范畴了
  • 再次对proposals进行bounding box regression,获取更高精度的rect box

Mask-RCNN

前文已经介绍了fast-RCNN的具体改进,而把fast-RCNN和FPN结合就是对应的Faster-RCNN算法了,这里我们先介绍FPN。

FPN

引入

FPN(Feature Pyramid Network)是一种精心设计的多尺度检测算法。主要用于目标检测中的多尺度问题,对于图像中较小和较大的物体在卷积层的不同feature特征进行检测。我们知道网络的感受野和stride通常是很矛盾的,因为一般网络结构的对应stride都是比较大的,而图像中的小物体可能比stride还小,为解决这个问题,传统上采用的方法包括:

  • 多尺度训练和测试,成为图像金字塔,下图(a)所表示的那样,每一个层的像素都进行对应的学习,目前ImageNet和COCO上的比赛效果好的几乎都是采用了这种的训练方式,不过这种方式带来的问题是会很耗时和空间。
    记录深度学习的detection系列过程--RCNN系列_第25张图片
  • 第二一种解决办法是进行特征分层。即每层分别对同样的scale进行预测,也就是说每一层预测的是同样的语义信息,学习的也是同样的语义信息,这会出现一个什么样的问题呢。也就是我们知道对于浅层神经网路来说,它保留了比较细节的信息,为细节特征,而深层网路含有比较小的分辨率,对应着比较大的信息,更多的是语义特征。

结合上文中所所说的两点解决办法,我们看出存在问题为:

  • 如何学习具有较强语义信息的多尺度特征表示。
  • 如何设计通用的特征来解决物体检测中的多个子问题?
  • 如何高效的计算多尺度特征表示?

针对上述问题,FPN(上图(d))所示的过程,在原来的网络上做修改:每个分辨率的feature map引入后一分辨率缩放两倍的feature map做element-wise相加操作。如此,每层分辨率的feature map都融合了不同分辨率和不同语义轻度的特征,融合后的不同分辨率的feature map 分别做对应的物体检测,这样就保留了每一层都具有合适的分辨率以及强语义特征。同时,计算量也小。

结构

记录深度学习的detection系列过程--RCNN系列_第26张图片
FPN结构中包含自下而上,自上而下和横向连接三个部分,如上图所示,这个结构可以把各个层级进行特征融合。FPN是一种通用的框架,可以结合各种骨架网络使用,例如VGG和resnet,在Mask RCNN文章中使用了ResNNet-FPN网络结构,如下图:
记录深度学习的detection系列过程--RCNN系列_第27张图片
上图的Resent-PFN包括有三部分,自下而上连接,自上而下连接以及横向连接。

自下而上(bottom-up)

和普通的特征提取没有区别,就是这个是采用的Resent网络特征结构,根据feature map 的分辨率可以得到5个stage,stage2,stage3,stage4和stage5各自最后一层输出conv2,conv3,conv4和conv5分别定义为 C 2 , C 3 , C 4 , C 5 C_2,C_3,C_4,C_5 C2,C3,C4,C5,他们相对于原始图片的stride是{4,8,16,32}。需要注意的是,考虑到内存原因,stage1的conv1并没有使用。

自上而下和横向连接(up-down)

自上而下是从最高层开始进行上采样,这里的上采样直接使用的是最近邻上采样,而不是使用反卷积操作,一方面简单,另外一方面可以减少训练参数。(何为反卷积?如何训练参数)
记录深度学习的detection系列过程--RCNN系列_第28张图片
横向连接则是将上采样的结果和自底向上生成的相同大小的feature map进行融合。具体就是对 C 1 , C 2 , C 3 , C 4 C_1,C_2,C_3,C_4 C1,C2,C3,C4中的每一层经过一个conv 1x1操作**(1x1卷积用于降低通道数)**,无激活函数操作,输出通道全部设置为相同的256通道,然后和上采样的feature map进行加和操作,在融合之后还会再采用3*3的卷积核对已经融合的特征进行处理,目的是消除上采样的混叠效应(aliasing effect)。

总结一下,ResNet-FPN作为RPN输入的feature map是 P 2 , P 3 , P 4 , P 5 , P 6 P2,P3,P4,P5,P6 P2,P3,P4,P5,P6,而作为后续Fast RCNN的输入则是 P 2 , P 3 , P 4 , P 5 P2,P3,P4,P5 P2,P3,P4,P5

ResNet-FPN+Fast RCNN== Faster RCNN(只选用一个feature map)

记录深度学习的detection系列过程--RCNN系列_第29张图片
将ResNet-FPN和Fast RCNN进行结合,实际上就是Faster RCNN的了,但与最初的Faster RCNN不同的是,FPN产生了特征金字塔 [ P 2 , P 3 , P 4 , P 5 , P 6 ] [P2,P3,P4,P5,P6] [P2,P3,P4,P5,P6]而并非只是一个feature map。金字塔经过RPN之后会产生很多region proposal,这些region proposal是分别由 [ P 2 , P 3 , P 4 , P 5 , P 6 ] [P2,P3,P4,P5,P6] [P2,P3,P4,P5,P6]经过RPN产生的,但用于输入到Fast RCNN中的是 [ P 2 , P 3 , P 4 , P 5 ] [P2,P3,P4,P5] [P2,P3,P4,P5] ,也就是说要在 [ P 2 , P 3 , P 4 , P 5 ] [P2,P3,P4,P5] [P2,P3,P4,P5]中根据region proposal切出ROI进行后续的分类和回归预测。**问题来了,我们要选择哪个feature map来切出这些ROI区域呢?**实际上,我们会选择最合适的尺度的feature map来切ROI。具体来说,我们通过一个公式来决定宽w和高h的ROI到底要从哪个[ P K P_K PK来切:
在这里插入图片描述
这里224表示用于预训练的ImageNet图片的大小, k 0 k_0 k0表示面积为 224 ∗ 224 224*224 224224的ROI所应该在的层级。作者将 k 0 k_0 k0设置为4,也就是说 w ∗ h = 224 ∗ 224 w*h=224*224 wh=224224的ROI应该从 P 4 P_4 P4 中切出来。假设ROI的scale小于224(比如说是112 * 112), k = k 0 − 1 = 3 k=k_0 -1=3 k=k01=3,就意味着要从更高分辨率的 P 3 P_3 P3 中产生。另外, k k k值会做取整处理,防止结果不是整数。
这种做法很合理,大尺度的ROI要从低分辨率的feature map上切,有利于检测大目标,小尺度的ROI要从高分辨率的feature map上切,有利于检测小目标。

ResNet-FPN+Fast RCNN+mask

我们再进一步,将ResNet-FPN+Fast RCNN+mask,则得到了最终的Mask RCNN,如下图:
记录深度学习的detection系列过程--RCNN系列_第30张图片
Mask RCNN的构建很简单,只是在ROI pooling(实际上用到的是ROIAlign,后面会讲到)之后添加卷积层,进行mask预测的任务。
下面总结一下Mask RCNN的网络:

  • 骨干网络ResNet-FPN,用于特征提取,另外,ResNet还可以是:ResNet-50,ResNet-101,ResNeXt-50,ResNeXt-101;
  • 头部网络,包括边界框识别(分类和回归)+mask预测。头部结构见下图:
    记录深度学习的detection系列过程--RCNN系列_第31张图片

ROI Align

实际上,Mask RCNN中还有一个很重要的改进,就是ROIAlign。Faster R-CNN存在的问题是:特征图与原始图像是不对准的(mis-alignment),所以会影响检测精度。而Mask R-CNN提出了RoIAlign的方法来取代ROI pooling,RoIAlign可以保留大致的空间位置。为了讲清楚ROI Align,这里先插入两个知识,双线性插值和ROI pooling。

双线性插值

双线性插值本质上就是在两个方向上做线性插值。
记录深度学习的detection系列过程--RCNN系列_第32张图片
如图,假设我们想得到P点的插值,我们可以先在x方向上,对 Q 1 1 Q_11 Q11 Q 2 1 Q_21 Q21之间做线性插值得到 R 1 R_1 R1 R 2 R_2 R2 同理可得。然后在y方向上对 R 1 R_1 R1 R 2 R_2 R2进行线性插值就可以得到最终的 P P P

ROI Pooing

这就是fast-rcnn的了。不过多解释。

下面回到ROI Align当中。
在Faster RCNN中,有两次整数化的过程:

  • region proposal的xywh通常是小数,但是为了方便操作会把它整数化。
  • 将整数化后的边界区域平均分割成 k x k 个单元,对每一个单元的边界进行整数化。

记录深度学习的detection系列过程--RCNN系列_第33张图片
两整数化的过程如上图所示。事实上,经过上述两次整数化,此时的候选框已经和最开始回归出来的位置有一定的偏差,这个偏差会影响检测或者分割的准确度。在论文里,作者把它总结为“不匹配问题”(misalignment)。为了解决这个问题,ROI Align方法取消整数化操作,保留了小数,使用以上介绍的双线性插值的方法获得坐标为浮点数的像素点上的图像数值。但在实际操作中,ROI Align并不是简单地补充出候选区域边界上的坐标点,然后进行池化,而是重新进行设计。
下面通过一个例子来讲解ROI Align操作。如下图所示,虚线部分表示feature map,实线表示ROI,这里将ROI切分成2x2的单元格。如果采样点数是4,那我们首先将每个单元格子均分成四个小方格(如红色线所示),每个小方格中心就是采样点。这些采样点的坐标通常是浮点数,所以需要对采样点像素进行双线性插值(如四个箭头所示),就可以得到该像素点的值了。然后对每个单元格内的四个采样点进行maxpooling,就可以得到最终的ROIAlign的结果。
记录深度学习的detection系列过程--RCNN系列_第34张图片

损失函数

Mask RCNN定义多任务损失:
L = L c l s + L b o x + L m a s k L=L_{cls}+L_{box}+L{mask} L=Lcls+Lbox+Lmask

你可能感兴趣的:(CV-Detection)