天天看点

R-FCN学习总结

文章目录

    • 简介
    • 网络结构
      • Position-Sensitive Score Map解析
        • 留坑(懂的老哥希望能不吝赐教)
      • Position-Sensitive Rol Pooling解析
      • Position-Sensitive Regression解析
    • 网络的训练
    • 损失函数
    • 其他
    • References

简介

R-FCN——Object Detection via Region-based Fully Convolutional Networks,这篇文章提出了一种高效简洁的目标检测模型 R-FCN(Region-based Fully Convolutional Networks ),作者将全卷积网络FCN(Fully Convolutional Network)应用于 Faster R-CNN,实现了整个网络的计算共享,极大的提高了检测速度,同时精度也可以与 Faster R-CNN相媲美。文章提出一种 position-sensitive score maps 用来平衡平移不变性(translation-invariance )和平移可变性(translation-variance )之间的矛盾,模型使用了 全卷积的 ResNet 结构,保证高检测精度的同时,将检测速度提高了 2.5~20倍。

注:本文内容大多摘自知乎文章并按照自己理解修改、添加部分内容,灰常感谢各位大佬无私分享!

这篇论文不是太容易读懂,首先我们要明白两个概念:(预警,文章略长,请耐心阅读)

  • 分类网络的位置不敏感性:简单来讲,对于分类任务而言,我希望我的网络有一个很好地分类性能,随着某个目标在图片中不断的移动,我的网络仍然可以准确的将图片区分为对应的类别。实验表明,深的全卷积网络能够具备这个特性,如ResNet-101等。
  • 检测网络的位置敏感性:简单来讲,对于检测任务而言,我希望我的网络有一个好的检测性能,可以准确的输出目标所在的位置值。随着某个目标的移动,我们希望网络的检测结果能够和它一起移动,仍然能够准确的检测到它,即我对目标位置的移动很敏感。我们需要计算对应的偏差值,需要计算预测边框和GT的重合率等。但是,深的全卷积网路不具备这样的一个特征。

总之,分类网络的位置不敏感性和检测网络的位置敏感性是一个矛盾问题,而我们的目标检测中不仅要分类也要定位,那么如何解决这个问题呢,R-FCN提出了Position-sensitive score maps来解决这个问题;

下面我们来说一下R-FCN的设计动机:(摘自知乎)

Faster R-CNN是首个利用CNN来完成proposals预测的,从此之后很多的目标检测网络都开始使用Faster R-CNN的思想。而Faster R-CNN系列的网络都可以分成2个部分:ROI Pooling之前的共享全卷积网络和ROI Pooling之后的ROI-wise子网络(用来对每个ROI进行特征提出,并进行回归和分类)。第1部分就是直接用普通分类网络的卷积层,用来提取共享特征,然后利用ROI Pooling在最后一层网络形成的feature map上面提取针对各个RoIs的特征向量,然后将所有RoIs的特征向量都交给第2部分来处理(即所谓的分类和回归),而第二部分一般都是一些全连接层,在最后有2个并行的loss函数:softmax和smoothL1,分别用来对每一个RoI进行分类和回归,这样就可以得到每个RoI的真实类别和较为精确的坐标信息啦(x, y, w, h)。

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

网络结构

R-FCN的网络结构图如下:

R-FCN学习总结

首先,我们来分析一下R-FCN算法的整个运行步骤,使得我们对整个算法有一个宏观的理解,接下来再对不同的细节进行详细的分析:

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

这样,我们就可以在测试图片中获得我们想要的类别信息和位置信息啦。(检测任务)

Position-Sensitive Score Map解析

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

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

这其实就是position-sensitive score map设计的核心思想了。R-FCN会在共享卷积层的最后一层网络上接上一个卷积层,而该卷积层就是位置敏感得分图position-sensitive score map。该score map的含义如下所述: 首先它就是一层卷积层,它的 h e i g h t height height和 w i d t h width width和共享卷积层的一样(即具有同样的感受野),但是它的通道数为 k ∗ k ∗ ( C + 1 ) k*k*(C+1) k∗k∗(C+1)。其中 C C C表示物体类别种数,再加上1个背景类别,所以共有 ( C + 1 ) (C+1) (C+1)类,而每个类别都有 k ∗ k k*k k∗k个score maps。现在我们只针对其中的一个类别来进行说明,假设我们的目标属于人这个类别,那么其有 k ∗ k k*k k∗k 个score maps,每一个score map表示原始图像中的哪些位置含有人的某个部位,该score map会在含有对应的人体的某个部位的位置有高的响应值,也就是说每一个score map都是用来描述人体的其中一个部位出现在该score map的何处,而在出现的地方就有高响应值”。既然是这样,那么我们只要将RoI的各个子区域对应到属于人的每一个score map(论文中默认 k ∗ k = 9 k*k = 9 k∗k=9个)上然后获取它的响应值就好了。但是要注意的是,由于一个score map都是只属于一个类别的一个部位的(注意是一个部位,论文默认把物体分为9个部位),所以RoI的第 i个子区域一定要到第i张score map的对应区域去寻找响应值,因为RoI的第i个子区域需要的部位和第i张score map关注的部位是对应的。那么现在该RoI的 k ∗ k k*k k∗k个子区域都已经分别在属于人的 k ∗ k k*k k∗k个score maps上找到其响应值了,那么如果这些响应值都很高,那么就证明该RoI是人呀。当然这有点不严谨,因为我们只是在属于人的 k ∗ k k*k k∗k个score maps上找响应值,我们还没有到属于其它类别的score maps上找响应值呢,万一该RoI的各个子区域在属于其它类别的score maps上的响应值也很高,那么该RoI就也有可能属于其它类别呢?这就会涉及到一个比较的问题,哪个类别的响应值高,我就将它判断为哪一类目标。它们的响应值同样高(这里应该指相等)这个情况发生的几率很小,我们不做讨论。

以上就是position-sensitive score map的全部思想了。(大佬就是大佬呀,再次推荐文章,膜……)

留坑(懂的老哥希望能不吝赐教)

BTW这里我一直对这句话有一个疑问:“所以RoI的第 i个子区域一定要到第i张score map上去寻找对应区域的响应值,因为RoI的第i个子区域需要的部位和第i张score map关注的部位是对应的”。比如我们还是检测一个人,将其分为9个部分,对于一个站立的人来说,他的头部在ROI的第2个部分,那么就应该去第2张score map的对应区域找响应值;而如果是一个倒立的人,他的头部会在ROI的第8个部分,那么就应该去第8张score map的对应区域找响应值;这里就会出问题了:通常来讲第2张score map关注的人的头部,第8张score map关注的是人的脚部,去第8张score map找人的头部的响应值应该会出问题吧???可能我理解的有错,如果没错的话,这应该是R-FCN的一个缺陷吧?(留坑,没怎么想明白,懂的老哥希望能不吝赐教)

Position-Sensitive Rol Pooling解析

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

R-FCN学习总结

如上图所示,通过RPN提取出来的RoI区域,其是包含了 x , y , w , h x,y,w,h x,y,w,h的4个值,也就是说不同的RoI区域能够对应到score map的不同位置上,而一个RoI会被划分成 k ∗ k k*k k∗k个bins(也就是子区域。每个子区域bin的高宽分别是 h k \frac{h}{k} kh​ 和 w k \frac{w}{k} kw​ ),每个bin都对应到相应score map上的某一个子区域。既然该RoI的每个bin都对应到相应score map上的某一个子区域,那么池化操作就是在该bin对应的score map上的子区域执行,且执行的是平均池化。我们在前面已经讲了,第i个bin应该在第i个score map的对应区域上寻找响应值,那么也就是在第i个score map上的“该第i个bin对应的位置”上进行平均池化操作。并且由于我们有 ( C + 1 ) (C+1) (C+1)个类别,所以每个类别都要进行相同方式的池化操作,所以我们会得到一个 ( C + 1 ) (C+1) (C+1)个channel的特征图,如下图所示:

R-FCN学习总结

平均池化操作的计算方式如下:(符号的具体含义还是自己看论文吧,太费劲了嘤嘤嘤。。。。。。不过看不懂略过也行,不要紧)

r c ( i , j ∣ Θ ) = ∑ ( x , y ) ∈ bin ⁡ ( i , j ) z i , j , c ( x + x 0 , y + y 0 ∣ Θ ) / n r_{c}(i, j | \Theta)=\sum_{(x, y) \in \operatorname{bin}(i, j)} z_{i, j, c}\left(x+x_{0}, y+y_{0} | \Theta\right) / n rc​(i,j∣Θ)=(x,y)∈bin(i,j)∑​zi,j,c​(x+x0​,y+y0​∣Θ)/n

上图已经很明显地画出了池化的方式:对于每个类别,它都有 k ∗ k k*k k∗k个score maps。那么按照上述的池化方式,ROI针对某类别可以获得 k ∗ k k*k k∗k个值,因为一共有 ( C + 1 ) (C+1) (C+1)个类别,所以一个RoI就可以得到 k ∗ k ∗ ( C + 1 ) k*k*(C+1) k∗k∗(C+1)个值,这就是上图得到的特征图。那么对于每个类别,该类别的 k ∗ k k*k k∗k个值都表示该RoI属于该类别的响应值(表示该类别的 k ∗ k k*k k∗k个部分的响应值),那么将这 k ∗ k k*k k∗k个数相加就得到该类别的score。按上述方法一共可以得到 ( C + 1 ) (C+1) (C+1)个scores,那么在这 ( C + 1 ) (C+1) (C+1)个数上面使用简单的softmax函数就可以得到各个类别的概率了(注意,这里不需要使softmax分类器了,只需要使用简单的softmax函数即可,因为这里就是通过简单的比大小来判断最终的类别的,下面的两个公式就表示了这个过程)。

r c ( Θ ) = ∑ i , j r c ( i , j ∣ Θ ) r_{c}(\Theta)=\sum_{i, j} r_{c}(i, j | \Theta) rc​(Θ)=i,j∑​rc​(i,j∣Θ)

s c ( Θ ) = e r c ( Θ ) / ∑ c ′ = 0 C e r c ′ ( Θ ) s_{c}(\Theta)=e^{r_{c}(\Theta)} / \sum_{c^{\prime}=0}^{C} e^{r_{c^{\prime}}}(\Theta) sc​(Θ)=erc​(Θ)/c′=0∑C​erc′​(Θ)

Position-Sensitive Regression解析

前面的position-sensitive score map和Position-sensitive RoI pooling得到的值是用来分类的,那么自然需要相应的操作得到对应的值来进行回归操作。按照“position-sensitive score map”+“Position-sensitive RoI pooling”的思路,其会让每一个RoI得到 ( C + 1 ) (C+1) (C+1)个数作为每个类别的score,那么现在每个RoI还需要 4个数作为“回归偏移量”,也就是 x , y , w , h x,y,w,h 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的维度应当是 k ∗ k ∗ 4 k*k*4 k∗k∗4 ,然后经过Position-sensitive RoI pooling操作后,每一个RoI就能得到4个值作为该RoI的 x , y , w , h x,y,w,h x,y,w,h的偏移量了,其思路和分类完全相同,在此不再赘述。(要自己想清楚呀~)

网络的训练

这种有高响应值现在只是作者自己在yy的啊,如果网络不满足这一点的话,那么前的所有分析都gg了啊。好,现在我们就大致解释一下为什么训练该网络能够让网络最终满足这一点。首先根据网络的loss公式(loss决定模型的学习方向,损失函数后面会给),如果一个RoI含有人这个物体,那么该RoI通过“position-sensitive score map”+“position-sensitive RoI pooling”得到的 ( C + 1 ) (C+1) (C+1)个值中的属于人的那个值必然会在softmax损失函数的要求下“变得尽量的大”,那么如何才能使得属于人的这个值尽量的大呢?那么我们现在就要想想属于人的这个预测值是怎么来的? 在前面的分析,我们已经知道它是通过Position-sensitive RoI pooling这种池化操作的来的(这里我们要明确一点:池化和softmax是没有学习参数的,所以我们设计loss的时候只需要关注前面的部分),那么也就是说使得 ( C + 1 ) (C+1) (C+1)个值中属于人的那个值尽量大,必然会使得position-sensitive score map中属于人的那个score map上的“该RoI对应的位置区域的平均值”尽量大,从而也就是该score map上在该区域上的响应值尽量大。因为只有该区域的响应值大了,才能使得预测为人的概率大,才会降低softmax的loss。(还是那句话,loss决定模型的学习方向,你想让模型学什么,你就得设计什么样的loss)

PS:不得不说一句,作者思路是真牛13!

只要设计一个合适的loss,给模型学习的方向(即让某物体在对应score map上的对应区域的响应值尽量大),这种end-to-end的训练就会达到这一目的,下面拿论文中的图示举例:(相当形象呀,有木有~)

R-FCN学习总结

(这一部分有点啰嗦了,可忽略。)如上图所示,我们同样可以得出以上的结论。如Figure 3所示,我们输入了一张含有一个小孩的图片,图中黄色的BBox表示我们检测到的目标,也就是我们的一个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机制,就将其分类为背景类)。

损失函数

网路的损失函数如下:

L ( s , t x , y , w , h ) = L c l s ( s c ∗ ) + λ [ c ∗ > 0 ] L r e g ( t , t ∗ ) L\left(s, t_{x, y, w, h}\right)=L_{c l s}\left(s_{c^{*}}\right)+\lambda\left[c^{*}>0\right] L_{r e g}\left(t, t^{*}\right) L(s,tx,y,w,h​)=Lcls​(sc∗​)+λ[c∗>0]Lreg​(t,t∗)

这个Loss就是两阶段目标检测框架常用的形式。包括一个分类Loss和一个回归Loss。 λ \lambda λ用来平衡两者的重要性。对于任意一个RoI,我们需要计算它的softmax损失,和当其不属于背景时的回归损失。这很简单,因为每个RoI都被指定属于某一个GT box或者属于背景,即先选择和GT box具有最大重叠率(IOU)的Rol,然后在剩余的Rol中选择与GT box的重叠率值大于0.5的Rol进行匹配操作,最后将剩余的Rol都归为背景类。那么RoI有了label后,loss自然很容易计算出来。(有监督学习)

R-FCN的训练策略也是采用的Faster R-CNN中的4-step alternating training进行训练的。

其他

  • online hard example mining

    这个方法是目标检测框架中经常会用到的一个tricks,其主要的思路如下所示:首先对RPN获得的候选ROI(正负样本分别进行排序)进行排序操作;然后在含有正样本(目标)的ROI中选择前N个ROI,将正负样本的比例维持在1:3的范围内,基本上保证每次抽取的样本中都会含有一定的正样本,都可以通过训练来提高网络的分类能力。如果不进行此操作的话,很可能会出现抽取的所有样本都是负样本(背景)的情况,这样让网络学习这些负样本,会影响网络的性能。

  • Atrous algorithm(Dilated Convolutions或者膨胀卷积)

    这个不多解释了,不太懂的搜一下吧,其目的就是为了扩大感受野。

    R-FCN学习总结
  • 测试时的tricks

    在测试的时候,为了减少RoIs的数量,作者在RPN提取阶段就将RPN提取的大约2W个proposals进行过滤:

    • 去除超过图像边界的proposals
    • 使用基于类别概率且阈值IoU=0.7的NMS过滤
    • 按照类别概率选择top-N个proposals
    所以在测试的时候,一般只剩下300个RoIs,当然这个数量是一个超参数。并且在R-FCN的输出300个预测框之后,仍然要对其使用NMS去除冗余的预测框。

done~

References

  • https://arxiv.org/pdf/1605.06409v2.pdf
  • https://zhuanlan.zhihu.com/p/30867916
  • https://blog.csdn.net/WZZ18191171661/article/details/79481135
  • https://zhuanlan.zhihu.com/p/24780433
  • https://link.zhihu.com/?target=https%3A//arxiv.org/pdf/1412.7062.pdf

继续阅读