最近在看SiamRPN系列,结果看着看着就看到Faster RCNN上面去了。尽管这个模型已经有一段时间了,我还是想把通过这两天学习的理解写下来。
RPN全称是Region Proposal Network,这里Region Proposal翻译为“区域选取”,也就是“提取候选框”的意思,所以RPN就是用来提取候选框的网络。在Faster RCNN这个结构中,RPN专门用来提取候选框,在RCNN和Fast RCNN等物体检测架构中,用来提取候选框的方法通常是比较传统的方法,而且比较耗时。而RPN一方面耗时较少,另一方面可以很容易结合到Fast RCNN中,成为一个整体。我们可以认为Faster RCNN所做的创新与改进就是用RPN结合Fast RCNN。它们三者都是based on regional proposal,即预先提取出候选区域,再通过CNN对候选区域进行样本分类(two-stage),这会影响它的速度,达不到YOLO那样的实时性,但从另一方面也保证了它的定位精度。
References:
电子文献:
http://www.telesens.co/2018/03/11/object-detection-and-classification-using-r-cnns/
https://zhuanlan.zhihu.com/p/31426458
https://blog.csdn.net/lanran2/article/details/54376126
建议
在正文开始之前,推荐可以先了解一下相关的概念,比如1x1卷积、bounding box、anchor box和NMS等。我之前写过几篇相关的文章,可以先速览一下以防概念不清。
Bbox和anchor:computer-vision笔记:anchor-box。
非极大抑制:computer-vision笔记:non-max suppression。
1x1卷积:deep-learning笔记:着眼于深度——VGG简介与pytorch实现。
此外也推荐b站上的两个视频图解RCNN和FastRCNN和图解FasterRCNN,讲得挺不错的,就是声音有延迟,也可以直接看我的文章。视频中有地方讲得比较模糊,我在查阅资料之后更正了。
附faster RCNN的pytorch实现。
RCNN和Fast RCNN
它们两者是Faster RCNN的先驱和基础,在这里简单介绍一下。首先先说明,无论是RCNN,还是Fast RCNN,还是Faster RCNN,它们的目的都是一样的,就是对一个图片,找出其中的目标物体,并用bounding box框出。
RCNN
RCNN即Region CNN,可以说是利用深度学习进行目标检测的开山之作,它用CNN(AlexNet)代替了之前sliding window的方法。
上面是RCNN的基本结构(图源自上面推荐的视频)。首先我们通过Selective Search(选择性搜索)去生成大量的认为可能存在目标物体的小图块。然后将所有的这些图块通过预先训练得很完美的CNN进行特征提取,比如AlexNet、VGG等。然后我们再对这些convNet卷积网络的输出进行两个操作:(1)Bbox回归,确定Bbox框出的目标位置即用回归的方式确定Bbox的4个参数;(2)分类,即用SVM判断Bbox标注的目标是什么物体。
RCNN的主要缺点就是计算成本非常巨大,这里会用上千张小图块去通过一个同样的卷积网络,即进行约2000次左右的串行式前向传播,而在之后又要分别经过回归和支持向量机两个模型,也就是要重复地执行以上操作上千遍,这就严重影响了速度。
由于使用了AlexNet(或者VGG),需要每一个候选框统一成相同的227x227的尺寸(若使用VGG,则是224x224),这就严重影响了CNN提取特征的质量。由于RCNN中SVM需要单独训练,随着类别的增加训练SVM的个数也会增加,这也使得训练过程更加复杂。此外,Selective Search去生成这些图像块的过程也是非常expensive和slow的。
补充:这里简单介绍一下Selective Search。
Selective Search类似于一种层次聚类算法,就是根据颜色、纹理、尺寸和空间交叠相似度,从众多小尺寸、细粒度的框中逐步选择、合并出大尺寸、粗粒度的约2000个候选框,用作随后的特征提取。
考虑到RCNN提取特征的巨大花费和较低的质量,后来何恺明大神对此做出了最早的改进,提出了SPP(空间金字塔池化),使得候选区域特征的提取只需要执行一遍且能够使任意大小的RoI统一成相同尺寸,其思路类似于稍晚于它的Fast RCNN(不过从日后的表现来看Fast RCNN的RoI Pooling较好),直到后来更好的Faster RCNN被提出。
Fast RCNN
Fast RCNN主要针对RCNN的问题进行了改进,即从逐个提取特征进步到了一次性提取特征。它首先直接对原始图像用卷积网络去提取特征,然后再在这张feature map上使用Selective Search。这样就使得只需要一张图像经过一遍卷积网络而不是将上千张图像去经过上千遍网络。然而Selective Search在这里还是没有得到改进,这是后面Faster RCNN使用RPN替换Selective Search的突破点。
然后通过RoI Pooling Layer使各个图像块的大小统一,以方便后面的回归和分类操作,这点后面还会讲到。最后Fast RCNN还做了一项改进就是使用两个并行的层代替了原本的SVM和Bbox回归两个模型,减少了模型的复杂度和参数量,同时这也将原本的分类、回归多任务损失统一在同一个框架中,相当于可以在训练的时候协同调整,使模型更加平衡,表现更好。
Faster RCNN
基本结构
如图所示,Faster RCNN可以分为4个主要部分:conv layers
作为一种CNN网络目标检测方法,Faster RCNN首先使用一组基础的conv卷积+relu激活+pooling池化提取image的feature maps。该feature maps被共享用于后续RPN层和全连接层。Region Proposal Network
RPN网络用于生成region proposals。该层通过softmax判断anchors属于positive或者negative,再利用bounding box regression修正anchors获得精确的proposals。RoI pooling
RoI即Region of Interest,RoI pooling是池化层的一种。该层收集输入的feature maps和proposals,综合这些信息后,提取proposal feature maps,送入后续全连接层判定目标类别。classifier
利用proposal feature maps计算proposal的类别,即确定是什么物体。同时再次进行bounding box regression以获得检测框最终的精确位置。
流程
预处理
首先对输入的图像进行预处理(常规操作),即减去均值并缩放成固定大小MxN。这个预处理过程对training和inference都是identical的。注意,这里的mean指的是对于整个训练集/测试集的均值而不是单张图片本身。特征提取
接收了处理后固定大小的图像后,使用一个卷积网络去提取特征,这个网络包含conv,pooling,relu三种层。以使用VGG16的Faster RCNN版本的网络结构为例,如图所示。 这里的conv layers部分共有13个conv层,13个relu层和4个pooling层。这里的参数值得注意:所有的conv层都设置kernel size为3,padding为1,stride为1;而所有的pooling层都设置kernel size为2且stride为2。
这样设置有什么目的呢?可以结合下面的示意图来看,首先对所有的卷积都做了扩边处理(padding为1,即填充一圈0),使原图变为(M+2)x(N+2)的大小,然后再做3x3卷积,输出大小仍为MxN。正是这种设置,使得conv层不改变输入和输出矩阵大小。 再来看池化层,设kernel size为2且stride为2。这样每个经过pooling层的MxN矩阵,都会变为(M/2)x(N/2)大小。
综上所述,在通过的整个卷积网络中,conv层和relu层不改变输入输出大小,只有pooling层使输出长宽都变为输入的1/2。那么4个pooling层就使得MxN大小的矩阵经过特征提取后固定变为(M/16)x(N/16)的feature maps。提取候选框(RPN)
接下来就是最重要的Region Proposal Network。经典的检测方法生成检测框都非常耗时,如OpenCV adaboost使用滑动窗口+图像金字塔生成检测框;或如RCNN使用SS(Selective Search)方法生成检测框。而Faster RCNN则抛弃了传统的滑动窗口和SS方法,直接使用RPN生成检测框,这也是Faster RCNN的巨大优势,能极大提升检测框的生成速度。
这里还是先借用一张图来明确一下Faster RCNN的流程,整个RPN网络其实相当于这里的Anchor Generation Layer和Region Proposal Layer。这里的Anchor Target Layer是用于识别出一系列与ground truth box的分数达到一定阈值的较好的foreground anchors前景(物体)锚框和低于一定阈值的background anchors背景锚框,以及其对应的regression coefficients来训练RPN网络。这里的RPN Loss就是识别标记的foreground/background labels中的正确率与predicted和target regression coefficients之间的定义距离的组合。最后的Classification Loss也与RPN Loss定义类似,也是组合了正确率和系数距离。
补充:这里我想先结合上面讲一下训练的过程,也可以跳过这一块继续看RPN。
上面所述的Anchor Target Layer的输出并不用于后面分类器的训练。用于后面分类器训练的是Proposal Target Layer的输出。也就是说RPN层和分类器是分开训练的,先用预训练好的模型(比如VGG、ResNet和作者论文中用的ZF)训练RPN,再把训练好的RPN放到Faster RCNN中走上面流程图中的另一条路径训练分类器也就是整个Fast RCNN网络。根据这种思路,实际的训练过程分为4步:
(1)在已经预训练好的model上,第一次训练RPN网络。
(2)第一次训练整个Fast RCNN网络。
(3)再第二次单独训练训练RPN网络。
(4)再次利用步骤3中训练好的RPN网络,收集proposals,并第二次训练Fast RCNN网络。之所以只进行了类似的“循环”两次,是因为循环更多次并没有negligible improvements。
好的还是先回到RPN模块。
还是参照上一节提到的使用VGG16的Faster RCNN版本的网络结构,可以看到RPN网络实际分为2条线,上面一条通过softmax分类anchors获得positive anchors(存在目标的,也就是foreground anchors)和negative anchors两类,下面一条用于计算对于anchors的bounding box regression偏移量,以获得精确的proposal。而最后的Proposal Layer则负责综合positive anchors和对应bounding box regression偏移量获取proposals,同时剔除太小和超出边界的proposals。其实整个网络到了Proposal Layer这里,就相当于完成了目标定位的功能。
下面更细地讲一下这里具体是怎么做的。anchor
作者是这样生成anchor box的:对输入的feature map上的每一个点(pixel),都设置9个不同尺度和形状的anchor box,如下图所示。
这样通过anchor box引入了目标检测中多尺度的方法,可以看到基本上整张图片上的各种尺度和形状都被cover到了。也可以事先通过对数据集聚类分析的方式来确定初始的anchor box的尺寸。
当然,这样做获得box很不准确,不用担心,后面还有2次bounding box regression可以修正检测框的位置。补充:下面是原论文中的一张图,在这里做一些简单的解释。
- 这里的256-d指的是之前用于提取特征的卷积网络生成的feature maps的数量,其具体维度视使用的卷积网络而定。原文中使用的是ZF model中,其最后一层conv层输出维度为256,即生成256张feature maps,也相当于得到的一个feature map中每个点都是256维的。
- 结合前文中使用VGG16的Faster RCNN版本的网络结构,可以看到,在卷积网络提取出feature map之后,又做了3x3卷积且输出依旧是256维的,相当于每个点又融合了周围3x3的空间信息,也许这样做会是模型更鲁棒。
- 图中的k表示的不是千,而是每个点对应的anchor的个数,这里默认是9,而每个anhcor要分positive和negative,所以每个点cls分类需要两个分数,一个是前景(物体)分数,一个是背景分数,即图中所示2k scores;而每个anchor box又需要4个偏移量来定位,所以这里reg回归为4k coordinates。
- 在生成anchor的示意图中可以看到,显然anchors太多了,因此训练时会在合适的anchors中随机选取128个postive anchors与128个negative anchors进行训练。
分类
为了便于分析,我还是再把上面那张图拿下来。
在经过3x3的卷积之后,又经过18个1x1的卷积核,这里的卷积主要是为了改变维数。比如我们输入一张WxH的feature map,那么经过该卷积输出就为WxHx18大小(输出图像通道数总是等于卷积核数量)。那么为什么是18呢?
容易发现,18等于2(positive/negative)乘上9(anchors),也就是因为feature maps每一个点都有9个anchors,同时每个anchors又有可能是positive和negative,所以利用WxHx(9x2)大小的矩阵来保存这些信息。
这里的softmax就是用于分类获得positive anchors,也就相当于初步提取了检测目标候选区域的Bbox。
而softmax前后的两个reshape其实就是为了变换输入的张量以便于softmax分类(有点类似于一些网络在最后的卷积层和全连接层之间将张量拍扁成一维的),后面的reshape就是恢复原状的作用。
其实RPN在这里就是在原图尺度上,设置了密密麻麻的候选anchor box。然后判断哪些是里面有目标的positive anchor,哪些是没目标的negative anchor。回归
接下来我们来看看RPN模块下面那一条路径在做什么。
如图所示,绿色框为事先标注的飞机的ground truth box(GT),红色框为前面提取的positive anchors,虽然红色框被分类器识别为飞机,但是由于红色框定位不准,依旧没有达到正确地检测出飞机的目标。所以我们希望采用一种方法对红色框进行微调,使得positive anchors和GT更加接近。对于一个box,我们一般使用一个四维向量$\left ( x,y,w,h \right )$来表示,即标注中心点的坐标和box的宽度和高度。在下图中,红色框A代表原始的positive anchors,绿色框G代表目标的GT,我们的目标是寻找一种关系,使得输入原始的A经过映射得到一个跟真实窗口G更接近的回归窗口G’,即寻找一种变换$F$,s.t.$F\left ( A_{x},A_{y},A_{w},A_{h} \right )=\left ( G_{x}^{‘},G_{y}^{‘},G_{w}^{‘},G_{h}^{‘} \right )$且$\left ( G_{x}^{‘},G_{y}^{‘},G_{w}^{‘},G_{h}^{‘} \right )\approx \left ( G_{x},G_{y},G_{w},G_{h} \right )$。
那么这个变换$F$如何选择呢?一种简单的思路就是先做平移后做缩放,即:
因此我们需要学习的是$d_{x}\left ( A \right )$,$d_{y}\left ( A \right )$,$d_{w}\left ( A \right )$,$d_{h}\left ( A \right )$这四个变换。当输入的A与GT相差较小时,可以认为这种变换是一种线性变换,那么就可以用线性回归来进行微调。
注:线性回归就是给定输入的特征向量$X$,学习一组参数$W$,使得经过线性回归后的值跟真实值$Y$非常接近,即$Y=WX$。
对于该问题,输入$X$是cnn feature map,定义为$\phi$;同时还有训练传入A与GT之间的变换量,即$\left ( t_{x},t_{y},t_{w},t_{h} \right )$。输出是上面所说的四个变换。则目标函数可表示为:
为了让预测值$d_{\ast }\left ( A \right )$与真实值$t_{\ast }$差距最小,设计L1损失函数:
得到优化目标为:
这里的$argmin$表示的是给定参数的表达式达到最小值。
补充:这里positive anchor与ground truth之间的平移量$\left ( t_{x},t_{y} \right )$和尺度因子$\left ( t_{w},t_{h} \right )$定义如下:
请结合下图理解。之所以这样定义,是为了回归系数在图片进行仿射变换之后依旧能够保持不变。
有关仿射变换,可以看一下之前的文章linear-algebra笔记:二维仿射变换。
Proposal Layer
Proposal Layer有3个输入:positive anchors分类器结果,Bbox reg的变换量以及生成的anchor。如图所示,在选择最优的多个box,然后对这些box作NMS,结果作为proposals输出。
RPN小结
以上就是RPN网络提取候选框的大致介绍,总结起来就是:首先,生成anchors;然后,用softmax分类器提取positvie anchors;接着,Bbox reg回归positive anchors;最后,通过Proposal Layer生成proposals。
RoI pooling
先来看一个问题:对于传统的CNN(如AlexNet和VGG),当网络训练好后输入的图像尺寸必须是固定值,同时网络输出也是固定大小的vector或者matrix。如果输入图像大小不定,这个问题就变得比较麻烦。有2种解决办法:从图像中crop一部分传入网络,或者将图像warp成需要的大小后传入网络。 问题是,无论采取那种办法都不是很好,要么crop后破坏了图像的完整结构,要么warp后破坏了图像原始形状信息。
于是,Fast RCNN就提出了RoI pooling来解决这个问题,其思路是与其wrap图像破坏信息,不如尝试着去wrap特征。
其步骤如下:Step1:Coordinate on image
由于proposal对应的尺度是MXN,所以首先将其映射回(M/16)X(N/16)尺度大小的feature map。(若不能整除,则向下取整,相当于丢弃小部分右侧和下侧的信息)Step2:Coordinate on feature map
再将每个proposal对应的feature map区域水平分为WxH的网格。Step3:Coordinate on RoI feature
接着对网格中的每一份都进行max pooling处理。如此就得到了WxH固定大小的输出。 由于RoI pooling这里采用了两次浮点数取整运算,这就使得池化之后的输出可能会于原图像的尺寸对不上,因此后来何恺明大神又提出了基于双线性插值的RoI Align来代替取整,作出了进一步改进。补充:2019年IoUNet又提出了PrRoI pooling,相比RoI Align,它不用预设N的个数,直接使用积分取均值。
分类器
最后的分类部分利用已经获得的proposal feature maps,通过full connect层与softmax计算每个proposal具体属于那个类别(如人,车,电视等),输出含有各个类别的概率向量;同时再次利用bounding box regression获得每个proposal的位置偏移量,用于回归更加精确的目标检测框。