目录
本篇文章介绍了Faster RCNN的基本原理和思路,参考地址为知乎
Faster RCNN基本结构
经过R-CNN和Fast RCNN的积淀,Ross B. Girshick在2016年提出了新的Faster RCNN,在结构上,Faster RCNN已经将特征抽取(feature extraction),proposal提取,bounding box regression(rect refine),classification都整合在了一个网络中,使得综合性能有较大提高,在检测速度方面尤为明显。
依作者看来,如图1,Faster RCNN其实可以分为4个主要内容:
![](https://img-blog.csdnimg.cn/2020042009235795.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMTk1MzYw,size_16,color_FFFFFF,t_70)
- Conv layers。作为一种CNN网络目标检测方法,Faster RCNN首先使用一组基础的conv+relu+pooling层提取image的feature maps。该feature maps被共享用于后续RPN层和全连接层。
- Region Proposal Networks。RPN网络用于生成region proposals。该层通过softmax判断anchors属于positive或者negative,再利用bounding box regression修正anchors获得精确的proposals。
- Roi Pooling。该层收集输入的feature maps和proposals,综合这些信息后提取proposal feature maps,送入后续全连接层判定目标类别。
- Classification。利用proposal feature maps计算proposal的类别,同时再次bounding box regression获得检测框最终的精确位置。
所以本文以上述4个内容作为切入点介绍Faster R-CNN网络。
图2展示了python版本中的VGG16模型中的网络结构,可以清晰的看到该网络对于一副任意大小PxQ的图像,首先缩放至固定大小MxN,然后将MxN图像送入网络
- Conv layers中包含了13个conv层+13个relu层+4个pooling层(其实就是VGG16的网络结构);
- RPN网络首先经过3x3卷积,再分别生成positive anchors和对应bounding box regression偏移量,然后计算出proposals;
- Roi Pooling层则利用proposals从feature maps中提取proposal feature送入后续全连接和softmax网络作classification
- classification分类proposal到底是什么类别,同时再次bounding box regression获得检测框最终的精确位置。
![](https://img-blog.csdnimg.cn/20200419154156746.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMTk1MzYw,size_16,color_FFFFFF,t_70)
注:
本文不会讨论任何关于R-CNN家族的历史,分析清楚最新的Faster R-CNN就够了,并不需要追溯到那么久。实话说我也不了解R-CNN,更不关心。有空不如看看新算法。
1 Conv layers
Conv layers包含了conv,pooling,relu三种层。以python版本中的VGG16模型中的网络结构为例(如图3),Conv layers部分共有13个conv层,13个relu层,4个pooling层(如图4)。
![](https://img-blog.csdnimg.cn/20200419154418280.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMTk1MzYw,size_16,color_FFFFFF,t_70)
![](https://img-blog.csdnimg.cn/20200419154618713.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMTk1MzYw,size_16,color_FFFFFF,t_70)
这里有一个非常容易被忽略但是又无比重要的信息,在Conv layers中:
- 所有的conv层都是:kernel_size=3,pad=1,stride=1,所以conv层不改变输入和输出矩阵大小;
- 所有的pooling层都是:kernel_size=2,pad=0,stride=2 ,所以这样每个经过pooling层的MxN矩阵,都会变为(M/2)x(N/2)大小
总结:conv和relu层不改变输入输出大小,只有pooling层使输出长宽都变为输入的1/2。那么,一个MxN大小的矩阵经过Conv layers固定变为(M/16)x(N/16)!这样Conv layers生成的feature map中都可以和原图对应起来。
2 Region Proposal Networks(RPN)
经典的检测方法生成检测框都非常耗时,如OpenCV adaboost使用滑动窗口+图像金字塔生成检测框;或如R-CNN使用SS(Selective Search)方法生成检测框。而Faster RCNN则抛弃了传统的滑动窗口和SS方法,直接使用RPN生成检测框,这也是Faster R-CNN的巨大优势,能极大提升检测框的生成速度。
![](https://img-blog.csdnimg.cn/20200419155823788.png)
RPN部分的输入、输出如下:
- 输入:feature map、物体标签,即训练集中所有物体的类别与边框位置。
- 输出:Proposal、分类Loss、回归Loss,其中,Proposal作为生成的区域,供后续模块分类与回归。两部分损失用作优化网络。
2.1 Anchors
理解Anchor是理解RPN乃至Faster RCNN的关键。Faster RCNN先提供一些先验的边框,然后再去筛选与修正,这样在Anchor的基础上做物体检测要比从无到有的直接拟合物体的边框容易一些。
Anchor的本质是在原图大小上的一系列的矩形框,但Faster RCNN将这一系列的矩形框和feature map进行了关联。具体做法是,首先对feature map进行3×3的卷积操作,得到的每一个点的维度是512维,这512维的数据对应着原始图片上的很多不同的大小与宽高区域的特征,这些区域的中心点都相同。如果下采样率为默认的16,则每一个点的坐标乘以16即可得到对应的原图坐标。
为适应不同物体的大小与宽高,在作者的论文中,默认在每一个点上抽取了9种Anchors,具体Scale为{8,16,32},Ratio为{0.5,1,2},将这9种Anchors的大小反算到原图上,即得到不同的原始Proposal,如图6所示。而后通过分类网络与回归网络得到每一个Anchor的前景背景概率和偏移量,前景背景概率用来判断Anchor是前景的概率,回归网络则是将预测偏移量作用到Anchor上使得Anchor更接近于真实物体坐标。
![](https://img-blog.csdnimg.cn/20200420095645763.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMTk1MzYw,size_16,color_FFFFFF,t_70)
那么这9个anchors是做什么的呢?借用Faster RCNN论文中的原图,如图7,遍历Conv layers计算获得的feature maps,为每一个点都配备这9种anchors作为初始的检测框。这样做获得检测框很不准确,不用担心,后面还有2次回归可以修正检测框位置。
![](https://img-blog.csdnimg.cn/20200419170318733.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMTk1MzYw,size_16,color_FFFFFF,t_70)
解释一下上面这张图的数字。
- 在原文中使用的是ZF Net(ILSVRC2013分类任务的冠军,使用反卷积对CNN的中间特征图进行可视化分析,通过分析特征行为找到提升模型的办法,微调Alexnet提升了表现。)其Conv Layers中最后的conv5层num_output=256,对应生成256张特征图,所以相当于feature map每个点都是256-dimensions
- 在conv5之后,做了rpn_conv/3x3卷积且num_output=256,相当于每个点又融合了周围3x3的空间信息(猜测这样做也许更鲁棒?反正我没测试),同时256-d不变(如图4和图7中的红框)
- 假设在conv5 feature map中每个点上有k个anchor(默认k=9),而每个anhcor要分前景和背景,所以每个点由256d feature转化为cls=2k scores(二分类嘛);而每个anchor都有(x, y, w, h)对应4个偏移量,所以reg=4k coordinates(回归的四个值)
- 补充一点,全部anchors拿去训练太多了,训练程序会在合适的anchors中随机选取128个postive anchors+128个negative anchors进行训练(后面再说)
注意,在本文讲解中使用的VGG conv5 num_output=512,所以是512d,其他类似。
言归正传,其实RPN最终就是在原图尺度上,设置了密密麻麻的候选Anchor。然后用cnn去判断哪些Anchor是里面有目标的前景,哪些是没目标的背景。所以,仅仅是个二分类而已!
那么Anchor一共有多少个?原图800x600,VGG下采样16倍,feature map每个点设置9个Anchor,所以:
其中ceil()表示向上取整,是因为VGG输出的feature map size= 37*50。
![](https://img-blog.csdnimg.cn/20200419174919440.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMTk1MzYw,size_16,color_FFFFFF,t_70)
2.2 RPN的真值与预测量
理解RPN的预测量与真值分别是什么,也是理解RPN原理的关键。对于物体检测任务来讲,模型需要预测每一个物体的类别及其出现的位置,即类别、中心点坐标x与y、宽w与高h这5个量。由于有了Anchor这个先验框,RPN可以预测Anchor的类别作为预测边框的类别,并且可以预测真实的边框相对于Anchor的偏移量,而不是直接预测边框的中心点坐标x与y、宽高w与h。
举个例子,如图9所示,输入图像中有3个Anchors与两个标签,从位置来看,Anchor A、C分别和标签M、N有一定的重叠,而Anchor B位置更像是背景。
![](https://img-blog.csdnimg.cn/20200420101043139.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMTk1MzYw,size_16,color_FFFFFF,t_70)
首先介绍模型的真值。对于类别的真值,由于RPN只负责区域生成,保证recall,而没必要细分每一个区域属于哪一个类别,因此只需要前景与背景两个类别(二分类),前景即有物体,背景则没有物体。
RPN通过计算Anchor与标签的IoU来判断一个Anchor是属于前景还是背景。IoU的含义是两个框的公共部分占所有部分的比例,即重合比例。在图9中,Anchor A与标签M的IoU计算公式如式如下:
当IoU大于一定值时,该Anchor的真值为前景,低于一定值时,该Anchor的真值为背景。
然后是偏移量的真值。如图10所示绿色框为飞机的Ground Truth(GT),红色为提取的positive anchors,即便红色的框被分类器识别为飞机,但是由于红色的框定位不准,这张图相当于没有正确的检测出飞机。所以我们希望采用一种方法对红色的框进行微调,使得positive anchors和GT更加接近。
![](https://img-blog.csdnimg.cn/20200419180734374.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMTk1MzYw,size_16,color_FFFFFF,t_70)
对于窗口一般使用四维向量 ( )表示,分别表示窗口的中心点坐标和宽高。对于图 11,红色的框A代表原始的positive Anchors,绿色的框G代表目标的GT,我们的目标是寻找一种关系,使得输入原始的anchor A经过映射得到一个跟真实窗口G更接近的回归窗口G’,即:
- 给定anchor 和
- 寻找一种变换F,使得:
![](https://img-blog.csdnimg.cn/20200419181859646.png)
那么经过何种变换F才能从图11中的anchor A变为G’呢? 比较简单的思路就是:
- 先做平移
- 再做缩放
注:
其实我觉得接下来就没必要再细讲了,回归嘛!大家应该都是搞过机器学习的,这里就是用的回归最基本的思想。懂得就直接跳过这一节。
观察上面4个公式发现,需要学习的是 这四个变换。当输入的anchor A与GT相差较小时,可以认为这种变换是一种线性变换, 那么就可以用线性回归来建模对窗口进行微调(注意,只有当anchors A和GT比较接近时,才能使用线性回归模型,否则就是复杂的非线性问题了)。对应于Faster RCNN原文,平移量( )与尺度因子( )如下:
接下来的问题就是如何通过线性回归获得 了。
2.3 RPN卷积网络
为了实现上述的预测,RPN搭建了如图5、图12所示的网络结构。具体实现时,在feature map上首先用3×3的卷积进行更深的特征提取,然后利用1×1的卷积分别实现分类网络和回归网络。
![](https://img-blog.csdnimg.cn/20200419155823788.png)
![](https://img-blog.csdnimg.cn/20200420104001736.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMTk1MzYw,size_16,color_FFFFFF,t_70)
在物体检测中,通常我们将有物体的位置称为前景,没有物体的位置称为背景。在分类网络分支中,首先使用1×1卷积输出18×37×50的特征,由于每个点默认有9个Anchors,并且每个Anchor只预测其属于前景还是背景,因此通道数为18。随后利用torch.view()函数将特征映射到2×333(9*37)×50,这样第一维仅仅是一个Anchor的前景背景得分,并送到Softmax函数中进行概率计算,得到的特征再变换到18×37×50的维度,最终输出的是每个Anchor属于前景与背景的概率。
在回归分支中,利用1×1卷积输出36×37×50的特征,第一维的36包含9个Anchors的预测,每一个Anchor有4个数据,分别代表了每一个Anchor的中心点横纵坐标及宽高这4个量相对于真值的偏移量。
2.4 RPN真值的求取
上一节的RPN分类与回归网络得到的是模型的预测值,而为了计算预测的损失,还需要得到分类与偏移预测的真值,具体指的是每一个Anchor是否对应着真实物体,以及每一个Anchor对应物体的真实偏移值。求真值的具体实现过程如图13所示,主要包含4步,下面具体介绍。
![](https://img-blog.csdnimg.cn/20200420104830247.png)
1. Anchor生成
这部分与前面Anchor的生成过程一样,可以得到37×50×9=16650个Anchors。由于按照这种方式生成的Anchor会有一些边界在图像边框外,因此还需要把这部分超过图像边框的Anchors过滤掉。
2. Anchor与标签的匹配
为了计算Anchor的损失,在生成Anchor之后,我们还需要得到每个Anchor的类别,由于RPN的作用是建议框生成,而非详细的分类,因此只需要区分正样本与负样本,即每个Anchor是属于正样本还是负样本。前面已经介绍了通过计算Anchor与标签的IoU来判断是正样本还是负样本。在具体实现时,需要计算每一个Anchor与每一个标签的IoU,因此会得到一个IoU矩阵,具体的判断标准如下:
- 对于任何一个Anchor,与所有标签的最大IoU小于0.3,则视为负样本。
- 对于任何一个标签,与其有最大IoU的Anchor视为正样本。
- 对于任何一个Anchor,与所有标签的最大IoU大于0.7,则视为正样本。
需要注意的是,上述三者的顺序不能随意变动,要保证一个Anchor既符合正样本,也符合负样本时,赋予正样本。并且为了保证这一阶段的召回率,允许多个Anchors对应一个标签,而不允许一个标签对应多个Anchors。
3. Anchor的筛选
由于Anchor的总数量接近于2万,并且大部分Anchor的标签都是背景,如果都计算损失的话则正、负样本失去了均衡,不利于网络的收敛。在此,RPN默认选择256个Anchors进行损失的计算,其中最多不超过128个的正样本。如果数量超过了限定值,则进行随机选取。当然,这里的256与128都可以根据实际情况进行调整,而不是固定死的。
4. 求解回归偏移真值
上一步将每个Anchor赋予正样本或者负样本代表了预测类别的真值,而回归部分的偏移量真值还需要利用Anchor与对应的标签求解得到,具体公式见式:
得到偏移量的真值后,将其保存在bbox_targets中。与此同时,还需要求解两个权值矩阵bbox_inside_weights和bbox_outside_weights,前者是用来设置正样本回归的权重,正样本设置为1,负样本设置为0,因为负样本对应的是背景,不需要进行回归;后者的作用则是平衡RPN分类损失与回归损失的权重,在此设置为1/256。
2.5 损失函数的计算
有了网络预测值与真值,接下来就可以计算损失了。RPN的损失函数包含分类与回归两部分。
代表了256个筛选出的Anchors的分类损失, 为每一个Anchor的类别真值, 为每一个Anchor的预测类别。由于RPN的作用是选择出Proposal,并不要求细分出是哪一类前景,因此在这一阶段是二分类,使用的是交叉熵损失。值得注意的是,在F.cross_entropy()函数中集成了Softmax的操作,因此应该传入得分,而非经过Softmax之后的预测值。
代表了回归损失。回归损失使用了
函数。
函数结合了1阶与2阶损失函数,原因在于,当预测偏移量与真值差距较大时,使用2阶函数时导数太大,模型容易发散而不容易收敛,因此在大于1时采用了导数较小的1阶损失函数。
2.6 NMS与生成Proposal
完成了损失的计算,RPN的另一个功能就是区域生成,即生成较好的Proposal,以供下一个阶段进行细分类与回归。NMS生成Proposal的主要过程如图14所示。
![](https://img-blog.csdnimg.cn/20200420112333293.png)
Proposal Layer forward 按照以下顺序依次处理:
首先生成大小固定的全部Anchors,然后将网络中得到的回归偏移作用到Anchor上使Anchor更加贴近于真值,并修剪超出图像尺寸的Proposal,得到最初的建议区域。在这之后,按照分类网络输出的得分对Anchor排序,保留前12000个得分高的Anchors。由于一个物体可能会有多个Anchors重叠对应,因此再应用非极大值抑制(NMS)将重叠的框去掉,最后在剩余的Proposal中再次根据RPN的预测得分选择前2000个,作为最终的Proposal,输出到下一个阶段。
2.7 筛选Proposal得到RoI
在训练时,上一步生成的Proposal数量为2000个,其中仍然有很多背景框,真正包含物体的仍占少数,因此完全可以针对Proposal进行再一步筛选,过程与RPN中筛选Anchor的过程类似,利用标签与Proposal构建IoU矩阵,通过与标签的重合程度选出256个正负样本。
这一步有3个作用:
- 筛选出了更贴近真实物体的RoI,使送入到后续网络的物体正、负样本更均衡,避免了负样本过多,正样本过少的情况。
- 减少了送入后续全连接网络的数量,有效减少了计算量。
- 筛选Proposal得到RoI的过程中,由于使用了标签来筛选,因此也为每一个RoI赋予了正、负样本的标签,同时可以在此求得RoI变换到对应标签的偏移量,这样就求得了RCNN部分的真值。
具体实现时,首先计算Proposal与所有的物体标签的IoU矩阵,然后根据IoU矩阵的值来筛选出符合条件的正负样本。
筛选标准如下:
- 对于任何一个Proposal,其与所有标签的最大IoU如果大于等于0.5,则视为正样本。
- 对于任何一个Proposal,其与所有标签的最大IoU如果大于等于0且小于0.5,则视为负样本。
经过上述标准的筛选,选出的正、负样本数量不一,在此设定正、负样本的总数为256个,其中正样本的数量为p个。为了控制正、负样本的比例基本满足1:3,在此正样本数量p不超过64,如果超过了64则从正样本中随机选取64个。剩余的数量256-p为负样本的数量,如果超过了256-p则从负样本中随机选取256-p个。
经过上述操作后,选出了最终的256个RoI,并且每一个RoI都赋予了正样本或者负样本的标签。在此也可以进一步求得每一个RoI的真值,即属于哪一个类别及对应真值物体的偏移量。
3 RoI pooling层
上述步骤得到了256个RoI,以及每一个RoI对应的类别与偏移量真值,为了计算损失,还需要计算每一个RoI的预测量。
前面的VGGNet网络已经提供了整张图像的feature map,因此自然联想到可以利用此feature map,将每一个RoI区域对应的特征提取出来,然后接入一个全连接网络,分别预测其RoI的分类与偏移量。
然而,由于RoI是由各种大小宽高不同的Anchors经过偏移修正、筛选等过程生成的,因此其大小不一且带有浮点数,然而后续相连的全连接网络要求输入特征大小维度固定,这就需要有一个模块,能够把各种维度不同的RoI变换到维度相同的特征,以满足后续全连接网络的要求,于是RoI Pooling就产生了。
对RoI进行池化的思想在SPPNet中就已经出现了,只不过在Fast RCNN中提出的RoI Pooling算法利用最近邻差值算法将池化过程进行了简化,而在随后的Mask RCNN中进一步提出了RoI Align的算法,利用双线性插值,进一步提升了算法精度。
![](https://img-blog.csdnimg.cn/20200419154156746.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMTk1MzYw,size_16,color_FFFFFF,t_70)
在此我们举一个例子来讲解这几种算法的思想,假设当前RoI大小为332×332,使用VGGNet的全连接层,其所需的特征向量维度为512×7×7,由于目前的特征图通道数为512,Pooling的过程就是如何获得7×7大小区域的特征。
3.1 RoI Pooling简介
RoI Pooling的实现过程如图15所示,假设当前的RoI为图4.9中左侧图像的边框,大小为332×332,为了得到这个RoI的特征图,首先需要将该区域映射到全图的特征图上,由于下采样率为16,因此该区域在特征图上的坐标直接除以16并取整,而对应的大小为332/16=20.75。在此,RoI Pooling的做法是直接将浮点数量化为整数,取整为20×20,也就得到了该RoI的特征,即图15中第3步的边框。
![](https://img-blog.csdnimg.cn/20200420115249818.png)