小言_互联网的博客

faster-RCNN论文解析

387人阅读  评论(0)

为了增加自己的理解,本文会从论文的理解和代码的解析两个方面来阐述。

一、概述

在目标检测领域,faster-RCNN表现出了极强的生命力,是现在很多目标算法的基础,尤其是其核心算法,RPN网络更是很多优秀的检测算法的基础。
网络上有很多优秀的论文解读的博客,本文也是以它们作为一个参考,然后再尽力配合一些编程方面的讲解。在编程方面,本文以VGG-16为例。

1、1目标

从编程的角度的来说,以faster-RCNN 为代表的Object Detection任务,可以描述成:给定一张图片,找出图中有哪些对象,以及这些对象的位置和置信度概率。



图1 task of Object Detection 示意图

1.2 整体架构



图2 faster-RCNN基本结构图

上图可以清晰的看到对于我们的faster-RCNN来说,整个的模型包含4个部分:

  • Conv layers:作为一种CNN网络目标检测的方法,Faster-RCNN首先使用一组基础的conv+relu+Pooling层来提取image的feature map。该feature maps被共享用于后续RPN层和全连接层。
  • Region Proposal Networks:RPN网络作为faster-RCNN的核心,用于生成region proposals。该层会通过softmax判断anchors属于positive还是negative,再利用bounding box regesssion修正anchors获得较精确的proposals。
  • Roi Pooling。该层负责收集输入的feature maps和proposals,综合这些信息后提取proposal feature maps,送入后续全连接层判定目标类别。
  • Classification。利用proposal feature maps计算proposal的类别,同时再次bounding box regression获得检测框最终的精确位置。


图3 faster-RCNN网络结构图
上图清晰的阐述了Faster-RCNN(VGG-16模型)的整体的网络架构,我们可以看到,对于任意大小的输入图片,首先会缩放至M*N,然后将图片输入网络,也就是说网络的输入的大小是固定的。而Conv layers中包含了13个conv层+13个relu层+4个pooling层;RPN网络首先经过3x3卷积,然后经过两个1*1的卷积核,分别进行positive/negative anchors的判断和生成对应的bounding box regression偏移量,然后计算出proposals;而Roi Pooling层则利用proposals从feature maps中提取proposal feature送入后续全连接层和softmax网络作classification(即分类proposal到底是什么object)。 #### 二、Conv layers Conv layers包含了conv,pooling,relu三种层。以python版本中的VGG16模型中的faster_rcnn_test.pt的网络结构为例,如图2,Conv layers部分共有13个conv层,13个relu层,4个pooling层。这里有一个非常容易被忽略但是又无比重要的信息,在Conv layers中:
  1. 所有的conv层都是:kernel_size=3,pad=1,stride=1
  2. 所有的Pooling层都是:kernel_size=2,pad=0,stride=2
    为什么说它重要,在Faster RCNN Conv layers中对所有的卷积都做了扩边处理( pad=1,即填充一圈0),导致原图变为 (M+2)x(N+2)大小,再做3x3卷积后输出MxN 。正是这种设置,导致Conv layers中的conv层不改变输入和输出矩阵大小。如图4:

图4 卷积示意图
类似的是,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中都可以和原图对应起来。 在代码的实现方面,特征提取使用的是预训练好的模型提取图片的特征。论文中主要使用的是 Caffe 的预训练模型 VGG16。修改如下图所示:为了节省显存,前四层卷积层的学习率设为 0。Conv4_3 的输出作为图片特征(feature)。conv4_3 相比于输入,下采样了 16 倍,也就是说输入的图片尺寸为 3×M×N,那么feature的尺寸就是 C×(M/16)×(N/16)。VGG 最后的三层全连接层的前两层,一般用来初始化 RoIHead 的部分参数,这个我们稍后再讲。总之,一张图片,经过特征提取之后,会得到一个 C×(M/16)×(N/16) 的 features map。

图5 Extractor结构图

三、RPN网路

RPN网络作为faster-RCNN最为突出的贡献,将候选区域提取的时间开销几乎降为0(2s->0.01s)。


图6 RPN网络结构图
图6展示了RPN网络的具体结构。可以看到RPN网络实际分为2条线,上面一条通过softmax分类anchors获得positive和negative分类,下面一条用于计算对于anchors的bounding box regression偏移量,以获得精确的proposal。而最后的Proposal层则负责综合positive anchors和对应bounding box regression偏移量获取proposals,同时剔除太小和超出边界的proposals。其实整个网络到了Proposal Layer这里,就完成了相当于目标定位的功能。
3.1 多通道图像卷积基础知识介绍

在介绍RPN之前,稍微说一下几个小的基础知识,已经懂得大佬们跳过就好~
1、对于单通道图像+单卷积核做卷积,图4已经展示了;
2、对于多通道图像+多卷积核做卷积,计算方式如下

图7 多通道卷积示意图
输入有3个通道,同时有2个卷积核。对于每个卷积核,先在输入的3个通道上,分别作卷积,再将3个通道结果加起来得到卷积输出。所以对于某个卷积层,无论输入图像有多少个通道,输出图像通道数总是等于卷积核数量! 对多通道图像做1x1卷积,其实就是将输入图像于每个通道乘以卷积系数后加在一起,即相当于把原图像中本来各个独立的通道“联通”在了一起。
3.2 anchors

提到RPN网络,就不能不说anchors。所谓anchors,实际上就是一组矩形,是大小和尺寸固定的候选框,论文中用到的 anchor 有三种尺寸和三种比例,如下图所示,三种尺寸分别是小(蓝 128)中(红 256)大(绿 512),三个比例(width:height)分别是 1:1,1:2,2:1。3×3 的组合总共有 9 种 anchor。


图8 anchors示意图

借用Faster-RCNN论文中的原图来说明这9个anchors是用来做什么的。用这 9 种 anchor 在特征图(feature map)左右上下移动,每一个特征图上的点都有 9 个 anchor,最终生成了 (H/16)× (W/16)×9 个anchor. 对于一个 512×50×38 的 feature map,有 50×38×9~ 17100个 anchor。 也就是对一张图片,有 17100个左右的 anchor。这种做法很像是暴力穷举,17100个 anchor,哪怕是蒙也能够把绝大多数的 ground truth bounding boxes 蒙中。


图9 anchors操作示意图

  1. 在原文中使用的是ZF model中,其Conv Layers中最后的conv5层num_output=256,对应生成256张特征图,所以相当于feature map每个点都是256 dimensions。
  2. 在conv5之后,做了rpn_conv/3x3卷积且num_output=256,相当于每个点又融合了周围3x3的空间信息(没有想通这个地方是为什么~~欢迎大佬指教),同时256 d不变。
  3. 假设在conv5 feature map中每个点上有k个anchor(默认k=9),而每个anhcor要分positive和negative,所以每个点由256d feature转化为cls=2k scores;而每个anchor都有(x, y, w, h)对应4个偏移量,所以reg=4k coordinates。
  4. 补充一点,全部anchors拿去训练太多了,训练程序会在合适的anchors中随机选取128个postive anchors+128个negative anchors进行训练。

注意,在本文讲解中使用的VGG conv5 num_output=512,所以是512d,其他类似。
其实RPN最终就是在原图尺度上,设置了密密麻麻的候选Anchor。然后用cnn去判断哪些Anchor是里面有目标的positive anchor,哪些是没目标的negative anchor。所以,仅仅是个二分类而已!
来一张精华图,

图10 Gernerate Anchors

##### 3.3 softmax判定positive与negative 一副MxN大小的矩阵送入Faster RCNN网络后,到RPN网络变为(M/16)x(N/16),不妨设 W=M/16,H=N/16。在进入reshape与softmax之前,先做了1x1卷积,如图11: ![alt](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9waWM0LnpoaW1nLmNvbS84MC92Mi0xYWI0YjZjM2RkNjA3YTUwMzViNTIwM2M3NmIwNzhmM19oZC5qcGc?x-oss-process=image/format,png#pic_center)
图11 RPN判定positive/negative网络结构

该1x1卷积的caffe prototxt定义如下:
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}.";

综上所述,RPN网络中利用anchors和softmax初步提取出positive anchors作为候选区域(另外也有实现用sigmoid代替softmax,原理类似)。

3.4 对proposals进行bounding box regression

说完RPN网络的第一条线,我们再来看一下它的下面的这条线,如图13

图11 RPN中的bbox_reg
先来看一看上图中1x1卷积的caffe prototxt定义:
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)] 变换量。
也就是说,假设VGG的输出是50x38x512的特征,那么对应的设置50x38xk个anchors,而RPN输出:
 1、大小为50x38x2k的positive or negative softmax分类特征矩阵
 2、大小为50x38x4k的regression坐标回归特征矩阵
恰好满足RPN完成positive/negative分类+bounding box regression坐标回归.

3.5 RPN生成Rols

Proposal Layer负责综合所有 [ d x ( A ) , d y ( A ) , d w ( A ) , d h ( A ) ] [d_x(A),d_y(A),d_w(A),d_h(A)] 变换量和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个输入:
1、positive/negative anchors分类器结果rpn_cls_prob_reshape
2、对应的bbox reg的 [ d x ( A ) , d y ( A ) , d w ( A ) , d h ( A ) ] [d_x(A),d_y(A),d_w(A),d_h(A)] 变换量rpn_bbox_pred,
3、im_info
另外还有参数feat_stride=16。
首先解释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的前传函数)按照以下顺序依次处理:

  1. 生成anchors,利用 [ d x ( A ) , d y ( A ) , d w ( A ) , d h ( A ) ] [d_x(A),d_y(A),d_w(A),d_h(A)] 对所有的anchors做bbox regression回归(这里的anchors生成和训练时完全一致)
  2. 按照输入的positive softmax scores由大到小排序anchors,提取前pre_nms_topN(e.g. 6000)个anchors,即提取修正位置后的positive anchors。
  3. 限定超出图像边界的positive anchors为图像边界(防止后续roi pooling时proposal超出图像边界)
  4. 剔除非常小(width<threshold or height<threshold)的positive anchors
  5. 进行nonmaximum suppression
  6. Proposal Layer有3个输入:positive和negative anchors分类器结果rpn_cls_prob_reshape,对应的bbox reg的(e.g. 300)结果作为proposal输出。

这里需要留意的地方是,在第三步中,将anchors映射会原图判断是否超出了边界,所有输出的proposal= [ x 1 , y 1 , x 2 , y 2 ] [x_1,y_1,x_2,y_2] 是相对于MxN的输入的图像尺度的,这一点会在后续的网络中使用。原则来说,检测的任务就到此为止啦,后续的内容应该是属于分类任务。

RPN 的使命就结束啦,然后总结起来的话就是:
生成anchors -> softmax分类器提取positvie anchors -> bbox reg回归positive anchors -> Proposal Layer生成proposals

三、Rol Pooling

RoI Pooling层则负责收集proposal,并计算出proposal feature maps,送入后续网络。从图3中可以看到Rol pooling层有2个输入:

  • 原始的feature maps
  • RPN输出的proposal boxes(大小各不相同)
3.1为何需要Rol Pooling

先来看一个问题:对于传统的CNN(如AlexNet和VGG),当网络训练好后输入的图像尺寸必须是固定值,同时网络输出也是固定大小的vector or matrix。如果输入图像大小不定,这个问题就变得比较麻烦。有2种解决办法:

  • 从图像中crop一部分传入网络
  • 将图像warp成需要的大小后传入网络
图12 crop与warp破坏图像原有结构信息
两种办法的示意图如图12,可以看到无论采取那种办法都不好,要么crop后破坏了图像的完整结构,要么warp破坏了图像原始形状信息。而我们的RPN网络生成proposals的方法,对positive anchors进行bounding box regression,那么这样获得的proposals也是大小和形状各不相同的,也会存在上述的问题,所以faster-RCNN中提出使用Rol Pooling来解决这个问题。
3.2 Rol Pooling原理

先来看看RoI Pooling Layer的caffe prototxt的定义:

layer {
  name: "roi_pool5"
  type: "ROIPooling"
  bottom: "conv5_3"
  bottom: "rois"
  top: "pool5"
  roi_pooling_param {
    pooled_w: 7
    pooled_h: 7
    spatial_scale: 0.0625 # 1/16
  }
}

其中有新参数pooled_w和pooled_h,还有一个参数spatial_scale。RoI Pooling layer forward过程:

  • 由于proposal是对应MXN尺度的,所以首先使用spatial_scale参数将其映射回(M/16)X(N/16)大小的feature map尺度;
  • 再将每个proposal对应的feature map区域水平分为 pooled_w x pooled_h的网格;
  • 对网格的每一份都进行max pooling处理。
    这样处理后,即使大小不同的proposal输出结果都是 pooled_w x pooled_h固定大小,实现了固定长度输出。
图13 proposal示意图

四、Classification

Classification部分利用已经获得的proposal feature maps,通过full connect层与softmax计算每个proposal具体属于那个类别(如人,车,电视等),输出cls_prob概率向量;同时再次利用bounding box regression获得每个proposal的位置偏移量bbox_pred,用于回归更加精确的目标检测框。Classification部分网络结构如图16。

图14 Classification部分网络结构图

从RoI Pooling获取到7x7=49大小的proposal feature maps后,送入后续网络,可以看到做了如下2件事:
1.通过全连接和softmax对proposals进行分类,这实际上已经是识别的范畴了
2.再次对proposals进行bounding box regression,获取更高精度的rect box
这里来看看全连接层InnerProduct layers,简单的示意图如图15,

图15 全连接示意图

其计算公式如下:

其中W和bias B都是预先训练好的,即大小是固定的,当然输入X和输出Y也就是固定大小。所以,这也就印证了之前Roi Pooling的必要性。到这里,我想其他内容已经很容易理解,不在赘述了。

到这里整个的关于faster-RCNN的网络结构就已经阐述完啦,接下来讲一下faster-RCNN的训练,在原论文中也花了大量的篇幅来阐述其训练的过程。

五、Faster-RCNN训练

Faster R-CNN的训练,是在已经训练好的model(如VGG_CNN_M_1024,VGG,ZF)的基础上继续进行训练。实际中训练过程分为6个步骤:

  1. 在已经训练好的model上,训练RPN网络。
  2. 利用步骤1中训练好的RPN网络,收集proposals
  3. 第一次训练Fast RCNN网络
  4. 第二训练RPN网络
  5. 再次利用步骤4中训练好的RPN网络,收集proposals
  6. 第二次训练Fast RCNN网络

可以看到训练过程类似于一种“迭代”的过程,不过只循环了2次。至于只循环了2次的原因是应为作者提到:“A similar alternating training can be run for more iterations, but we have observed negligible mprovements”,即循环更多次没有提升了。接下来本章以上述6个步骤讲解训练过程。

图16 Faster-RCNN网络训练流程图
5.1RPN网络训练

RPN的总体的架构如下所示:


图17 RPN网络总体架构图
anchor 的数量和 feature map 相关,不同的 feature map 对应的 anchor 数量也不一样。RPN 在Extractor输出的 feature maps 的基础之上,先增加了一个卷积,然后利用两个 1x1 的卷积分别进行二分类(是否为正样本)和位置回归。进行分类的卷积核通道数为 9×2(9 个 anchor,每个 anchor 二分类,使用交叉熵损失),进行回归的卷积核通道数为 9×4(9 个 anchor,每个 anchor 有 4 个位置参数)。RPN 是一个全卷积网络(fully convolutional network),这样对输入图片的尺寸就没有要求了。 接下来 RPN 做的事情就是利用(AnchorTargetCreator)将 17100多个候选的 anchor 选出 256 个 anchor 进行分类和回归位置。选择过程如下: - 对于每一个 ground truth bounding box (gt_bbox),选择和它重叠度(IoU)最高的一个 anchor 作为正样本 - 对于剩下的 anchor,从中选择和任意一个gt_bbox重叠度超过 0.7 的 anchor,作为正样本,正样本的数目不超过 128 个。 - 随机选择和gt_bbox重叠度小于 0.3 的 anchor 作为负样本。负样本和正样本的总数为 256。

对于每个 anchor, gt_label 要么为 1(前景),要么为 0(背景),而 gt_loc 则是由 4 个位置参数 (tx,ty,tw,th) 组成,这样比直接回归座标更好。


计算分类损失用的是交叉熵损失,而计算回归损失用的是 Smooth_l1_loss. 在计算回归损失的时候,只计算正样本(前景)的损失,不计算负样本的位置损失。

图18 RPN网络整体训练流程图
与检测网络类似的是,依然使用Conv Layers提取feature maps。整个网络使用的Loss如下: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20191014155614586.png#pic_cneter) 上述公式中$i$ 表示anchors index, $p_i$ 表示positive softmax probability,$p_i^*$代表对应的GT predict概率(即当第$i$个anchor与GT间IoU>0.7,认为是该anchor是positive,$p_i^*=1$;反之IoU<0.3时,认为是该anchor是negative,$p_i^*=0$;至于那些0.3
  1. cls loss,即rpn_cls_loss层计算的softmax loss,用于分类anchors为positive与negative的网络训练
  2. reg loss,即rpn_loss_bbox层计算的soomth L1 loss,用于bounding box regression网络训练。注意在该loss中乘了 p i p_i^* ,相当于只关心positive anchors的回归(其实在回归中也完全没必要去关心negative)。

由于在实际过程中, N c l s N_{cls} N r e g N_{reg} 差距过大,用参数 λ λ 平衡二者(如 N r e g = 256 N_reg=256 N r e g = 2400 N_reg=2400 时设置 λ = N c l s / N r e g 10 \lambda=N_{cls}/ N_{reg}\approx 10 ),使总的网络Loss计算过程中能够均匀考虑2种Loss。这里比较重要是 L r e g L_{reg} 使用的soomth L1 loss,计算公式如下:

现在我们再来详细的聊一下图18中的各个模块在损失函数中扮演了什么角色。

  1. 在RPN训练阶段,rpn-data(python AnchorTargetLayer)层会按照和test阶段Proposal层完全一样的方式生成Anchors用于训练
  2. 对于rpn_loss_cls,输入的rpn_cls_scors_reshape和rpn_labels分别对应 p p p p^* , N c l s N_{cls} 参数隐含 p p p p^* 的caffe blob的大小中
  3. 对于rpn_loss_bbox,输入的rpn_bbox_pred和rpn_bbox_targets分别对应 t t t t^* ,rpn_bbox_inside_weigths对应 p p^* ,rpn_bbox_outside_weigths未用到(从soomth_L1_Loss layer代码中可以看到),而 N r e g N_{reg} 同样隐含在caffe blob大小中
5.2 通过训练好的RPN网络收集proposals

在该步骤中,利用之前的RPN网络,获取proposal rois,同时获取positive softmax probability,如图19,然后将获取的信息保存在python pickle文件中。该网络本质上和检测中的RPN网络一样,没有什么区别。

图19
5.3 训练Faster-RCNN网络

读取之前保存的pickle文件,获取proposals与positive probability。从data层输入网络。然后:

1.将提取的proposals作为rois传入网络,如图20蓝框
2.计算bbox_inside_weights+bbox_outside_weights,作用与RPN一样,传入soomth_L1_loss layer,如图20绿框

图20
之后的stage2训练都是大同小异,不再赘述了。

最后对于整个网络结构补充一种图~盗用来自于小伙伴的图片

图21 Faster-RCNN 网络结构图
##### 参考资料

Faster-RCNN
一文读懂Faster-RCNN
从编程实现角度学习 Faster R-CNN(附极简实现)


转载:https://blog.csdn.net/WangKingJ/article/details/102541279
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场