目录

  • 简介

  • 特征提取

  • RPN网络

    • Anchors
    • 回归预测 (Bounding Box Regression)
    • 建议区域生成(Proposal Layer)
  • ROI Pooling以及分类模块

    • ROI Pooling
    • 分类以及回归
  • 网络训练

  • 后续可改进的点

  • 总结

简介

网络上关于Faster R-CNN详解的文章比较多,但是实现Faster R-CNN的方法具体还是多参照代码,所以这里希望能够简洁地对Faster R-CNN中的技术进行介绍,解释关键点的具体思路。以便在看具体代码的时候疑惑少一些。

Faster R-CNN网络分为两步:

  1. 将图片输入特征提取网络(也称为Backbone)得到Feature Map(特征图),然后将其输入RPN网络预测出目标区域(也可以叫建议区域)
  2. 根据建议区域和第一步中得到的Feature Map进行具体区域的特征进一步进行卷积分类回归,分类是判断类型,回归是修正预测区域使其更加精准

流程图如下

目标检测算法笔记 (二)Two-Stage 经典算法 Faster R-CNN

特征提取

目标检测中对图像中的特征进行提取是非常重要的一步,它能将图像中的细节组合并计算关联反映出来。卷积网络浅层的特征偏向于细节,深层偏向于细节的组合即抽象,因此这里的Faster R-CNN并不会取深层的图像特征。

Faster R-CNN首先使用一些基础的 Conv + ReLU + Pooling 模块提取图像中的特征组成Feature Map,Feature Map用于后续的RPN层以及ROI Pooling层。

Faster R-CNN(这里以Python版 VGG16中的结构为例)中所有的Conv和ReLU层的参数如下

Pad Stride Kernel Size
Conv 1 1 3
Pooling 0 2 2

这样在Conv层图像尺寸会由Pad = 1填充变成(M + 2) * (N + 2)然后通过3x3的卷积变回M x N的尺寸,即经过Conv层尺寸是不会变的;

而在Pooling层,图像的尺寸会变为(M / 2) * (N / 2);

通过如此规划,最后的Feature Map就可以和原图进行对应了,比如图中由于经过了4个Pooling层可知,Feature Map尺寸为 (M / 16) * (N / 16)。

PS:ReLU层不影响图像尺寸

RPN网络

在RPN网络提出之前对于目标检测框的生成方法非常费时且不高效,比如Opencv Adaboost使用滑动窗口+图像金字塔生成检测框、R-CNN使用SS(Selective Search)生成检测框。

RPN网络算是One-Stage 检测算法的标志了,它抛弃了上述方法,直接对Feature Map进行卷积预测生成目标可能存在的区域(建议区域)。

目标检测算法笔记 (二)Two-Stage 经典算法 Faster R-CNN

从上图中可以看到,RPN网络对Feature Map进行卷积后分为两条线,上面一条经过Softmax分类anchors获得Positive(正例)和Negative(负例);

下面一条这是计算anchors的标定框的回归量(Bounding Box Regression),目的是获取更为精确的标定框;

最终的Proposal层则是将正例和负例结合回归预测量进行调整筛选出可能具有目标且合理的目标框,也称为建议区域。其实到这里已经基本完成目标定位的功能。

PS:图中数字在后面有解释

Anchors

目标检测算法笔记 (二)Two-Stage 经典算法 Faster R-CNN
Anchors 示意图

一般Anchor会生成9个矩形,每一个矩形表示为(x1, y1, x2, y2)表示矩阵左下角和右上角。9个矩形共3中尺寸,每种尺寸中长宽比大约为 width : height in \in {1:1, 1:2, 2:1},如上图。

那么这九个anchor是做什么的呢,论文中是为feature map中每一个点都配备这9个anchors作为初始的检测框。如下图所示

目标检测算法笔记 (二)Two-Stage 经典算法 Faster R-CNN
  1. 在原文所使用的特征提取模型中,使用的feature map是conv5的结果,而其conv5的输出维度为256(不同特征提取网络的不同层数输出维度不一样,导致的效果也不会一样,这里不必太纠结,具体分析),即feature map有256维,相当于feature map每一个点都是256维的
  2. 对feature map中每一个点都做3x3卷积(rpn_conv)并且输出维数仍为256,相当于再次计算了每个点与其周围8个点的相关联的程度
  3. 假设feature map中每个点有k个anchor(默认k=9,这也是图二中上条线18数字的来历),而每个anchor要分为positive和negative,所以每个点的256维会转化为 2k 个 scores (2 * k = 18 这里,分别为正例和负例概率),然后每个anchor都有(x, y, w, h)对应4个偏移量,所以256维还会再次转化为 4k 个 coordinates。PS:不会把所有的anchor都拿去训练的,会在合适的anchors中随机选择128 positive anchor + 128 negative anchor进行训练

注意,这里1x1卷积后的 2k scores分数还需要进行调整经过softmax进行预测调整,然后再调整格式以便后续输入,具体调整参考代码即可。

注意,这里预测出来的2k scores和4k reg都是通过1x1卷积直接得出的,那么anchor这一机制又是怎么体现出来的呢?

其实这里只是先预测占位,对应的anchor生成以及综合考虑选择发生在后面的建议区域生成部分(Proposal层),通过Proposal的综合选择出具体的anchor后,计算损失,权值更新后,网络在1x1卷积部分就会“聪明”的选择合适anchor位置进行预测分数上涨。

回归预测

上面虽然对anchor进行了分类和选择,但是难免还是存在anchor覆盖不到的或者是标定目标不准确的情况,所以为了进一步提升Bounding Box的准确性,即微调bbox,RPN网络的下面一条线路就对Bounding Box进行了回归预测其偏移值。

上节也有介绍到,在Feature Map经历过3x3卷积提升局部关联性后,通过两个不同的1x1卷积得到了不同维度的预测数据,而通过设计损失函数,就可以使得网络在“有目的”的调整网络,其实两条线路的操作上是差不多的。但是回归预测有效有一个前提是,两个目标的位置需要相近,否则回归预测这一条线将很难收敛。

回归预测的目标是寻找一种关系使得输入原始的anchor A可以通过映射得到更为真实的且更接近真实值G的G’:

  • 给定anchor A = (Ax,Ay,Aw,AhA_x, A_y, A_w, A_h) 和 GT = (Gx,Gy,Gw,GhG_x, G_y, G_w, G_h)
  • 寻找一种变换使得 F (Ax,Ay,Aw,AhA_x, A_y, A_w, A_h) = (Gx,Gy,Gw,GhG_x', G_y', G_w', G_h'),其中 (Gx,Gy,Gw,GhG_x', G_y', G_w', G_h') \approx (Gx,Gy,Gw,GhG_x, G_y, G_w, G_h)

如下图所示

目标检测算法笔记 (二)Two-Stage 经典算法 Faster R-CNN

其中变化F的思路如下

先做平移
Gx=Awdx(A)+Ax G_x' = A_w · d_x(A) + A_x

Gy=Ahdy(A)+Ay G_y' = A_h · d_y(A) + A_y

然后再做缩放
Gw=Awexp(dw(A)) G_w' = A_w · exp(d_w(A))

Gh=Ahexp(dh(A)) G_h' = A_h · exp(d_h(A))

这样问题就变成了如何获得dd_*了,论文中发现当anchor A与G相差较小的时候,可以认为这种变换是一种线性变换,那么就可以用线性回归建模,如果相差比较大的话,线性回归来解决显然就不合适,即复杂非线性问题。

线性回归可以表示为
Y=WTX Y’ = W^TX
学习一组参数W使得Y‘与Y非常接近。在这个问题上,由于输入X是CNN的Feature Map,这里定义为ϕ\phi,然后将A与G之间的变化量传入,记为(tx,ty,tw,tht_x, t_y, t_w, t_h)。输出即(dx(A),dy(A),dw(A),dh(A)d_x(A), d_y(A), d_w(A), d_h(A)),目标函数可以表示为
d(A)=WTϕ(A) d_*(A) = W_*^T · \phi(A)
其中ϕ(A)\phi(A)对应anchor的feature map组成的特征向量,WW_*是学习的参数,论文里为了让预测值d(A)d_*(A)与真实值tt_*差距最小,设计了L1损失函数(实际情况下使用Smooth L1,更好收敛):
Loss=iNtiWTϕ(Ai) Loss = \sum_i^N|t_*^i -W_*^T · \phi(A^i)|
函数优化目标为:
W^=argminWintiWTϕ(Ai)+λW \hat{W_*} = argmin_{W_*} \sum_i^n|t_*^i - W_*^T · \phi(A^i)| + \lambda||W_*||
上述平移量(tx,tyt_x, t_y)和尺度因子(tw,tht_w, t_h)如下:
tx=(xxa)/waty=(yya)/ha t_x = (x - x_a) / w_a \quad t_y = (y - y_a) / h_a

tw=log(w/wa)th=log(h/ha) t_w = log(w / w_a) \quad t_h = log(h / h_a)

至此在训练RPN网络的时候,根据损失和优化目标就可以学习W的参数了。但是这里有一个前提是A和G的差距不大。这里ϕ(A)\phi(A)代表feature map的特征向量,即RPN网络下面那一条线的输入,输出36数字的意义这里就很明确了,就是4 x k(这里k=9,所以为36),代表每个anchor的回归预测量 dd_*

建议区域生成(Proposal Layer)

到目前为止,获得的信息有:

  • (M / 16) * (N / 16) * 2 * k 的 positive/negative softmax分类特征矩阵
  • (M / 16) * (N / 16) * 4 * k 的 regression坐标回归预测
  • 图像的Ground Truth信息(Img_Info)

那么汇合的Proposal Layer的目的就很明显了,就是将之前两条线路的结果汇总计算得到Two-Stage算法第一步的结果:目标建议框proposal。

Proposal Layer接受上述三个数据以及缩放的大小(feature_stride,这里为16),这里feature_stride主要用来计算anchor的偏移量。其处理顺序如下:

  1. 生成anchors,然后利用回归预测的dd_*对所有的anchors做bbox regression回归调整
  2. 根据anchors的positive softmax scores降序排列anchors,选取最高的前pre_nms_topN个anchors
  3. 限定超出图像边界的positive anchors为图像边界(简单把超出部分直接裁剪掉),防止后续的roi pooling和proposal超出图像边界
  4. 剔除尺寸非常小的positive anchors
  5. 对剩余的positive anchors进行NMS(nonmaximum suppression)

之后输出proposals,格式为(x1,y1,x2,y2x1, y1, x2, y2)。

RPN网络通过两个分支以及最后一层Proposal有效的完成了图像中目标区域的选取,相比Multi-Stage快速且高效。

ROI Pooling

在上节完成目标区域的测定后,接下来自然就是目标的分类了。此时有用的信息为:

  • 原始的Feature Map
  • RPN网络输出的proposals

问题自然就来了,传统CNN分类网络的输出都是固定的尺寸,而RPNs提供的bbox大小各不相同,怎么办呢?

通过对建议区域crop一部分传入网络或者对建议区域warp传入网络都会破坏图像的完整结构,有没有可以不破坏图像结构又可以传入不同尺寸到网络中,这就是这一节的目的,通过ROI Pooling来处理好不同大小的图像Patch提取并进行卷积分类。

ROI Pooling其实很简单,可以分为一下几步:

  1. 由于proposal是对应 M x N 尺寸的,所有首先使用 spatial_scale 参数将其映射回(M / 16) * (N / 16)的feature map尺度
  2. 将每个proposal对应的feature map区域水平分为 pooled_w x pooled_h 的网格(pooled参数是超参数,预先设置的)
  3. 对每一份网格进行max pooling的处理

处理过程如下面图所示

目标检测算法笔记 (二)Two-Stage 经典算法 Faster R-CNN
目标检测算法笔记 (二)Two-Stage 经典算法 Faster R-CNN
目标检测算法笔记 (二)Two-Stage 经典算法 Faster R-CNN
这里展示的pooled_w = pooled_h = 2,最终的结果的值是

目标检测算法笔记 (二)Two-Stage 经典算法 Faster R-CNN
由此,即可较好的对不同尺寸的建议区域进行提取处理方便后续分类操作。

分类以及回归

目标检测算法笔记 (二)Two-Stage 经典算法 Faster R-CNN

这一块在ROI pooling后就比较简单了,就是比较正常的分类网络,通过3x3卷积以及1x1全连接完成图像的分类,不过这里还加了一个Bounding Box Regression来获得更高精度的bbox。

网络训练

接下来简单说说Faster R-CNN网络的训练。具体步骤如下:

  1. 首先先训练RPN网络,至于用于提取特征的模型可以选择预训练模型(即已经训练好的)。训练好后收集proposals
  2. 通过上一步收集到的proposals,第一次训练Fast R-CNN网络
  3. 拿第一次训练Fast R-CNN网络后其权值训练RPN网络,并再次在训练后手机proposals
  4. 重复2-3一遍(论文中作者说循环2次后精度不再提升,具体根据实际情况循环训练)

接下来具体先说RPN网络的训练,RPN网络的Loss如下:
L({pi},{ti})=1NclsiLcls(pi,pi)+λ1NregipiLreg(ti,ti) L(\{p_i\}, \{t_i\}) = \frac{1}{N_{cls}} \sum_i L_{cls}(p_i, p_i^*) + \lambda \frac{1}{N_{reg}} \sum_i p_i^* L_{reg}(t_i, t_i^*)
上式其中ii表示anchors index,pip_i表示positive softmax probability,pip_i^*代表对应的GT predict概率(当第ii个anchor与GT之间IoU > 0.7,认为该anchor是positive,pi=1p_i^* = 1;反之IoU < 0.3时,认为该anchor是negative,pi=0p_i^* = 0;其余的anchor不参与训练),tt代表predict bounding box,tt^*代表对应的positive anchor对应的GT box。

整个Loss分为两个部分:

  • Cls Loss计算RPN网络上一条线SoftMax估计的Loss,用于分类anchors为positive还是negative的训练
  • Reg Loss计算RPN网络下一条线Bounding Box Regression的Loss,注意到其在累加项中乘了pip_i^*,相当于只关心positive anchors的回归(这一条线路的设计就无关negative)

当然,NclsN_{cls}NregN_{reg}的差距在实际过程中可能存在不平衡的情况,所以用λ\lambda进行平衡,一般设置为λ=NregNcls\lambda = \frac{N_{reg}}{N_{cls}}。这里注意实际中LregL_{reg}使用Smooth L1进行损失计算,因为Smooth L1比L1容易收敛比L2在训练初期更为稳定,Smooth L1计算公式如下:
Lreg(ti,ti)=i{x,y,w,h}smoothL1(titi) L_{reg}(t_i, t_i^*) = \sum_{i \in \{x,y,w,h\}} smooth_{L1}(t_i - t_i^*)

smoothL1(x)={0.5x2ifx<1x0.5otherwise smooth_{L1}(x) = \begin{cases} 0.5x^2 & if |x|<1 \\ |x| - 0.5 & otherwise \end{cases}

Fast R-CNN网络的训练即收集好proposals将其传入ROI pooling然后进行卷积预测即可,损失Loss和RPN网络大同小异,具体代码参考即可。

后续改进

Faster R-CNN非常经典,但同时也存在一些设计不合理的地方,这里将其列出以便后续参考学习:

  • 损失函数计算不够合理,SmoothL1虽然能较好处理L1和L2的问题,但计算4个点的Loss是基于其是分别独立的情况下的,实际中4个点是有一定关联的,同时多个检测框也可能存在同向的SmoothL1 Loss但是IoU的差距可能就很大,后续即有IoU Loss、GIoU Loss、DIoU Loss、CIoU Loss等改进。其中IoU Loss就是简单计算预测框与GT之间的IoU再乘以-1,;GIoU Loss发现IoU(A, B) = 0时无法优化,因为不了解A,B的远近,同时也清楚A,B具体是如何相交的,GIoU Loss计算简单来说就是IoU减去(A和B的外接矩形C - A和B的交集)/ C;DIoU Loss和CIoU Loss这是进一步对GIoU Loss进行改进使其更容易进行训练。

  • ROI Pooling存在两次量化,严重影响精度。后续提出有ROI Align、PrPooling,保持更好的保持了精度

  • RPN网络对Feature Map利用程度不够,前面有提到卷积层浅层偏图像细节,深层偏图像抽象,RPN网络只使用了某一层的输出,可以结合多层的输出进行联合预测,这也是后续某些论文所提出来的

  • anchor机制存在限制,虽然在当时提出具有突破性意义,但随着发展,anchor成为了限制检测准确定的点

  • 特征提取不够高效,对原始图像的卷及操作过于简单,可以考虑更换使用性能更好的BackBone

总结

Faster R-CNN在当时提出之际非常经典,将Object Detection的进度一下提高了不少,结构以及思路非常具有启发意义,存在的问题也在后续得到改善,到目前Two-Stage算法仍然在检测精度上保持稳定,但是仍然处理不了一些困难的目标检测问题(目标变形、目标遮挡etc.),在种种问题改善后,本身的机制比如anchor机制也开始成为了限制点,这也是目前Object Detection的一个方向。

总的来说入门学习Faster R-CNN对于应用也好研究也好非常有价值。但还是建议具体结合代码学习。

参考

  1. https://zhuanlan.zhihu.com/p/31426458
  2. https://blog.csdn.net/u011974639/article/details/78053203
  3. https://github.com/chenyuntc/simple-faster-rcnn-pytorch
  4. https://github.com/rbgirshick/py-faster-rcnn

相关文章: