Faster RCNN是由 R-CNN、Fast R-CNN 改进而来,是非常经典的目标检测的两阶段网络。
此篇博客是我通过学习以下优秀博客归纳整理而得:
Faster R-CNN:详解目标检测的实现过程 - 郭耀华 - 博客园
yolov5与Faster-RCNN 训练过程正负样本和评价指标_norman_sen的博客-CSDN博客_yolov5正负样本
一、Faster R-CNN的整体结构
- 输入、数据预处理。首先,将尺寸大小为 M×N 的图片输入 Faster-RCNN 网络进行 resize 操作,处理图片的尺寸到 H×W,适应模型要求。
- Conv layers——backbone提取特征。Faster-RCNN 可以采用多种的主干特征提取网络,常用的有VGG,Resnet,Xception等等。作为一种CNN网络目标检测方法,Faster RCNN使用一组基础的 conv+relu+pooling 层提取 image的feature maps ,该 feature maps 被共享用于后续 RPN 层和全连接层。也就是使用共享的卷积层为全图提取特征。
- Region Proposal Networks。RPN网络用于生成 region proposals (目标候选区域)。将 RPN 生成的候选框投影到特征图上获得相应的特征矩阵。该层通过 softmax 判断 anchors (锚)属于前景或者背景,再利用 bounding box regression 修正 anchors 获得精确的 proposals 。
- RoI Pooling。该层收集输入的 feature maps 和 proposals,将每个特征矩阵缩放到 7×7 大小的特征图,综合这些信息后提取 proposal 和 feature maps,送入后续全连接层判定目标类别。
- 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 中:
- 所有的conv层都是:kernel_size=3,pad=1,stride=1
- 所有的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 层不改变输入和输出矩阵大小。
类似的是,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流程
经典的检测方法生成检测框都非常耗时,如 OpenCV adaboost 使用滑动窗口+图像金字塔生成检测框;或如 R-CNN 使用 SS(Selective Search) 方法生成检测框。而 Faster RCNN 则抛弃了传统的滑动窗口和 SS 方法,直接使用 RPN 生成检测框。
RPN作为Faster RCNN的一大主要创新点,网络直接使用 RPN 生成候选区域,这也将生成区域提议的时间从 2s 缩减到了 10ms,大大提升了生成待检测区域的速度。
RPN 执行两种不同类型的预测:二进制分类和边框回归调整。
RPN大致流程总结:生成anchors -> softmax 分类器提取 positvie anchors -> bbox reg 回归 positive anchors -> Proposal Layer 生成 proposals
2.1 Proposal的生成
提到 RPN 网络,就不能不说 锚框(anchor)。RPN 网络给特征图的每个网格生成 9个anchor(3种尺度 x 3个高宽比),这 9 种初始 anchor 包含三种面积 (128×128,256×256,512×512),每种面积又包含三种长宽比 (1:1,1:2,2:1) 。忽略掉跨越边界的 anchor 以后,剩下的anchor通过边界框回归参数调整为候选框,然后采用极大值抑制过滤掉一部分框,剩下的2k个候选框作为输出传递给 ROI 网络进行预测。锚框是在原图上设置不同大小的假想框,来检测框中是否出现物体。简单地说,RPN 依靠一个在共享特征图上滑动的窗口,为每个位置生成 9种 预先设置好长宽比与面积的框(anchor)。
RPN 接受所有的候选框(锚点)并为目标输出一套好的建议。它通过为每个锚点提供两个不同的输出来完成。
第一个输出是 锚点作为目标的概率。如果你愿意,可以叫做「目标性得分」。注意,RPN 不关心目标的类别,只在意它实际上是不是一个目标(而不是背景)。我们将用这个目标性得分来过滤掉不好的预测,为第二阶段做准备。第二个输出是 边框回归,用于调整锚点以更好的拟合其预测的目标。
2.2 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 个通道和 3x3 卷积核大小的卷积层,然后我们有两个使用 1x1 卷积核的并行卷积层,其通道数量取决于每个点的锚点数量。
对于分类层,我们对每个锚点输出两个预测值:它是背景(不是目标)的分数,和它是前景(实际的目标)的分数。
对于回归或边框调整层,我们输出四个预测值:Δ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之前,先做了1x1卷积。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.4 Proposal 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 锚点来计算回归损失。为了计算回归的目标,我们使用前景 anchor box 和最接近的真实目标,并计算将 anchor box 转化为目标所需的正确 Δ。(因为不需要考虑其类别)
论文中建议使用 Smooth L1 loss 来计算回归误差,而不是用简单的 L1 或 L2 loss。Smooth L1 基本上就是 L1,但是当 L1 的误差足够小,由确定的 σ 定义时,可以认为误差几乎是正确的且损失以更快的速率减小。
三、 ROI 流程
基于区域的卷积神经网络 R-CNN
基于区域的卷积神经网络(R-CNN)是 Faster R-CNN 工作流的最后一步。从图像上获得卷积特征图之后,用它通过 RPN 来获得目标建议并最终为每个建议提取特征(通过 RoI Pooling),最后我们需要使用这些特征进行分类。R-CNN 试图模仿分类 CNNs 的最后阶段,在这个阶段用一个全连接层为每个可能的目标类输出一个分数。
R-CNN 有两个不同的目标:
1. 将建议分到一个类中,加上一个背景类(用于删除不好的建议)。
2. 根据预测的类别更好地调整建议的边框。
在最初的 Faster R-CNN 论文中,R-CNN 对每个建议采用特征图,将它平坦化并使用两个大小为 4096 的有 ReLU 激活函数的全连接层。
然后,它对每个不同的目标使用两种不同的全连接层:
- 一个有 N+1 个单元的全连接层,其中 N 是类的总数,另外一个是背景类。
- 一个有 4N 个单元的全连接层。我们希望有一个回归预测,因此对 N 个类别中的每一个可能的类别,我们都需要 Δcenterx、Δcentery、Δwidth、Δheight。
3.1 ROI预测
Rol pooling层有2个输入:
- 原始的feature maps
- RPN输出的proposal boxes(大小各不相同)
将 RPN 网络生成的 proposals 结合特征图送入 ROI poling 进行下采样,然后通过两个并行卷积对 proposals 分别预测其可能属于的类别和边界框回归参数,注意是每个都要预测,可以理解为1个 proposal 预测了 N 个类别和 4N 个边界框回归参数。
从RoI Pooling获取proposal feature maps后,送入后续网络,可以看到做了如下2件事:Classifier 部分利用已经获得的 proposal feature maps,通过 full connect 层 与 softmax 计算每个 proposal 具体属于哪个类别(如人,车,电视等);同时再次利用 bounding box regression 获得每个 proposal 的位置偏移量 bbox_pred,用于回归更加精确的目标检测框。
注意,这里回归的结果是预测框中心点相对于正样本RoIs中心点坐标的位移以及两者长宽的比例,并且是归一化(减去均值除以标准差)后的结果。
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个步骤:
- 在已经训练好的model上,训练RPN网络,对应stage1_rpn_train.pt
- 利用步骤1中训练好的RPN网络,收集proposals,对应rpn_test.pt
- 第一次训练Fast RCNN网络,对应stage1_fast_rcnn_train.pt
- 第二训练RPN网络,对应stage2_rpn_train.pt
- 再次利用步骤4中训练好的RPN网络,收集proposals,对应rpn_test.pt
- 第二次训练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的联合训练方法。