一、目标检测之R-FCN

R-FCN: Object Detection via Region-based Fully Convolutional Networks
(R-FCN:基于区域的全卷积网络的目标检测)

二、R-FCN介绍

1、R-FCN贡献

  • 二阶段目标检测,基于区域的全卷积网络,几乎所有计算都在整张图像上共享;
  • 提出Position-sensitive score maps来解决目标检测的位置敏感性问题;
  • 比Faster-RCNN快2.5-20倍(在K40GPU上面使用ResNet-101网络可以达到 0.17 sec/image);

2、R-FCN与R-CNN系列的异同点
目标检测之R-FCN

  • 相同点:首先,均为二阶段的检测框架(全卷积子网络+RoI-wise subnetwork); 其次两者最终输出的结果都是相应的类别和对应的BB;
  • 不同点
    如上图所示,我们可以看到和Faster R-CNN相比,R-FCN具有更深的共享卷积网络层,这样可以获得更加抽象的特征;同时,它没有RoI-wise subnetwork,不像Faster R-CNN的feature map左右都有对应的网络层,它是真正的全卷积网络架构;从图中的表格可以看出Faster R-CNN的共享卷积子网络是91层,RoI-wise子网络是10层,而R-FCN只有共享卷积子网络,深度为101层。与R-CNN相比,最大的不同就是直接获得整幅图像的feature map,再提取对应的ROI,而不是直接在不同的ROI上面获得相应的feature map,这就解决了目标检测中位置敏感性问题;

3、理解分类网络的位置不敏感性和检测网络的位置敏感性
目标检测之R-FCN

  • 分类网络的位置不敏感性:对于分类任务而言,希望我的网络有一个很好地分类性能,随着某个目标在图片中不断的移动,我的网络仍然可以准确的将你区分为对应的类别。如上图左边所示,不管你这只鸟在图片中如何移动,我的分类网络都能准确的将你分类为鸟。实验表明,深的全卷积网络能够具备这个特性,如ResNet-101等。

  • 检测网络的位置敏感性:对于检测任务而言,我希望我的网络有一个好的检测性能,可以准确的输出目标所在的位置值。随着某个目标的移动,我的网络希望能够和它一起移动,仍然能够准确的检测到它,即我对目标位置的移动很敏感。我需要计算对应的偏差值,我需要计算我的预测和GT的重合率等。但是,深的全卷积网路不具备这样的一个特征。

4、R-FCN动机
Faster R-CNN是利用CNN来完成proposals的预测的,Faster R-CNN系列的网络都可以分成2个部分:

  • Fully Convolutional subnetwork before RoI Layer
  • RoI-wise subnetwork

第一部分: 直接用普通分类网络的卷积层,用其来提取共享特征,然后一个RoI Pooling Layer在第1部分的最后一张特征图上进行提取针对各个RoIs的特征向量(或者说是特征图,维度变换一下即可),然后将所有RoIs的特征向量都交由第二部分来处理(分类和回归);
第二部分: 一般都是一些全连接层,在最后有2个并行的loss函数:softmax和smoothL1,分别用来对每一个RoI进行分类和回归,这样就可以得到每个RoI的真实类别和较为精确的坐标和长宽了;

注意! 第一部分都是像VGG、GoogleNet、ResNet之类的基础分类网络,这些网络的计算都是所有RoIs共享的,在一张图片测试的时候只需要进行一次前向计算即可。而对于第二部分的RoI-wise subnetwork,它却不是所有RoIs共享的,因为这一部分的作用就是“给每个RoI进行分类和回归”,所以当然不能共享计算。那么现在问题就处在这里,首先第1部分的网络具有“位置不敏感性”,而如果我们将一个分类网络比如ResNet的所有卷积层都放置在第1部分用来提取特征,而第2部分则只剩下全连接层,这样的目标检测网络是“位置不敏感的translation-invariance”,所以其检测精度会较低,并且也白白浪费了分类网络强大的分类能力(does not match the network’s superior classification accuracy)。而ResNet论文中为了解决这样的位置不敏感的缺点,做出了一点让步,即将RoI Pooling Layer不再放置在ResNet-101网络的最后一层卷积层之后而是放置在了“卷积层之间”,这样RoI Pooling Layer之前和之后都有卷积层,并且RoI Pooling Layer之后的卷积层不是共享计算的,它们是针对每个RoI进行特征提取的,所以这种网络设计,其RoI Pooling Layer之后就具有了“位置敏感性translation-variance”,但是这样做牺牲了测试速度,因为所有RoIs都要经过若干层卷积计算,测试速度会很慢。

三、R-FCN算法

1、R-FCN框架
目标检测之R-FCN
步骤:

  • 首先,我们选择一张需要处理的图片,并对这张图片进行相应的预处理操作;
  • 接着,我们将预处理后的图片送入一个预训练好的分类网络中(这里使用了ResNet-101网络的Conv4之前的网络),固定其对应的网络参数;
  • 接着,在预训练网络的最后一个卷积层获得的feature map上存在3个分支,第1个分支就是在该feature map上面进行RPN操作,获得相应的ROI;第2个分支就是在该feature map上获得一个K* K*(C+1)维的位置敏感得分映射(position-sensitive score map),用来进行分类;第3个分支就是在该feature map上获得一个4* K* K维的位置敏感得分映射,用来进行回归;
  • 最后,在K* K*(C+1)维的位置敏感得分映射和4* K* K维的位置敏感得分映射上面分别执行位置敏感的ROI池化操作(Position-Sensitive Rol Pooling,这里使用的是平均池化操作),获得对应的类别和位置信息。

2、Position-Sensitive Score Map解析
目标检测之R-FCN
R-FCN的主要设计思想就是“位置敏感得分图(position-sensitive score map)”。现在我们来解释一下其设计思路。如果一个RoI中含有一个类别C的物体,我们将该RoI划分为K* K个区域,其分别表示该物体的各个部位,比如假设该RoI中含有的目标是人,K=3,那么就将“人”划分成了9个子区域,top-center区域应该是人的头部,而bottom-center应该是人的脚部,我们将RoI划分为K*K个子区域是希望这个RoI在其中的每一个子区域都应该含有该类别C的物体的各个部位,即如果是人,那么RoI的top-center区域就应该含有人的头部。当所有的子区域都含有各自对应的该物体的相应部位后,那么分类器才会将该RoI判断为该类别。也就是说物体的各个部位和RoI的这些子区域是“一一映射”的对应关系

OK,现在我们知道了一个RoI必须是K* K个子区域都含有该物体的相应部位,我们才能判断该RoI属于该物体,如果该物体的很多部位都没有出现在相应的子区域中,那么就该RoI判断为背景类别。那么现在的问题就是网络如何判断一个RoI的 K*K个子区域都含有相应部位呢?前面我们是假设知道每个子区域是否含有物体的相应部位,那么我们就能判断该RoI是否属于该物体还是属于背景。那么现在我们的任务就是判断RoI子区域是否含有物体的相应部位

这其实就是position-sensitive score map设计的核心思想了。R-FCN会在共享卷积层的最后一层网络上接上一个卷积层,而该卷积层就是位置敏感得分图position-sensitive score map,该score map的含义如下所述:首先它就是一层卷积层,它的height和width和共享卷积层的一样(即具有同样的感受野),但是它的通道个数为K* K* (C+1) 。其中C表示物体类别种数,再加上1个背景类别,所以共有(C+1)类,而每个类别都有 K* K个score maps。现在我们只针对其中的一个类别来进行说明,假设我们的目标属于人这个类别,那么其有 K* K 个score maps,每一个score map表示原始图像中的哪些位置含有人的某个部位,该score map会在含有对应的人体的某个部位的位置有高的响应值,也就是说每一个score map都是用来描述人体的其中一个部位出现在该score map的何处,而在出现的地方就有高响应值”。既然是这样,那么我们只要将RoI的各个子区域对应到属于人的每一个score map上然后获取它的响应值就好了。但是要注意的是,由于一个score map都是只属于一个类别的一个部位的,所以RoI的第 i个子区域一定要到第i张score map上去寻找对应区域的响应值,因为RoI的第i个子区域需要的部位和第i张score map关注的部位是对应的。那么现在该RoI的K* K个子区域都已经分别在属于人的K*K个score maps上找到其响应值了,那么如果这些响应值都很高,那么就证明该RoI是人呀。

3、Position-Sensitive Rol Pooling解析

上面我们只是简单的讲解了一下ROl的K*K个子区域在各个类别的score maps上找到其每个子区域的响应值,我们并没有详细的解释这个“找到”是如何找的?这就是位置敏感Rol池化操作(Position-sensitive RoI pooling),其字面意思是池化操作是位置敏感的,下来我们对它进行解释说明。

通过RPN提取出来的RoI区域,其是包含了x,y,w,h的4个值,也就是说不同的RoI区域能够对应到score map的不同位置上,而一个RoI会被划分成K* K个bins(也就是子区域。每个子区域bin的长宽分别是 h/k 和 w/k ),每个bin都对应到score map上的某一个区域。既然该RoI的每个bin都对应到score map上的某一个子区域,那么池化操作就是在该bin对应的score map上的子区域执行,且执行的是平均池化。我们在前面已经讲了,第i个bin应该在第i个score map上寻找响应值,那么也就是在第i个score map上的第i个bin对应的位置上进行平均池化操作。由于我们有(C+1)个类别,所以每个类别都要进行相同方式的池化操作。
目标检测之R-FCN
上图表示了池化的方式,对于每个类别,它都有K* K个score maps,那么按照上述的池化方式,ROI可以针对该类别可以获得K* K个值,那么一共有(C+1)个类别,那么一个RoI就可以得到K* K* (C+1)个值,就是上图的特征图。那么对于每个类别,该类别的K* K个值都表示该RoI属于该类别的响应值,那么将这K*K个数相加就得到该类别的score,那么一共有(C+1)个scores,那么在这(C+1)个数上面使用简单的softmax函数就可以得到各个类别的概率了(注意,这里不需要使softmax分类器了,只需要使用简答的softmax函数,因为这里就是通过简单的比大小来判断最终的类别的)。

4、Position-Sensitive Regression解析

前面的position-sensitive score mapPosition-sensitive RoI pooling得到的值是用来分类的,那么自然需要相应的操作得到对应的值来进行回归操作。按照position-sensitive score map和Position-sensitive RoI pooling思路,其会让每一个RoI得到(C+1)个数作为每个类别的score,那么现在每个RoI还需要 4个数作为回归偏移量,也就是x,y,w,h的偏移量,所以仿照分类设计的思想,我们还需要一个类似于position-sensitive score map的用于回归的score map。那么应该如何设置这个score map呢,论文中给出了说明:即在ResNet的共享卷积层的最后一层上面连接一个与position-sensitive score map并行的score maps,该score maps用来进行regression操作,我们将其命名为regression score map,而该regression score map的维度应当是 4* K* K ,然后经过Position-sensitive RoI pooling操作后,每一个RoI就能得到4个值作为该RoI的x,y,w,h的偏移量了,其思路和分类完全相同。

5、为什么position-sensitive score map能够在含有某个类别的物体的某个部位的区域上具有高响应值?

首先根据网络的loss计算公式,如果一个RoI含有人这个物体,那么该RoI通过position-sensitive score map和Position-sensitive RoI pooling得到的(C+1)个值中属于人的那个值必然会在softmax损失函数的驱动下变得尽量的大,那么如何才能使得属于人的这个值尽量的大呢?那么我们需要想想属于人的这个预测值是怎么来的?经过前面的分析,我们已经知道它是通过Position-sensitive RoI pooling这种池化操作获得的,那么也就是说使得(C+1)个值中属于人的那个值尽量大,必然会使得position-sensitive score map中属于人的那个score map上的RoI对应的位置区域的平均值尽量大,从而会使得该score map上在该区域上的响应值尽量大,因为只有该区域的响应值大了,才能使得预测为人的概率大,才会降低softmax的loss,整个训练过程才能进行下去。
目标检测之R-FCN
如上图中Figure 3所示,我们输入了一张含有一个小孩的图片,图中黄色的BB表示我们的检测到的目标,也就是我们的一个ROI,中间是9张位置敏感的得分映射图(在这里使用的是3x3的特征映射),这9张图分别表示对人这个目标的top-left、top-center、… bottom-right不同区域敏感的得分映射。对应到图中就是将这个ROI分为9个子区域,每一个子区域其实大致上对应到了小孩的不同部位,而不同的部位一般都会有其独特的特征存在,9个区域敏感得分映射图对不同的区域比较敏感(所谓的敏感就是说如果这个子区域中存在该目标的某个部位特征时,其才会输出较大的响应值,否则的话我会输出较小的响应值)。上图中Figure 3中的9个得分映射对ROI中划分的对应子区域都比较敏感(都有很强的响应值,越白表示响应越大,越黑表示响应越小),即ROI中的9个子区域都有较大的响应值。然后进行位置敏感池化操作,最后进行Vote操作,由于9个区域中基本上都有很高的响应值,最后投票通过,认为这个ROI中的对象是一个person。同理,可以得出上图中Figure 4是一个背景类。(上图中Figure 4的位置敏感ROI池化中有5个区域是黑色的,即表示具有较低的响应值,只有4个区域比较高,即表示具有较高的响应值,根据Vote机制,就将其分类为背景类)。

6、Loss计算及其分析
目标检测之R-FCN
这个Loss就是两阶段目标检测框架常用的形式。包括一个分类Loss一个回归Loss。λ用来平衡两者的重要性。对于任意一个RoI,我们需要计算它的softmax损失,和当其不属于背景时的回归损失。这很简单,因为每个RoI都被指定属于某一个GT box或者属于背景,即先选择和GT box具有最大重叠率(IOU)的Rol,然后在剩余的Rol中选择与GT box的重叠率值大于0.5Rol进行匹配操作,最后将剩余的Rol都归为背景类。即每个Rol都有了对应的标签,我们就可以根据监督学习常用的方法来训练它啦。