目录
参考资料
论文:
博客:
第1章 Fast RCNN概述
Fast R-CNN 主要是在R-CNN和SPPNet的基础上进行改进的,有着以下几个优点:
- 与R-CNN、SPPNet相比,有着更高的准确率。
- 通过使用多任务损失,将模型训练由多阶段转变为单阶段训练(一次搞定分类+回归)。
- 训练时可以一次更新网络的所有层,不再需要分步更新参数。
- 采用Roi Pooling,优化minibatch采样策略,不再需要硬盘来存储CNN提取的特征数据。
第2章 Fast RCNN网络细节
Fast R-CNN的流程主要分为三步:
- 使用 Selective Search 方法生成2K个图片候选区域。
- 对整张图片进行特征提取得到相应的特征图(这是对R-CNN的一大改进,参考了SPPNet);
- 将2k个生成的候选区域映射到特征图中。
- 使用ROI Pooling将所有的候选区域特征统一缩放到 7 × 7 7\times7 7×7 大小,然后将这2K个特征向量展平,并连接到全连接层上,得到两个输出结果,一个是K+1类(类别数+背景类)的概率,还有一个是每个类的预测边框。
1.1 特征映射
这一映射主要是基于图像经过多层卷积与池化之后,图像的相对位置不变这一特性来实现的。
因为Fast R-CNN的Backbone是VGG,而在VGG中,卷积操作是不改变图像尺寸的,主要是池化操作会改变尺寸大小。
如上图所示,映射操作是在conv5之后,ROI Pooling之前进行的,在这之间进行了4次最大池化操作,每一次都将特征图的尺寸缩小1/2,所以最后特征图就变为了原始图像的 1 2 4 = 1 16 \frac{1}{2^4} = \frac{1}{16} 241=161 ,那么相应的每一个候选区域的坐标也应该按比例缩放,也就是说映射到特征图上的坐标是原始坐标的 1 16 \frac{1}{16} 161 。
例如:假设某个候选区域的坐标为 ( x m i n , y m i n , x m a x , y m a x ) (x_{min},y_{min},x_{max},y_{max}) (xmin,ymin,xmax,ymax) ,则映射到特征图上就是 ( x m i n ′ , y m i n ′ , x m a x ′ , y m a x ′ ) (x_{min}',y_{min}',x_{max}',y_{max}') (xmin′,ymin′,xmax′,ymax′)。
最后,需要注意的是,R-CNN中生成的候选区域会经过NMS进行一波筛选,但Fast RCNN中却没有这一步,或者说在训练阶段没有,但在测试阶段有。
我是在看了它的源码才发现的,至于为什么要这么做,论文中也没有提及,代码中也没有相关的注释说明,所以我也不清楚(当然,我也不是十分确定,因为Fast RCNN的源码不好读,代码分布的比较散,甚至还fork了caffe的源码,把自己的代码放在了框架里面,反正这操作挺骚的)。
1.2 RoI Pooling
(1)概念
在R-CNN中为了统一输入使用了比较暴力的方法(resize),但在Fast R-CNN中,使用了RoI Pooling,这一方法参考了SPPNet的空间金字塔池化,可以将RoI Pooling看做空间金字塔池化的一个简化版。
ROI是框在conv特征图上的一个方型,用四元组定义(左上顶点r、c,高h和宽w),显然,RoI的大小是各不相同的,(无预处理的情况下)CNN无法处理大小不同的特征。这也是为什么R-CNN想不到共享特征的原因。那么,我们需要一个将特征图的特定区域改变维度(通常是降维)的工具,这个工具就是我们经常使用的池化(pooling)。
然而,Fast R-CNN中提出的兴趣域池化层 Roi Pooling 与我们熟知的各类池化层不同。
- 传统池化层通过设置池化窗口宽度 width 、填充 padding 和步幅 stride 来间接控制输出形状。
- 而 Roi Pooling 层则通过参数设置直接控制输出形状。
例如,指定每个区域输出的高和宽为 h 2 h_2 h2 和 w 2 w_2 w2,假设某一兴趣区域窗口的高和宽分别为 h h h 和 w w w,该窗口将被划分为形状为 h 2 × w 2 h_2 \times w_2 h2×w2 的子窗口网格,且每个子窗口的大小约为 ( h h 2 × w w 2 ) (\frac{h}{h_2}\times \frac{w}{w_2}) (h2h×w2w)。
任一子窗口的高和宽要取整,其中的最大元素作为该子窗口的输出。因此,兴趣区域池化层可从形状各异的兴趣区域中均抽取出形状相同的特征。
(2)举例
下图在4×4的输入上,选取了左上角的3×3区域作为Roi。对Roi做2×2的Roi Pooling 得到2×2的输出。
4个划分后的子窗口分别含有元素**(Roi pooling的每个网格大小不一定相等!)**:
- 0、1、4、5(5最大)
- 2、6(6最大)
- 8、9(9最大)
- 10
1.3 多任务损失函数
损失函数由两部分组成,一个是分类损失,一个是边界框回归损失。
每个RoI都有自己的输出:
- softmax得出的,K+1维(K是数据集目标类,还有一个背景类)的概率 p = ( p 0 , … , p K ) p=(p_0,…,p_K) p=(p0,…,pK)
- K个物体类的坐标,(大写K是目标类数,小写k是目标类的索引) t k = ( t x k , t y k , t w k , t h k ) t_k=(t_x^k,t_y^k,t_w^k,t_h^k) tk=(txk,tyk,twk,thk)
严谨来讲这不是坐标,而是第k类尺度不变的平移和log空间的高/宽位移。
X ′ = w × t x k + X Y ′ = h × t y k + Y w ′ = w × e t w k h ′ = h × e t h k X' = w\times t_x^k+X\\ Y' = h\times t_y^k+Y\\ w'=w\times e^{t_w^k}\\ h'=h\times e^{t_h^k} X′=w×txk+XY′=h×tyk+Yw′=w×etwkh′=h×ethk
与输出对应的ground truth:
- 概率 p p p 对应的标签类别 u u u
- 坐标 t u t^u tu 对应回归目标 v v v
t u t^u tu 意味着只考虑真实分类对应的边界框与Ground Truth的误差
由此我们可以得出多任务的损失函数:
- 一个是分类的负对数损失 L c l s ( p , u ) L_{cls}(p,u) Lcls(p,u) ,顺带一说,负对数损失就是softmax分类器的标配;
- L l o c ( t u , v ) L_{loc}(t_u,v) Lloc(tu,v) 就是定位损失啦,它的损失函数采用的是smooth L1损失,具体地说,对四个坐标分别进行smooth L1,然后加起来,就像下面这样:
第3章 Fast RCNN总结
在原文中,作者说Fast RCNN是R-CNN和SPPNet的一个快速更新,所以改进的内容并不是特别多,与后面的Faster RCNN提出了RPN相比,这只能算是一次打补丁的行为。
Fast RCNN不足:
候选区域的选取还是通过selective search,并且只能在CPU中运行这个算法,所以这个阶段浪费了大量时间。(这也是Faster RCNN改进的点)