Faster R-CNN原理详解

(一)前言:

2014年R-CNN结构的提出,首次将卷积神经网络带入目标检测领域。2015年发表的Fast R-CNN,流程更为紧凑,大幅提高目标检测速度。
在这里插入图片描述
但是Fast R-CNN在区域建议(即候选框的提取)上耗费了大量时间。

为了解决这个问题,作者提出了Faster R-CNN网络,其中最主要的贡献就是使用了RPN(Region Proposal Networks,区域生成网络)和ROI Pooling(Region of Interest)层,使检测的综合性能有了大幅提升。

(二)网络结构:

2.1 整体结构解析

在这里插入图片描述

整体结构如图所示,具体过程为:

  1. 通过conv layers(通常采用VGG)在原图上提取特征图feature maps;
  2. 通过Region Proposal Network(RPN层)生成不同大小的anchors,并提取anchors中的目标候选框(即prior box);
  3. 将这些目标候选框映射回feature maps的区域,这些区域称之为ROI(Region of Interest, 感兴趣区域);
  4. 通过classifier(分类器)对ROI进行分类和坐标框预测;

数据流为:

  1. conv layers传入图像,生成Feature maps;
  2. 通过RPN层,输出每个点对应不同大小候选框(anchors)的背景判别得分和初步的坐标框预测值;
  3. 将正样本映射回feature maps上的区域并截取出来;
  4. 对截取出来的不同区域(大小可能不同)进行ROI Pooling,使其获得固定尺寸输出;
  5. 最后通过classifier对ROI Poolling的结果进行类别判断和坐标框预测;

看到这里可能还是有些懵圈,但是不要担心,这里只是大体讲一下网络的结果,结构单元和细节处理过程会在下面详细讲。

2.2 Conv Layers:获取feature map

在这里插入图片描述
我们以VGG-16作为Conv Layers为例,简单地写一下:

# vgg-16
def vgg16(inputs):

    net = conv2d(inputs, filters=64)
    net = conv2d(net, filters=64)

    net = max_pool2d(net, k=2, strides=2)

    net = conv2d(net, filters=128)
    net = conv2d(net, filters=128)

    net = max_pool2d(net, k=2, strides=2)

    net = conv2d(net, filters=256)
    net = conv2d(net, filters=256)
    net = conv2d(net, filters=256)

    net = max_pool2d(net, k=2, strides=2)

    net = conv2d(net, filters=512)
    net = conv2d(net, filters=512)
    net = conv2d(net, filters=512)

    net = max_pool2d(net, k=2, strides=2)

    net = conv2d(net, filters=512)
    net = conv2d(net, filters=512)
    net = conv2d(net, filters=512)

    return net

假设输入图片为300×300大小,经过卷积层和总共4个步长为2的max pooling,我们就得到了一个19×19×512大小的feature map(就是图中黑乎乎的那个)。

2.3 RPN层:获取正样本区域(Proposals)

在这里插入图片描述

2.3.1 anchors的生成:

anchors 指的是在原图上生成的所有候选框。由于一张图中需要检测到的目标可能大小不同、位置不同,所以我们需要位置、大小和长宽比各不相同的anchors 在原图上选出候选区域,再判断这些候选区域是否为物体,以及与真值框(真实坐标)的偏移量。
在这里插入图片描述
在论文中,图(a)、图(b)描述的是之前的目标检测框架使用的对不同大小目标的检测方法:

要么使用图像金字塔(如图a),即将图像缩放成不同大小比例生成不同大小的feature maps来检测;
要么使用不同大小的多个卷积核(如图b),对同一个feature maps做多次检测;

但这些方法都大大增加了在提取候选框上的时间消耗。

而作者提出了,可以使用相同大小的卷积核而且不需要使用图像金字塔,在同一个feature map上,对不同大小的候选框(文章中称之为anchors)来同时进行预测。
在这里插入图片描述

这样如果我们输入的图像大小为M×N×3,经过conv layers获得的feature map大小为 (M/16)×(N/16)×512,其中feature map上的每个点都能在原图上映射为一个相应区域。
在这里插入图片描述
对每个特征点对应的映射区域,我们生成3种不同边长和对应3种不同长宽比,3×3共9个anchors(候选框);边长分别为【128, 256, 512】,长宽比分别为【1:1,1:2,2:1】,如图所示):
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这样我们就通过每个特征点对相应区域生成大小不同、长宽比也各不相同的候选框(anchors),对每个M×N大小的图片生成共(M/16)×(N/16)×9个anchors,实现了对候选区域的初步选取。

2.3.2 正负样本的判别:

先讲一下IOU的概念,IOU是描述两个区域重叠程度的一个量,计算方式如图:
在这里插入图片描述
在训练过程中,我们需要分别计算这些anchors与传入的真值框的IOU值,将其中IOU值大于某一阙值(论文中取0.8)的anchors标记为正样本,称之为prior boxes(先验框),如图(绿色为真值框,红色为正样本):
在这里插入图片描述
在这里插入图片描述

这一步就是将与真值框重叠程度较高的anchors筛选出来,用于进一步判别其表示对物体类别并预测与真值框的偏移。

我们这时可以看到,由于我们选取的anchors都是固定大小和固定位置,即使初步筛选出来的正样本,也依然与真值框有一定的偏差,因此我们就将这个偏差量化表示,作为预测的回归值,这步操作称为bounding box regression
在这里插入图片描述
式中,t代表target,即回归值;

训练模型时,我们由于输入了真值框(ground-truth box),就能够计算预测回归的目标值:
在这里插入图片描述
X*,Y*,W*,H*分别是真值框的中心坐标及其宽高;
Xa,Ya,Wa,Ha则分别是anchors的中心坐标及其宽高;

这样的话得出来的 t* 的4个值,就分别是anchor对应应该回归的中心坐标偏移量和宽高的偏移大小。

进行预测时,没有真值框的输入,我们则通过卷积层预测 t 的4个值(在训练过程中 t 不断地向 t* 回归),再通过公式:
在这里插入图片描述
将X,Y,W,H反解出来,就得到了最终的目标框的预测坐标。

2.3.4 简单的代码实现:

在这里插入图片描述

def RPN_net(feature_map):

    rpn_feature = conv2d(feature_map, k_size=3, filters=256) # 256-d

    num_anchors = 3*3

    scores = conv2d(rpn_feature, 2*num_anchor,
                    k_size=1, activation=None)

    coordinates = conv2d(rpn_feature, 4*num_anchor,
                	 k_size=1, activation=None)
                
    return scores, coordinates

其中:

  1. 使用了1×1大小的卷积层代替全连接层,以适应不同大小的图片输入(注意原图上的sliding window(即卷积核)大小为3×3,应该是为了让读者看得更清除一些,但实际上卷积核采用的还是1×1大小);
  2. scores是每个特征点的每个anchors的背景or物体的判别得分;其中每个特征点的输出大小为2*9,2代表这是一个二分类(背景or物体),9代表每个特征点对应9个anchors;
  3. coordinates 即每个特征点的每个anchors的坐标偏移量预测(即公式中的tx,ty,tw,th);

2.3.3 训练过程中正负样本的筛选:

我们可以计算出,每张图片我们会生成(M/16)×(N/16)×9个anchors,即对一张600×600大小的图片,总共会生成38×38×9接近一万三千个anchors,其中大部分的anchors都是负样本,而如图只有少数anchors能够标记为正样本:

在这里插入图片描述
这样的话如果对所有anchors都进行梯度下降,那么我们最后反向传播得到的梯度中正样本的影响就会微乎其微,导致模型难以收敛;不仅如此,对如此大量的数据进行处理,也大大拖延了训练模型的时间。

作者为了解决以上问题,提出了解决办法:
在这里插入图片描述

即训练时,每张图片只随机取256个anchors参与Loss的计算,其中正负样本的比例控制为1:1,即128个正样本和128个负样本;如果一张图片的正样本不足128个,那就用负样本进行填充;这样筛选出来的样本区域,就称之为Proposals

其余样本不参与Loss计算,其Loss置零。

2.4 ROI Pooling层:约束映射区域大小

在这里插入图片描述

2.4.1 传统检测中的问题:

对于传统的CNN,当网络训练好后输入的图像尺寸必须是固定值,同时网络输出也是固定大小的向量或者矩阵。如果输入图像大小不定,这个问题就变得比较麻烦。有2种解决办法:
在这里插入图片描述

一是通过crop的方法,即只裁剪图片的一部分;
二是通过warp的方法,将图片缩放到指定大小;

但这两种方式都会破坏图片的结构信息。

作者则提出了可以使用ROI Pooling,既能够获得固定大小区域也能保留这一图片区域的结构信息。

2.4.2 ROI Pooling原理:

这里参考了Elag大佬的ROI Pooling讲解https://blog.csdn.net/u011436429/article/details/80279536

(1)我们以一个8×8大小的feature map为例,调整ROI Pooling的输出大小参数为2×2(原文中为7×7):
在这里插入图片描述

(2)假设一个Proposals在feature map上的映射区域为:
(左上角,右下角坐标):(0,3),(7,8),如图
在这里插入图片描述

(3)我们将其划分为(2×2)个sections(因为输出大小为2×2):
在这里插入图片描述

(4)然后对每个区域分别进行max pooling,就得到了固定大小的输出:
在这里插入图片描述

如果放到原文中,过程为:

  1. 通过RPN网络,提取出了256个Proposals(包含正、负样本);
  2. 在feature map(大小为(M/16)×(N/16)×512)上映射为256个区域;
  3. 最后通过ROI Pooling,得到大小为256×7×7×512的输出;

2.5 Classifier:预测物体类别和预测框偏移量

Classifier 的作用是对ROI Pooling 输出的256×7×7×512矩阵对应的Proposals,进行物体类别的预测;并且由于第一次对正样本anchors进行坐标框偏移量预测生成Proposals时并不精准,这里需要对Proposals再次进行bounding box regress。

2.5.1 Classifier的结构:

在这里插入图片描述

2.5.2 Classifier的代码实现:


def classifier(roi_pooling, is_training=True):

    pool5_flat = tf.layers.flatten(roi_pooling) # (256, 7*7*512)

    fc6 = tf.layers.dense(pool5_flat, 4096)

    if is_training:
        fc6 = tf.layers.dropout(fc6, rate=0.5)

    fc7 = tf.layers.dense(fc6, 4096)
    if is_training:
        fc7 = tf.layers.dropout(fc6, rate=0.5)

    cls_scores = tf.layers.dense(fc7, num_classes,
                                 activation=None) # (256, num_classes)
    reg_pred = tf.layers.dense(fc7, 4,
                               activation=None) # (256, 4)
                               
    return cls_scores, reg_pred

这样就得到了对应256个Proposals的物体类别向量(cls_scores)和偏移值预测(reg_pred,公式中的t*的四个值)。

(三)实验结果:

在这里插入图片描述
在这里插入图片描述

如果觉得对您有帮助的话,记得点赞关注哦

我们下期再见~

在这里插入图片描述

发布了58 篇原创文章 · 获赞 117 · 访问量 6792

猜你喜欢

转载自blog.csdn.net/weixin_44936889/article/details/103788908
今日推荐