新提出的Fast R-CNN模型解决了之前模型存在的问题,并使得模型具有以下的优点:
目标检测的性能(mAP)要高于R-CNN和SPPnet整个训练过程是single-stage的,并且使用了multi-task 的损失函数训练的过程能够更新所有层(这点主要针对于SPPnet,因为SPPnet不能更新SPP layer 之前的层)不需要消耗额外的空间来存储feature对于conv layer和FC layer,大家应该都很熟悉,所有我给大家重点讲解一下这个RoI pooling layer,如下图所示,对于不同size的RoI(object proposal),我们都把它划分成 ( 7 ∗ 7 ) (7*7) (7∗7)的网格,然后对每个网格(bin)内的全部像素点求一个max pooling,即选取一个最大值作为输出,最后对不同size的RoI,我们都得到 7 ∗ 7 7*7 7∗7的feature map。这点其实是借鉴SPPnet的,它相当于是SPP layer的一个特例,就是只使用了一个尺度 ( 7 ∗ 7 ) (7*7) (7∗7)。
由此可见,经过RoI pooling layer之后,不同size的object proposal的feature map变成同样的size了。至于为什么需要RoI pooling layer,这和为什么在SPP-net要用SPP layer同样的道理。
本文使用了三个预训练的网络来初始化网络,分别是AlexNet(S),VGG_CNN_M_1024(M),VGG16(L)。此外,还对网络结构做了以下改变:
把网络中的最后一个max pooling层替换为RoI pooling layer把网络中的最后一个FC layer + softmax替换成两个并行的网络,一个是FC + softmax来进行分类,另一个是FC + bbox regressor来进行位置回归网络的输入也变成了两个:图片和每个图片对应的RoIs文中指出了SPPnet在fine-tune时不会更新SPP layer之前的层,因为SPP layer的反向传播是非常低效的。此外,R-CNN和SPPnet共同存在的一个问题就是,在训练时,假设一个mini-batch有128个RoI,那么这128个RoI全部是来自于不同的图片的,这样就导致不能共享feature,使得整个反向传播的效率非常低。
那么在Fast R-CNN中,作者提出了一个新的方法使得训练过程中能够共享feature。首先一个mini-batch是从N张图片中采样的,每张图片采取R/N个RoI,假设N=2,R=128,那么有64个RoI是来自同一张图片的,所以这些RoI可以在forward 和 backward passes时共享计算和内存(可以理解为共享feature),这样就会比来自不同图片的128个RoI快64倍。
此外呢,整个训练过程是one fine-tune stage的,这是因为Fast R-CNN网络直接包括softmax分类器和bounding-box regressor,所以不用额外训练SVM分类器和回归器。
Fast R-CNN有两个输出,一个是softmax输出的分类结果,另一个是regressor输出的位置offset,所以我们的loss包含两个部分,用这个共同的loss去同时训练这两部分。
分类器会为每个RoI输出一个possibility distribution p = ( p 0 , p 1 , … , p k ) p=(p_0,p_1,…,p_k) p=(p0,p1,…,pk) 同时每个RoI都有一个ground-truth class u u u ( u u u不是一个概率分布,而是一个数字,为0是代表是背景,为1-20是代表所属的类别),所以分类器的损失函数可以表示为: L c l s ( p , u ) = − l o g p u L_{cls}(p,u)=-logp_u Lcls(p,u)=−logpu
其中, p u p_u pu 代表这个RoI属于第 u u u 类的概率值。
回归器的作用是使得最后预测的bounding box和ground-truth的box更接近,所以回归器的输出是每个RoI需要进行的位置偏移(offset)。回归器的输出为 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) ,那每个RoI也有一个regression target v v v,所以回归器的损失函数可以表示为: L l o c ( t u , v ) = ∑ i ∈ x , y , w , h s m o o t h L 1 ( t i u − v i ) L_{loc}(t^u,v)=\sum_{i\in{x,y,w,h}} smooth_{L_1}(t^u_i-v_i) Lloc(tu,v)=∑i∈x,y,w,hsmoothL1(tiu−vi)
其中, s m o o t h L 1 ( x ) = { 0.5 x 2 i f ∣ x ∣ < 1 ∣ x ∣ − 0.5 o t h e r w i s e smooth_{L_1}(x)= \begin{cases}0.5x^2 &\text if |x|<1 \\ |x|-0.5 &\text otherwise \end{cases} smoothL1(x)={0.5x2∣x∣−0.5if∣x∣<1otherwise
所以, Fast R-CNN的损失函数可以表示为: L ( p , u , t u , v ) = L c l s ( p , u ) + λ [ u ≥ 1 ] L l o c ( t u , v ) L(p,u,t^u,v)=L_{cls}(p,u)+\lambda[u\geq1] L_{loc}(t^u,v) L(p,u,tu,v)=Lcls(p,u)+λ[u≥1]Lloc(tu,v)
其中, [ u ≥ 1 ] [u\geq1] [u≥1] 是一个指示器,当 u ≥ 1 u\geq1 u≥1时,为1,否则为0。这是因为当 u = 0 u=0 u=0 时,代表是背景,所以我们就不需要考虑这个RoI的位置。
其中关于每个RoI的ground truth的定义:如果这个RoI和某个ground truth box有最大的IoU值,那么这个ground truth box的类别就是这个RoI对应的ground truth class,然后这个RoI变到该ground truth box的位置变换,即为该RoI的regression ground truth。
这个主要是讲RoI pooling layer的反向传播,这个其实就和pooling层的反向传播类似,毕竟它本质上也就是个pooling层嘛。所以我们先来看一下pooling层如何进行反向传播的。
下图显示的是max pooling的前向传播和反向传播,前向传播主要是处理feature,比如(2, 2)的pool size,就是在(2, 2)的区域内取一个最大值。那反向传播呢主要是处理gradient,过程和前向刚好相反,这里是把值赋予给原来最大值所在的那个位置,然后 其他位置就设置为0(如右图所示)。
下图显示的是average pooling的前向传播和反向传播,前向传播主要是处理feature,比如(2, 2)的pool size,就是在(2, 2)的区域内求一个平均值。那反向传播呢主要是处理gradient,过程和前向刚好相反,是把值均分为4份赋予给原来(2, 2)区域内的所有位置(如右图所示)。
在测试时,就是输入一张图片和object proposals(RoI)到网络中,网络便会输出每个RoI的分类结果和位置偏移,然后就对RoI进行位置调整,最后同样也是使用非极大值抑制(NMS)来去除掉重复的框,便得到最终的结果。
