文献阅读:Fast R-CNN(2015)
作者:Ross Girshick
阅读原因:了解RCNN、Fast RCNN、Faster RCNN在object detection中的应用
RCNN学习笔记
主要参考:①关于Faster R-CNN的一切——笔记2:Fast R-CNN ②【目标检测】Fast RCNN算法详解
文章目录
摘要
- 继2014年的RCNN之后,Ross Girshick在15年推出Fast RCNN,构思精巧,流程更为紧凑,大幅提升了目标检测的速度。在Github上提供了源码
- 本文提出用Fast RCNN进行object detection。Fast Region-based CNN(Fast R-CNN)建立在之前的工作上,目的是利用深度卷积网络高效地对object proposals进行分类。
回顾
与图像分类不同的是,object detection需要对objects精确局部化,使得问题更复杂:
1、需要处理很多proposals;
2、需要修正这些proposals(粗略的局部化),从而得到精确的局部化。
RCNN的不足
-
多阶段训练:对CNN做fine-tuning → \to → 训练SVM取代fine-tuning中CNN最后一层的softmax 分类器 → \to → 用bounding-box回归对窗口进行微调(SVM输出评分后)
-
训练过程在时间和空间上都expensive:对于SVM和bounding-box回归,需要从每一个图像的每一个proposals中提取特征并记录,需要大量计算时间和存储空间。
-
慢!!
RCNN速度慢的原因:需要对每一个region proposals使用CNN提取特征,没有共享计算。因此提出SPPnets。
SPPnets(Spatial Pyramid Pooling)通过共享计算来加速RCNN,它是对整个输入图像计算一个convolutional feature map【一幅图像仅用CNN计算一次】,然后从这个共享的feature map中提取每个object proposal对应的特征向量,进而对object proposal进行分类。
从feature map中提取某一个object proposal对应特征向量的方法:把feature map中这个proposal内的feature map的部分max-pooling成一个固定大小的输出。选择不同的输出大小进行pooling,然后将这些输出连结起来。可参考Spatial Pyramid Pooling(略)和SPP(Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition)(详)
但SPPnet的训练过程也是多阶段的【包括提取特征、fine-tuning、训练SVM,以及最后bounding-box回归】,而且这里的fine-tuning与RCNN不同,无法更新SP pooling之前的卷积层,导致它的精度受到限制。
所以下面要研究Fast RCNN。先说说它的优点:
- 比RCNN、SPPnet有更高的检测质量(mAP)
- single-stage训练,使用multi-task loss
- 训练可以更新所有网络layers
- 不需要feature caching存储空间
Fast RCNN结构
↓ \downarrow ↓
↓ \downarrow ↓
↓ \downarrow ↓
要点1. RoI pooling层
\qquad
RoI层是用一个固定尺寸(H
×
\times
×W,例如 3
×
\times
× 3,H和W独立于RoI)的spatial content进行max-pooling,将不同尺寸的RoI的特征转换为一个固定尺寸的小的feature map。本文中,RoI是conv feature map上的一个长方形窗口,用四元组
(
r
,
c
,
h
,
w
)
(r,c,h,w)
(r,c,h,w)定义:
(
r
,
c
)
(r,c)
(r,c)是左上角坐标,
(
h
,
w
)
(h,w)
(h,w)是长和宽。
\qquad
RoI层是SPPnet中spatial pyramid pooling层的一个特例【只有一个pyramid level】,它要做两件事:一是原image中的region proposal怎么在conv feature map上找到它的对应位置?二是要把这个region proposal对应的conv feature map中的特征用max-pooling转换成一个固定大小H×W的feature map。
\qquad 第一个问题:首先要明确,conv feature map的大小和原image是不一样的(比如VGG16,conv feature map是14×14×512,原图227×227×3),所以需要一个RoI projection:将region proposal映射为conv feature map上对应的RoI。
\qquad
原图生成conv feature map的过程是一系列卷积、下采样的操作,若只考虑卷积过程,因为四元组的前两个分量是左上角的坐标,所以只与卷积的步长有关。而四元组的后两个分量表示RoI的尺寸大小,所以与步长、卷积核大小都有关。
\qquad
假设(x,y)是原图坐标,(xx,yy)是conv feature map坐标,S是CNN卷积操作中所有strides的乘积,给出映射公式如下:
(
x
,
y
)
=
(
1
+
S
∗
(
x
x
−
1
)
,
1
+
S
∗
(
y
y
−
1
)
)
(x,y) = (1+S* (xx-1),1+S* (yy-1))
(x,y)=(1+S∗(xx−1),1+S∗(yy−1))
由原图反解conv feature map坐标:xx = (x-1)/S+1,yy = (y-1)/S+1
而宽度w和高度h,有如下迭代公式
h
i
=
(
h
i
+
1
−
1
)
∗
s
t
r
i
d
e
i
+
c
i
h_i=(h_{i+1}-1)*stride_i+c_i
hi=(hi+1−1)∗stridei+ci
其中,stridei表示第i层到第i+1层进行的卷积操作的步长,ci表示该卷积核的大小【
c
i
×
c
i
c_i\times c_i
ci×ci】
\qquad 第二个问题:假设输入的feature RoI大小是h × \times ×w,希望生成固定大小的H × \times ×W的feature map。那么将feature RoI分成大小为(h/H) × \times ×(w/W)的一共H × \times ×W个子窗口,每个子窗口进行传统的max-pooling操作得到一个值【每个feature map通道单独操作,所以输出通道数不变,和传统max-pooling一样】,所以就有H × \times ×W个输出。
RoI max-pooling层的工作原理:
将
h
×
w
h\times w
h×w RoI window拆分为
H
×
W
H\times W
H×W个网格子窗口,每一个sub-window的尺寸大约为
h
/
H
×
w
/
W
h/H\times w/W
h/H×w/W,再对每个sub-window进行max-pooling得到相应的输出grid cell
要点2. multi-task loss
利用multi-task loss,实现单阶段联合训练softmax分类器和bbox回归器,得到两个并列的输出层。而RCNN需要三个阶段分别训练softmax分类器、SVM、bbox回归器。
一个Fast RCNN网络有两个并列的输出层。第一个完成分类任务,输出每个RoI的K+1类离散概率分布: p = ( p 0 , . . . , p K ) p=(p_0,...,p_K) p=(p0,...,pK),p由FC层的K+1个输出softmax计算得到。第二个完成回归任务,输出K个物体类的refined了的bounding-box坐标: 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)。
每一个训练RoI有两个标签:ground-truth类别标签
u
u
u和ground-truth bounding-box 回归目标
v
v
v【是一个四元组,即RCNN论文中的G】。用multi-task loss
L
L
L联合训练分类器和bounding-box回归器:
[ u ≥ 1 ] [u\geq 1] [u≥1]为示性函数 I [ u ≥ 1 ] \mathbb{I}_{[u\geq 1]} I[u≥1]:当 u ≥ 1 u\geq 1 u≥1时结果为1,否则结果为0。我们将背景类标记为u=0,因为背景RoI没有ground-truth bounding box的概念,所以它对应的 L l o c L_{loc} Lloc忽略。
其中,分类任务的损失函数为 L c l s ( p , u ) = − log p u L_{cls}(p,u)=-\log p_u Lcls(p,u)=−logpu是true class u的log loss【若 p u = 1 , p k = 0 , ∀ k ≠ u , p_u=1,p_k=0,\forall k\ne u, pu=1,pk=0,∀k̸=u,则 L c l s ( p , u ) = 0 L_{cls}(p,u)=0 Lcls(p,u)=0,即没有损失】。回归任务的损失函数 L l o c L_{loc} Lloc是定义在类别u的正确bounding-box回归目标: v = ( v x , v y , v w , v h ) v=(v_x,v_y,v_w,v_h) v=(vx,vy,vw,vh),和类别u的预测bounding-box: t u = ( t x u , t y u , t w u , t h u ) t^u=(t^u_x,t^u_y,t^u_w,t^u_h) tu=(txu,tyu,twu,thu)【即RCNN论文中的 G ^ \hat{G} G^】的损失函数。实际操作中, v v v表示从proposal P到ground-truth box G(属于类别u)的真实的平移放缩变换, t u t^u tu表示预测的变换
回归的损失函数
L
l
o
c
L_{loc}
Lloc为:
这里,smooth
L
1
(
x
)
_{L_1}(x)
L1(x)是robust L1损失,相较于L2损失【RCNN和SPPnet中】对outliers不那么敏感。训练时,将
v
i
v_i
vi标准化(零均值、单位方差),并且
λ
=
1
\lambda=1
λ=1。
如何训练?
1. 预训练网络初始化
用三个pre-trained ImageNet初始化Fast RCNN,每个net都有5个pooling层和5到13个conv层,需要做的结构变化如下:
(1)最后一个max pooling层替换为RoI pooling层,设定H和W使得RoI pooling层的输出满足第一个FC层要求的输入大小;
(2)网络的最后一个FC层和softmax【预训练中为1000-way ImageNet图像分类器】替换为两个并列的输出层(FC+softmax层和FC+bbox regressor)
(3)网络修改为可以接收两个输入:一系列图像和一系列这些图像中对应的RoIs
2. fine-tuning for detection
①分层抽样
用back-propagation训练所有权重参数是Fast RCNN的一个重要能力
- 为什么SPPnet不能更新weights?
当每一个训练样本来自于不同的图像时,back-propagation through SPP层是非常低效的,而这正是RCNN和SPPnets的训练过程。这种低效性来源于每一个RoI都有很大的感受野【经常需要spanning整幅图像】(??)。由于向前算法必须处理整个感受野,因此输入的训练样本都很大(经常是整幅图像)。
感受野(receptive field):【神经学】感受器受刺激兴奋时,通过感受器官中的向心神经元将神经冲动(各种感觉信息)传到上位中枢,一个神经元所反应(支配)的刺激区域就叫做神经元的感受野。【CNN】卷积神经网络每一层输出的特征图(feature map)上的像素点在原始图像上映射的区域大小
在Fast RCNN训练中,随机梯度下降的mini-batch是分层采样的:首先随机采样N个images,然后每个image抽取R/N个RoI样本【R为mini-batch的大小】,因此从同一张image采样的RoIs就可以在前向和后向传播中共享计算了【因为Fast RCNN是将整幅图像输入CNN,而RCNN和SPPnet,是将每个proposal都输入CNN进行计算】。N取的小一些可以减少mini-batch的计算。例如N=2,R=128,则先采样两个图像,再从每个图像中抽取128/2=64个RoI样本【RCNN和SPPnet中,每一个region proposal都是从所有不同图像中抽样的】。
这64个RoIs中25%是从与某个ground-truth的IoU大于等于0.5的proposals中抽取的(label是1~K),其余的是从IoU在[0.1,0.5)之间的proposals中抽取的(label是0)。而IoU小于0.1的视作hard example mining。不需要做data augmentation。
②RoI pooling 层的反向传播
③SGD超参数
最后两个并列的FC层(softmax+bbox回归)的初始化:用零均值,标准差分别为0.01和0.001的Gaussian分布进行初始化。
如何检测?(forward)
(1)对于一个image,先运行selective search生成约2000个region proposals,然后将这幅image和region proposals输入Fast RCNN网络。
(2)对于每个RoI
r
r
r,网络的向前传播会输出一个类别后验概率分布
p
p
p和一系列与
r
r
r相对应的预测bounding-box偏移量坐标【每一类都有一个与该类相对应的refined了的预测bounding-box】。
(3)然后根据估计概率
Pr
(
c
l
a
s
s
=
k
∣
r
)
≜
p
k
\Pr(class=k|r)\triangleq p_k
Pr(class=k∣r)≜pk对每一类的bounding-box进行非极大值抑制(NMS)
FC层提速——TSVD
对于目标检测任务,需要处理的RoIs数量庞大,近乎一半的向前传播过程的时间用在了计算FC层上。可通过截断奇异值分解(TSVD)对FC层进行提速。
一层的u
×
\times
×v权重矩阵
W
W
W可因式分解为:
W
≈
U
Σ
t
V
T
W\approx U\Sigma_tV^T
W≈UΣtVT即对W进行SVD分解,再取前 t 个特征值进行截断。其中,u
×
\times
×t 矩阵
U
U
U由W的前 t 个左奇异向量构成,v
×
\times
×t 矩阵
V
V
V由W的前 t 个右奇异向量构成。TSVD法将参数的个数从uv降到t(u+v)。
为了压缩网络,将一个以W为参数的FC层替换为两个没有线性关系的FC层:第一个的权重矩阵为
Σ
t
V
T
\Sigma_tV^T
ΣtVT(没有bias),第二个的权重矩阵为
U
U
U(有W的bias)。
主要成果
- 在VOC07,2010,2012有最佳的mAP
- 相比RCNN和SPPnet有更快的training和testing
- 在VGG16中fine-tuning conv层可以提高mAP
Design Evaluation
multi-task 训练是否有帮助?
多任务训练可以避免进行一系列的任务训练,同时任务之间通过共享表示相互影响,从而提升结果。
其中,S表示AlexNet,M表示VGG_CNN_M_10241,L表示VGG 16。
- 首先设 λ = 0 \lambda=0 λ=0即仅使用分类loss函数 L c l s L_{cls} Lcls训练baseline网络【空白对照组】,结果见S、M、L的第一列;
- 再设 λ = 1 \lambda=1 λ=1即使用multi-task loss进行训练(不加入bounding box回归),结果见第二列;
- 然后在baseline网络上添加bounding-box回归层,并在其他参数固定的同时用 L l o c L_{loc} Lloc对这一层进行训练,结果见第三列;
- 最后是Fast RCNN的训练结果,见第四列。
不难发现,multi-task训练相较于只进行分类训练,对分类的精确度反而所有提升。
是否需要更多训练数据?
进行多次实验后,随着训练数据增多(以及mini-batch迭代步数的增加),训练效果有所提升。
SVM是否优于softmax?
Fast RCNN在fine-tuning中使用的是softmax分类器,而不是RCNN和SPPnet中的线性SVM。
不难看出,同样使用Fast RCNN,使用softmax的效果要优于SVM,这说明单阶段的fine-tuning比之前多阶段的训练更有效。同时,相比于SVM,softmax在给一个RoI评分时,引入了类别之间的competition。
Return of the devil in the details: Delving deep into convolutional nets(K. Chatfield, K. Simonyan, A. Vedaldi, and A.Zisserman) ↩︎