Faster RCNN是由 R-CNN、Fast R-CNN 改进而来,是非常经典的目标检测的两阶段网络。

此篇博客是我通过学习以下优秀博客归纳整理而得:

一文读懂Faster RCNN – 知乎

Faster R-CNN详解和网络模型搭建 – 知乎

Faster R-CNN:详解目标检测的实现过程 – 郭耀华 – 博客园

yolov5与Faster-RCNN 训练过程正负样本和评价指标_norman_sen的博客-CSDN博客_yolov5正负样本

一、Faster R-CNN的整体结构

  1. 输入、数据预处理。首先,将尺寸大小为 M×N的图片输入 Faster-RCNN 网络进行 resize 操作,处理图片的尺寸到 H×W,适应模型要求。
  2. Conv layers——backbone提取特征。Faster-RCNN 可以采用多种的主干特征提取网络,常用的有VGG,Resnet,Xception等等。作为一种CNN网络目标检测方法,Faster RCNN使用一组基础的 conv+relu+pooling 层提取 image的feature maps ,该feature maps被共享用于后续 RPN 层和全连接层。也就是使用共享的卷积层为全图提取特征。
  3. Region Proposal Networks。RPN网络用于生成 region proposals (目标候选区域)。将 RPN 生成的候选框投影到特征图上获得相应的特征矩阵。该层通过 softmax 判断 anchors (锚)属于前景或者背景,再利用 bounding box regression 修正 anchors 获得精确的 proposals 。
  4. RoI Pooling。该层收集输入的 feature maps 和 proposals,将每个特征矩阵缩放到 7×7 大小的特征图,综合这些信息后提取 proposal 和 feature maps,送入后续全连接层判定目标类别。
  5. Classifier。通过全连接层得到最后的概率,计算得到类别,同时再次 bounding box regression 获得检测框最终的精确位置。尤其注意的是,Faster R-CNN 真正实现了端到端的训练 (end-to-end training)。

Faster R-CNN整体结构图如下所示:

二、基础网络——backbone

  Faster R-CNN 第一步要使用在图片分类任务 (例如,ImageNet) 上预训练好的卷积神经网络,使用该网络得到的中间层特征的输出

原始的 Faster R-CNN 使用的是在 ImageNet 上预训练的 ZF 和 VGG,但之后出现了很多不同的网络,且不同网络的参数数量变化很大。例如,MobileNet,以速度优先的一个小型的高效框架,大约有 330 万个参数,而 ResNet-152(152 层),曾经的 ImageNet 图片分类竞赛优胜者,大约有 6000 万个参数。最新的网络结构如 DenseNet,可以在提高准确度的同时缩减参数数量。

如今,ResNet 已经取代大多数 VGG 网络作为提取特征的基础框架。Faster-RCNN 的三位联合作者 (Kaiming He, Shaoqing Ren 和 Jian Sun) 也是论文「Deep Residual Learning for Image Recognition」的作者,这篇论文最初介绍了 ResNets 这一框架。

ResNet 对比 VGG 的优势在于它是一个更深层、大型的网络,因此有更大的容量去学习所需要的信息。这些结论在图片分类任务中可行,在目标探测的问题中也应该同样有效。ResNet 在使用残差连接和批归一化的方法后更加易于训练,这些方法在 VGG 发布的时候还没有出现。

Conv layers

Conv layers 包含了 conv,pooling,relu 三种层。

每一层卷积网络都在前一层的信息基础上提取更加抽象的特征。第一层通常学习到简单的边缘,第二层寻找目标边缘的模式,以激活后续卷积网络中更加复杂的形状。最终,我们得到一个在空间维度上比原始图片小很多,但表征更深的卷积特征图。特征图的长和宽会随着卷积层间的池化而缩小,深度会随着卷积层滤波器的数量而增加。卷积特征图将图片的所有信息编码到深度的维度上,同时保留着原始图片上目标物体的相对位置信息。例如,如果图片左上角有一个红色矩形,经过卷积层的激活,那么红色矩形的位置信息仍然保留在卷积特征图的左上角。

以 python 版本中的 VGG16 模型中的faster_rcnn_test.pt 的网络结构为例:

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) 大小,再做 3×3 卷积后输出 MxN 。正是这种设置,导致 Conv layers 中的 conv 层不改变输入和输出矩阵大小。

类似的是,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 中都可以和原图对应起来。

二、RPN流程

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

在原文中,经过特征提取后,共享特征图的大小约为40×60,RPN生成的初始anchor总数为20000(40×60×9)。对于生成的anchor,RPN要做的事情有两个,第一个是判断anchor到底是前景还是背景,意思就是判断这个anchor到底有没有覆盖目标,在训练的时候排除掉了超越图像边界的anchor,剩下大约6000个,通过上面的分支,也就是先经过一个3×3卷积,得到一个相同大小shape的特征图,然后经过一个1×1的卷积层输出了18个值,因为是每一个点对应9个anchor,每个anchor有一个前景分数和一个背景分数,所以9×2=18;第二个是为属于前景的anchor进行第一次坐标修正。经过另一个1×1的卷积层输出了36个值,因为是每一个点对应9个anchor,每个anchor对应了4个修正坐标的值,所以9×4=36。那么,要得到这些值,RPN网络需要训练。在训练的时候,就需要对应的标签。那么,如何判定一个anchor是前景还是背景呢?文中做出了如下定义:如果一个anchor与ground truth的IoU在0.7以上,那这个anchor就算前景(positive)。类似地,如果这个anchor与ground truth的IoU在0.3以下,那么这个anchor就算背景(negative)。这样最终得到约2000个候选框。但是作者在进行RPN网络训练的时候,只使用了上述两种情况的anchor,与ground truth的IoU介于0.3和0.7的anchor没有使用。在训练anchor属于前景与背景的时候,是在一张图中,随机抽取了128个前景anchor与128个背景anchor。其实还有另一种方案就是取IoU最大值。正样本是在不够,就用负样本进行补充。

2.2.1 初步的3×3卷积核和1×1卷积核

RPN 是用完全卷积的方式高效实现的,用基础网络返回的卷积特征图作为输入。首先,我们使用一个有 512 个通道和 3×3 卷积核大小的卷积层,然后我们有两个使用 1×1 卷积核的并行卷积层,其通道数量取决于每个点的锚点数量。

对于分类层,我们对每个锚点输出两个预测值:它是背景(不是目标)的分数,和它是前景(实际的目标)的分数。

  对于回归或边框调整层,我们输出四个预测值:Δxcenter、Δycenter、Δwidth、Δheight,我们将会把这些值用到锚点中来得到最终的建议。

  使用最终的建议坐标和它们的目标性得分,然后可以得到一套很好的对于目标的建议。

2.2.2 softmax判定positive与negative——二分类

一副 MxN 大小的矩阵送入 Faster RCNN 网络后,到 RPN 网络变为 (M/16)x(N/16),不妨设 W=M/16,H=N/16。在进入reshape与softmax之前,先做了1×1卷积。feature maps 每一个点都有 9个 anchors,同时每个 anchors 又有可能是 positive 和 negative,所有这些信息都保存 WxHx(9*2) 大小的矩阵。

后面接 softmax 分类获得 positive anchors,也就相当于初步提取了检测目标候选区域 box(一般认为目标在 positive anchors 中)。那么为何要在 softmax 前后都接一个 reshape layer?其实只是为了便于 softmax 分类。

RPN 网络中利用 anchors 和 softmax 初步提取出 positive anchors 作为候选区域(另外也有实现用 sigmoid 代替 softmax。

2.2.3 对proposals进行bounding box regression

对于窗口一般使用四维向量(x,y,w,h)表示,分别表示窗口的中心点坐标和宽高。对于上图,红色的框A代表原始的 positive Anchors,绿色的框G代表目标的 GT,我们的目标是寻找一种关系,使得输入原始的 anchor A 经过映射得到一个跟真实窗口G更接近的回归窗口G’,即:

2.2.4Proposal Layer

Proposal Layer 负责综合所有[dx(A),dy(A),dw(A),dh(A)]变换量和 positive anchors,计算出精准的 proposal,送入后续 RoI Pooling Layer。

Proposal Layer会对RPN输出的分类和回归结果进行后处理(如NMS等),得到网络认为包含物体的区域,称为感兴趣的候选区域——RoI。至此,其实已经完成了定位任务,因为已经得到了包含物体的区域(bbox),只不过没有对物体类别进行细分,仅区分了前、背景。另外,由于anchor的位置和大小是人工预设的,且用于训练的样本有限,因此此处得到的检测结果可能并不够精准。

2.3 RPN的正负样本和损失

正负样本是从生成的所有anchor中选取并采样计算损失,可以理解为在生成anchor以后就根据 iou=0.7 来区分正负样本,然后通过正负样本比例 1:1 采集 256 个 anchor 计算损失,如果正样本不足,则采集负样本弥补。一句话概况就是训练 RPN 时是从所有的 anchor 中选取正负样本。

补充一下这里正负样本选取规则:

①和GT(真实框)有最大iou的anchor为正样本;

②和GT的iou超过0.7的anchor为正样本;

③和GT的iou小于0.3的anchor为负样本;

④iou在0.3~0.7之间的anchor会被忽略;

2.4 RPN训练、目标和损失函数

  RPN 执行两种不同类型的预测:二进制分类边框回归调整。为了训练,我们把所有的锚 anchor box 分成两类。一类是「前景」,另一类是「背景」。

  然后,我们对这些锚点随机采样,构成大小为 256 的 mini batch (维持前景锚点和背景锚点之间的平衡比例)。

  RPN 用所有以 mini batch 筛选出来的 anchor box和二进制交叉熵(binary cross entropy)来计算分类损失。然后它只用那些标记为前景的 mini batch 锚点来计算回归损失。为了计算回归的目标,我们使用前景 anchorbox 和最接近的真实目标,并计算将 anchorbox 转化为目标所需的正确 Δ。(因为不需要考虑其类别)

  论文中建议使用Smooth L1 loss来计算回归误差,而不是用简单的 L1 或 L2 loss。Smooth L1 基本上就是 L1,但是当 L1 的误差足够小,由确定的 σ 定义时,可以认为误差几乎是正确的且损失以更快的速率减小。

三、 ROI 流程

3.2 ROI训练

训练时,设置阈值为0.5来区分正负样本,与GT的iou大于0.5为正样本,小于0.5为负样本,这里和训练 RPN 的正负样本有一点不同,没有忽略样本,然后再按照正负样本比例为 1:1 采集 512 个样本用来计算损失,同样,如果正样本不足,则采集所有正样本,剩下的用负样本弥补,然后计算损失做梯度下降更新RPN的权重。

3.3 预测后处理

测试阶段或验证阶段,即预测结果后处理过程,会将全部的proposals做边界框回归, 假如有M个proposals,类别数为N,每个proposal预测N+1个边界框回归参数和N+1个概率,加1是因为还预测了背景,那么就会得到 Mx(N+1) 个预测框,然后去除背景框,还有MxN个框,然后设置一个置信度阈值,一般是0.05,有的代码这个值可能是0,然后再进一步去除一部分小框,剩下的框做nms 非极大值抑制,再取前 100个框作为最终的输出。这 100个框有两个作用,一是用来绘制最终打印在原图上的框,绘制前会再设置一个置信度阈值(0.5)来选择最后用于绘制的框;二是用来传入评价指标计算map,计算map会将这100个框直接传入coco等评价指标,进一步计算AP、MAP。

  非极大抑制(Non-maximum suppression):由于锚点经常重叠,因此建议最终也会在同一个目标上重叠。为了解决重复建议的问题,我们使用一个简单的算法,称为非极大抑制(NMS)。NMS 获取按照分数排序的建议列表并对已排序的列表进行迭代,丢弃那些 IoU 值大于某个预定义阈值的建议,并提出一个具有更高分数的建议。虽然这看起来很简单,但对 IoU 的阈值设定一定要非常小心。太低,你可能会丢失对目标的建议;太高,你可能会得到对同一个目标的很多建议。常用值是0.6建议选择:应用 NMS 后,我们保留评分最高的 N 个建议。论文中使用 N=2000,但是将这个数字降低到 50 仍然可以得到相当好的结果。

四、Faster RCNN整体训练

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

  1. 在已经训练好的model上,训练RPN网络,对应stage1_rpn_train.pt
  2. 利用步骤1中训练好的RPN网络,收集proposals,对应rpn_test.pt
  3. 第一次训练Fast RCNN网络,对应stage1_fast_rcnn_train.pt
  4. 第二训练RPN网络,对应stage2_rpn_train.pt
  5. 再次利用步骤4中训练好的RPN网络,收集proposals,对应rpn_test.pt
  6. 第二次训练Fast RCNN网络,对应stage2_fast_rcnn_train.pt

可以看到训练过程类似于一种“迭代”的过程,不过只循环了2次。至于只循环了2次的原因是应为作者提到:”A similar alternating training can be run for more iterations, but we have observed negligible improvements”,即循环更多次没有提升了。

在训练分类器和RoI边框修正时,步骤如下所示:

1) 首先通过RPN生成约20000个anchor(40×60×9)。

2) 对20000个anchor进行第一次边框修正,得到修订边框后的proposal。

3) 对超过图像边界的proposal的边进行clip,使得该proposal不超过图像范围。

4) 忽略掉长或者宽太小的proposal。

5) 将所有proposal按照前景分数从高到低排序,选取前12000个proposal。

6) 使用阈值为0.7的NMS算法排除掉重叠的proposal。

7) 针对上一步剩下的proposal,选取前2000个proposal进行分类和第二次边框修正。

总的来说,Faster R-CNN的loss分两大块,第一大块是训练RPN的loss(包含一个SoftmaxLoss和SmoothL1Loss),第二大块是训练Fast R-CNN中分类器的loss(包含一个SoftmaxLoss和SmoothL1Loss),其实原论文中训练方法特别复杂,但是现在大多直接采用RPN Loss + Fast R-CNN Loss的联合训练方法。

目前只能这个程度了,后续有新的理解会更新。