跟着问题学3.3——Faster R-CNN详解及代码实战(1)
Fast R-CNN的不足
- 选取区域使用的算法是固定的,不参与学习
- 选取区域的算法本身消耗比较高 (搜索选择法)
- 选取区域的算法选出来的区域大部分都是重合的,并且只有很小一部分包含我们想要识别的对象
- 区域范围的精度比较低 (即使经过调整)
- 判断分类有时只能使用部分包含对象的区域 (例如选取区域的算法给出左半张脸所在的区域,那么就只能使用左半张脸判断分类)
Faster-RCNN 是 RCNN 和 Fast-RCNN 的进化版,最大的创新是引入了区域生成网络 (RPN - Region Proposal Network),区域生成网络支持使用机器学习代替固定的算法找出图片中可能包含对象的区域,精度比固定的算法要高很多,而且速度也变快了。
从R-CNN到Fast R-CNN,再到本文的Faster R-CNN,目标检测的四个基本步骤(候选区域生成,特征提取,分类,位置精修)终于被统一到一个深度网络框架之内。所有计算没有重复,完全在GPU中完成,大大提高了运行速度。
Faster R-CNN可以简单地看做“区域生成网络(RPN)+Fast RCNN“的系统,用区域生成网络代替Fast R-CNN中的Selective Search方法
Faster R-CNN的网络框架
如上图所示,Faster R-CNN网络框架可以分为4大部分,分别是(1)骨干卷积网络层(conv layers)用于提取特征图(2)区域推荐网络(Region Proposal Network)输出图像上的anchor类别和第一次调整边界框位置;(3)RoI池化层输出统一尺度的候选框特征图;(4)分类器(classifier)用于输出候选框的类别同时第二次回归边界框的精确位置;
上图是以VGG16为骨干网络的Faster R-CNN模型的网络结构,再进一步的观察4个部分的模型细节:
(1)骨干卷积网络层(conv layers):首先预处理将尺寸为P*Q的图像转变为M*N的图像,然后将此图像送入骨干网络提取特征,骨干网络包含了13个conv层+13个relu层+4个pooling层(卷积层和池化层的设置可根据选用的骨干网络切换),然后输出特征图,该特征图共享用于后面的RPN和ROI层;
(2)区域推荐网络(Region Proposal Network):该部分首先利用3*3的卷积层进一步对特征图进行提取,然后送入2个分支,第一个分支为1*1*18的卷积层(18是通道数,后面为解释实际意义),然后经过softmax输出边界框内二分类是否含有物体(positive或者negative);第二个分支为1*1*36的卷积层,回归输出确定边界框(bounding box regression);
(3)RoI池化层:该部分利用骨干卷积网络层输出的特征图(feature maps)和区域推荐网络输出的候选框(proposals),结合图像缩放尺度等信息,输出推荐候选框对应的固定尺寸特征图(proposal feature maps);
(4)分类器和回归层:该部分根据ROI池化层输出的特征图,经过全连接层输出候选框的位置(bounding box regression)和具体类别(多分类)。
下面我们将详细地学习一下这4个部分的细节。
Fast R-CNN的输入
和 Fast-RCNN 一样,Faster-RCNN 也会使用 CNN 模型针对整张图片生成各个区域的特征,所以我们需要缩放原图片。(尽管 CNN 模型支持非固定大小的来源,但统一大小可以让后续的处理更简单,并且也可以批量处理大小不一样的图片。)
骨干卷积网络conv layers
如前面所说,骨干卷积网络一般直接借用VGG,ResNet等网络结构,包含了conv,pooling,relu三种网络层,值得注意的有下面2点:
(1)特征图尺寸的变化:骨干网络中,conv层一般只卷积提取特征,通过padding填充使得特征图的宽高尺寸不会变化,而池化pool层一般会使得宽高尺寸缩小2倍。
以VGG16模型为例:
Conv layers部分共有13个conv层,13个relu层,4个pooling层,所有的conv层的设置都是:kernel_size=3 ,pad=1,stride=1;所有的pooling层都是:kernel_size=2,pad=0,stride=2。因此,一个MxN大小的矩阵经过Conv layers固定变为(M/16)x(N/16)(注意这里的16是VGG16模型的4个池化层计算得到的,记为spatial_scale)!这样Conv layers生成的特征图feature map中都可以和原图对应起来,VGG16模型下,特征图的每个像素点对应着原图16*16的区域。
(2)特征图通道数的变化:最初的输入图像一般是3通道的,经过骨干网络后,会得到特征图,这时的特征图除了第一点讲到的尺寸的变化,还有一个重要的点是通道数的变化,比如VGG16模型最终的特征图是256通道的,这个通道数会随着选用模型的不同而变化,后面在区域生成网络中会再一次提到。
以VGG16模型再次概述,其输入图像张量大小(channels,width,height)为 [3, 256, 256],经过VGG16 模型特征提取得到输出feature维度为 [256, 32, 32]。过程中数据经过4次2*2的MaxPool,特征进行了16倍缩放,相应地原边界框位置和大小也会进行等比例缩放。
区域推荐网络(RPN)
经典的检测方法生成检测框都非常耗时,如OpenCV adaboost使用滑动窗口+图像金字塔生成检测框;或如R-CNN使用SS(Selective Search)方法生成检测框。而Faster RCNN则抛弃了传统的滑动窗口和SS方法,直接使用RPN生成检测框,这也是Faster R-CNN的巨大优势,能极大提升检测框的生成速度。
前面介绍了骨干特征提取网络,图像也从最初的输入变为了高维特征图,尺寸缩放了,通道数增加了,接下来我们详细看一下区域推荐网络是如何利用这些特征图输出推荐框(proposals)的。
图 RPN网络结构
上图展示了RPN网络的具体结构。可以看到RPN网络实际分为2条支路,上面一条通过softmax可将anchors二分类为positive和negative,下面一条支路用于计算对于anchors的bounding box regression偏移量,以获得精确的proposals。而最后的Proposal层则负责综合positive anchors和对应bounding box regression偏移量获取proposals,同时剔除太小和超出边界的proposals。整个网络到了Proposal Layer这里,其实就已经初步完成了目标定位的功能。
下面进行详细地介绍
多通道特征图和1*1卷积核
在介绍RPN前,我们先来回顾一下多通道特征图和1*1卷积核的知识。经过前面的学习,我们已经知道对于最初输入为RGB 3通道的输入图,经过卷积神经网络的特征提取,每一层都可以设置不同的通道数,这时我们认为每一个通道都表征了原始图片的某一种特征,其计算方式如下图所示:
图 多通道卷积计算方式
输出特征图的计算方法就是卷积核和对应通道的输入特征图卷积,然后得到多通道的输出,再相加合并成一个输出特征图。若输出通道数设为3,则应该有3组卷积核,每组仍是2通道,每一组会输出一个特征图,合起来共输出3通道的特征图。
前面讲的多通道表征特征是一个泛化的概念,但是需要注意的是,RPN网络直接把通道作为输出的具体概念,即候选框的类别概率和候选框的位置,这点后面详细介绍。
理解了前面多通道的概念,最后我们讨论一下卷积核尺寸为(1*1)的多通道卷积层。我们通常称之为1*1卷积层, 并将其中的卷积运算称为1*1卷积。
下图展示了使用输入通道数为3、输出通道数为2的1*1卷积核计算。可以看到,输入和最终的输出具有相同的高和宽,输出的通道数取决于卷积核的组数,每一通道的输出特征图由一组卷积核对输入特征不同通道相同位置的元素按权重累加得到。具体到图中,输出特征图中浅蓝色的神经元由输入通道对应位置的浅蓝色的神经元经过一组浅蓝色的卷积核(权重参数)加权求和得到,这其实是一种特殊的“全连接层”,即相当于把原图像中本来各个独立的通道“联通”在了一起,不过卷积核是固定不变的。
因为卷积核尺寸为1*1,所以1*1卷积不再能感受相邻元素,也就意味着计算只在通道维度上发生,这也代表着1*1卷积的主要作用是用来改变通道数。
anchors
目标检测的核心任务之一就是在图像上“框”出物体的位置,如下图。
那么如何得到这一个个框呢?其根本思路便是遍历图像上的每个像素点,然后在每个像素点上附加不同大小的框,然后判断哪个框是最合适的,Fast R-CNN也是在此思路上进行优化改进的,不再是简单的遍历,而是利用RPN网络直接训练生成。
提到RPN网络,就不能不说anchors。所谓anchors,实际上就是一组矩形框(一般设为9个)。9个矩形共有3种形状(128,256,512...),但在代码中一般不是直接用这个尺寸,而是将其乘上宽高比值的开方,宽高比为一般为三种1;2,1:1,2:1如下图。实际上通过anchors就引入了检测中常用到的多尺度方法。
图 anchors示意图
由rpn/generate_anchors.py生成的矩形。直接运行作者demo中的generate_anchors.py可以得到以下输出:
[[ -84. -40. 99. 55.]
[-176. -88. 191. 103.]
[-360. -184. 375. 199.]
[ -56. -56. 71. 71.]
[-120. -120. 135. 135.]
[-248. -248. 263. 263.]
[ -36. -80. 51. 95.]
[ -80. -168. 95. 183.]
[-168. -344. 183. 359.]]
其中每行的4个值表示矩形左上和右下角点坐标。这9个anchor框是基本候选框,下面就是利用这些框去遍历特征图上的每个像素点,得到整张特征图上所有的候选框。
注:关于上面的anchors size,其实是根据检测图像设置的。在python demo中,会把任意大小的输入图像reshape成800x600(即M=800,N=600)。再回头来看anchors的大小,anchors中长宽1:2中最大为352x704,长宽2:1中最大736x384,基本是cover了800x600的各个尺度和形状。
补充一点,全部anchors拿去训练太多了,训练程序会在合适的anchors中随机选取128个postive anchors+128个negative anchors进行训练(什么是合适的anchors下文有解释)
那么Anchor一共有多少个?原图800x600,VGG下采样16倍,feature map每个点设置9个Anchor,所以:
其中ceil()表示向上取整,是因为VGG输出的feature map size= 50*38。
图 Gernerate Anchors
二分类与第一次候选框回归
有了基础anchor之后,又该如何判断anchor的类别和位置呢?借用Faster RCNN论文中的原图,首先遍历Conv layers计算获得的feature maps,为每一个点都配备这9种anchors作为初始的检测框。这样做获得检测框很不准确,后面还有2次bounding box regression可以修正检测框位置。
解释一下上面这张图的数字256-d,2k scores和4k coordinates。
(1)在原文中使用的是ZF model中,其Conv Layers中最后的conv5卷积层的通道数num_output=256,对应生成256张特征图,所以相当于feature map每个点都是256-dimensions。
在conv5卷积层之后,RPN网络层先做了3x3卷积且num_output=256,相当于每个点又融合了周围3x3的空间信息),同时通道数256-d不变。注意这里的通道数还仅仅是泛化的高维特征。
(2)接下来RPN网络便是通过1*1卷积层将通道转变为了含有具体意义的是否含有目标值的得分和候选框的偏移量。假设在feature maps中每个点上有k个anchor(默认k=9),而每个anhcor要分positive和negative,所以每个点由256d feature转化为cls=2•k scores,注意这里的通道代表的是候选框的得分;这一步的本质就是给特征图的每个像素点设置候选anchor,然后用1*1卷积和softmax去判断哪些Anchor是里面有目标的positive anchor,哪些是没目标的negative anchor。所以,仅仅是个二分类而已!
(3)每个anchor都有(x, y, w, h)4个偏移量,所以reg=4•k coordinates,这里的每个通道代表一个偏移量,4个通道代表一个候选框的位置偏移量。每个像素点有k个候选框,因此一共有4k个通道来表征偏移量,这一步就是第一次的bounding box regression。
举例说明一下,如图所示绿色框为飞机的真实框Ground Truth(GT),红色为提取的含有目标的候选框positive anchors,即便红色的框被分类器识别为飞机,但是由于红色的框定位不准,这张图相当于没有正确的检测出飞机。所以我们希望采用一种方法对红色的框进行微调,使得positive anchors和GT更加接近。
对于候选框一般使用四维向量(x,y,w,h)表示,分别表示框的中心点坐标和宽高。对于下图,红色的框A代表原始的positive Anchors,绿色的框G代表目标的GT,我们的目标是寻找一种关系,使得输入原始的anchor A经过映射得到一个跟真实窗口G更接近的回归窗口G',即:
如何变换映射下面的损失函数部分再进行详细的说明。
非极大值抑制nms算法流程
非极大值抑制通过目标置信度对边界框进行筛选,其具体流程如下:
(1)初始化输出列表 out_bboxes = [ ];
(2)获取输入边界框 in_bboxes 对应的目标类别置信度;
(3)将照置信度由高到低的方式对边界框进行排序;
(4)选取置信度最高的边界框 bbox_max,将其添加到 out_bboxes 中,并计算它与其他边界框的IoU结果;
(5)IoU大于阈值的表明两区域较为接近,边界框重叠性较高,将这些框和bbox_max从 in_bboxes 中移除;
(6)重复执行3~5过程,直到 in_bboxes 为空,此时 out_bboxes 即最终保留的边界框结果。
Proposal Layer
Proposal Layer负责综合所有变换量和positive anchors,计算出精准的proposal,送入后续RoI Pooling Layer。
Proposal Layer有3个输入:二分类器结果positive vs negative anchors,对应的候选框偏移量的预测值rpn_bbox_pred,以及im_info;另外还有参数feat_stride=16。
首先解释im_info。对于一副任意大小PxQ图像,传入Faster R-CNN前首先reshape到固定MxN,im_info=[M, N, scale_factor]则保存了此次缩放的所有信息。然后经过Conv Layers,经过4次pooling变为WxH=(M/16)x(N/16)大小,其中feature_stride=16则保存了该信息,用于计算anchor偏移量。
Proposal Layer forward按照以下顺序依次处理:
(1)生成anchors,利用对所有的anchors做bbox regression回归(这里的anchors生成和训练时完全一致);
(2)按照输入的候选框内含有目标的得分positive softmax scores由大到小排序anchors,提取得分排序靠前的pre_nms_topN(e.g. 6000)个anchors,即提取修正位置后的positive anchors;
(3)限定超出图像边界的positive anchors为图像边界,防止后续roi pooling时proposal超出图像边界;
(4)剔除尺寸非常小的positive anchors;
(5)对剩余的positive anchors进行非极大值抑制NMS(nonmaximum suppression);
(6)输出proposal=[x1, y1, x2, y2],注意,由于在第三步中将anchors映射回原图判断是否超出边界,所以这里输出的proposal是对应MxN输入图像尺度的。
RoI pooling
区域推荐网络RPN最终会输出不定数量的可能包含对象的区域,接下来就是提取这些区域对应的特征了,注意区域推荐网络RPN使用的特征和标签分类网络使用的特征需要分开。
为何需要RoI Pooling
先来看一个问题:对于传统的CNN(如AlexNet和VGG),当网络训练好后输入的图像尺寸必须是固定值,同时网络输出也是固定大小的张量。如果输入图像大小不定,这个问题就变得比较麻烦。有2种解决办法:
- 从图像中crop一部分传入网络
- 将图像warp成需要的大小后传入网络
两种办法的示意图如图,可以看到无论采取那种办法都不好,要么crop后破坏了图像的完整结构,要么warp破坏了图像原始形状信息。
回忆RPN网络生成的proposals的方法:每个像素点生成的大小和比例均是不同的,再加上后面的回归校正以及删去超出图像边界等操作,最终获得的proposals也是大小形状各不相同,即也存在上述问题。所以Faster R-CNN中提出了RoI Pooling解决这个问题。RoI Pooling也是从Spatial Pyramid Pooling发展而来得。
RoI Pooling原理
RoI Pooling层负责收集proposal,并计算出推荐特征图(proposal feature maps),并统一推荐特征图的尺寸大小,送入后续网络。
计算具体过程如下:
(1)Rol pooling层有3个输入:原始的feature maps,RPN网络输出的推荐候选框(proposal bounding boxes)(大小各不相同)和im_info。
(2)由于RPN输出的候选框proposal是对应(M/16)x(N/16)尺寸的特征图,需要先使用spatial_scale参数将其映射回MxN尺寸的特征图feature map;
(3)再将每个候选框proposal对应的feature map区域最大池化为 pool_w*pool_h(论文为7*7)的网格;
这样处理后,即使大小不同的proposal输出结果都是 pool_w*pool_h 固定大小,实现了固定长度输出。
分类器和回归器Classification
Classification部分利用已经获得的推荐特征图(proposal feature maps),通过全连接(full connect)层与softmax计算每个候选框proposal具体属于那个类别(如人,车,电视等,多分类),输出cls_prob概率向量;同时再次利用边界框回归(bounding box regression)获得每个候选框(proposal)的位置偏移量(bbox_pred),用于回归更加精确的目标检测框。网络结构如图:
从RoI Pooling获取到7x7=49大小的推荐特征图proposal feature maps后,送入后续网络,可以看到做了如下2件事:
- 通过全连接和softmax对proposals进行分类,这实际上已经是识别的范畴了
- 再次对proposals进行bounding box regression,获取更高精度的rect box。
因为坐标和长宽的值大小不一定,例如同样是脸的左半部分,出现在图片的左上角和图片的右下角就会让 x y 坐标不一样,如果远近不同那么长宽也会不一样,我们需要把调整量作标准化,标准化的公式如下:
- x1, y1, w1, h1 = 候选区域
- x2, y2, w2, h2 = 真实区域
- x 偏移 = (x2 - x1) / w1
- y 偏移 = (y2 - y1) / h1
- w 偏移 = log(w2 / w1)
- h 偏移 = log(h2 / h1)
经过标准化后,偏移的值就会作为比例而不是绝对值,不会受具体坐标和长宽的影响。此外,公式中使用 log 是为了减少偏移的增幅,使得偏移比较大的时候模型仍然可以达到比较好的学习效果。
这里来看看全连接层InnerProduct layers,简单的示意图如图,
其计算公式如下:
其中W和bias B都是预先训练好的,即大小是固定的,当然输入X和输出Y也就是固定大小。所以,这也就印证了之前Roi Pooling的必要性。
参考资料
https://zhuanlan.zhihu.com/p/31426458
FasterRCNN_哔哩哔哩_bilibili