【论文】Shaoqing Ren, Kaiming He, Ross Girshick, Jian Sun. Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks.(pdf)
整体框架
Faster RCNN 可以分为 4 个大模块;
-
Conv Layers
用于图片的特征提取,经过一系列的 conv + relu + pooling 的特征映射
-
Region Proposal Networks
用于推荐候选区域,替代之前在 RCNN 或 Fast RCNN 中的 search selective,通过 softmax 判断 anchor 属于正样本还是负样本,然后利用 bbox regression 修正 anchor 获得精确的 proposal
-
RoI Pooling
和 Fast RCNN 一样,将不同大小形状的 proposal 转换为固定大小的输出 proposal feature
-
Classification
利用 proposal feature 计算 proposal 的类别,同时再次使用 bbox regression 获得加测框的最终精确位置
下面展示了 Faster RCNN 的细节处理,假设输入一张任意大小的图片 P × Q P\times Q P×Q
- 首先,缩放至固定大小 M × N M\times N M×N,然后再将图片送入网络
- Conv Layers 包含了 13 个卷积层(kernel_size = 3, padding = 1, stride = 1) + 13 个 ReLU + 4 个 池化层(kernel_size = 2, padding = 0, stride = 2)
- RPN 首先经过 3 × 3 3\times3 3×3 的卷积,分别生成 positive anchor 和对应的 bbox regression,然后计算出需要的 proposal
- RoI Pooling 则利用 proposal 对应 feature map 得到 proposal feature。后续送入全连接网络通过 softmax 做分类
Conv Layers
Faster RCNN 中对所有卷积都进行了 padding 处理(padding = 1),于是经过 3 × 3 3\times3 3×3 的卷积后输出图的大小并不发生改变(经过卷积后 ( M − 3 + 2 × 1 ) / 1 + 1 = M (M-3+2\times1)/1+1=M (M−3+2×1)/1+1=M)
这样的好处是,每次经过池化层图片大小缩小为原来的一半,即 M 2 × N 2 \frac{M}{2}\times\frac{N}{2} 2M×2N,而卷积和 relu 不改变图片大小,于是在经过 Conv Layers 后,图片变为 M 16 × N 16 \frac{M}{16}\times\frac{N}{16} 16M×16N,这样在 RoI Pooling 时将非常容易对齐
Anchor Generation Layer
Fast RCNN 中会反复提到一个概念——anchor,所谓 anchor 其实就是一组矩形框,9 个矩形有 3 种形状,长宽比大约为 1 : 1 1:1 1:1 、 、 、 1 : 2 1:2 1:2 和 2 : 1 2:1 2:1,实际上通过关 anchor 就引入了检测中常用的多尺度方法
在 Conv Layers 输出的 feature map 的每个点都配备这 9 个 anchor 作为初始的检测框,这样获得的检测框存在不准确的问题也不用太担心,后面会有两次机会通过回归修正检测框的位置
我们对论文图片做如下两点解释:
-
首先,Conv Layers 中的 conv5 的输出维度为 256,也就是有 256 张特征图,选用这一层的特征做 RPN 的输入,那么在每个点上维度都是 256
-
假设每个点有 k k k 个 anchor,每个 anchor 分为 positive 和 negative,那么分类得分就是 2 k 2k 2k;同时,每个 anchor 都有 ( x , y , w , h ) (x, y, w, h) (x,y,w,h) 4 个偏移量,所以会有 4 k 4k 4k coordinates
于是,接下来 anchor generation layer 的操作就是在原图尺度上生成密密麻麻的候选 anchor,论文中原图的大小为 800 × 600 800\times600 800×600,在通过 Conv Layer 后,feature map 的大小就是 50 × 38 50\times38 50×38(向上取整),那么就会生成 50 × 38 × 9 = 17100 50\times38\times9=17100 50×38×9=17100 个 anchor
Bounding Box Regression
如下图所示,红色的框为提取的 positive anchor box,绿色的框为 ground truth box,即便红色的框可以识别出飞机,但是由于定位不准确,我们需要 bbox regression 对红色的框进行微调,使得其更加接近于 ground truth
对于一个 box 使用 ( x , y , w , h ) (x,y,w,h) (x,y,w,h) 表示,分别表示中心点的位置和宽高。下图中还是用红色的框表示 positive anchor box A = ( A x , A y , A w A h ) A=(A_x,A_y,A_wA_h) A=(Ax,Ay,AwAh),绿色的框表示 ground truth box G = ( G x , G y , G w , G h ) G=(G_x,G_y,G_w,G_h) G=(Gx,Gy,Gw,Gh),我们希望寻得一种关系可以使 A A A 经过映射得到一个跟 ground truth box 更接近的 regression box G ′ = ( G x ′ , G y ′ , G w ′ , G h ′ ) G'=(G'_x,G'_y,G'_w,G'_h) G′=(Gx′,Gy′,Gw′,Gh′)
我们先做平移操作
G
x
′
=
A
w
⋅
d
x
(
A
)
+
A
x
G
y
′
=
A
h
⋅
d
y
(
A
)
+
A
y
G'_x=A_w\cdot d_x(A)+A_x\\ G'_y=A_h\cdot d_y(A)+A_y
Gx′=Aw⋅dx(A)+AxGy′=Ah⋅dy(A)+Ay
再做缩放
G
w
′
=
A
w
⋅
e
x
p
(
d
w
(
A
)
)
G
h
′
=
A
h
⋅
e
x
p
(
d
h
(
A
)
)
G'_w=A_w\cdot exp(d_w(A))\\ G'_h=A_h\cdot exp(d_h(A))
Gw′=Aw⋅exp(dw(A))Gh′=Ah⋅exp(dh(A))
其实,我们需要学习的参数只有 4 个
d
x
(
A
)
,
d
y
(
A
)
,
d
w
(
A
)
,
d
h
(
A
)
d_x(A),d_y(A),d_w(A),d_h(A)
dx(A),dy(A),dw(A),dh(A),在 anchor box 与 ground truth box 之间的差异不太大时,我们可以将其看作是一种线性变换,那么就可以使用线性回归来微调(差异过大时,这时将是一个非线性的问题)
线性变换可以表示为
Y
=
W
X
Y=WX
Y=WX,输入是 anchor 对应的 feature map 组成的特征向量
ϕ
(
A
)
\phi(A)
ϕ(A),训练同时传入
A
A
A 与
G
G
G 之间的差异
(
t
x
,
t
y
,
t
w
,
t
h
)
(t_x,t_y,t_w,t_h)
(tx,ty,tw,th),那么变换的目标函数就可以表示为
d
∗
(
A
)
=
W
∗
T
⋅
ϕ
(
A
)
d_*(A)=W_*^T\cdot\phi(A)
d∗(A)=W∗T⋅ϕ(A)
为了让预测值
d
∗
(
A
)
d_*(A)
d∗(A) 与真实值
t
∗
t_*
t∗ 的差距最小,设计 L1 损失函数
L
o
s
s
=
∑
i
N
∣
t
∗
i
−
W
∗
T
⋅
ϕ
(
A
i
)
∣
Loss=\sum_i^N|t_*^i-W_*^T\cdot\phi(A^i)|
Loss=i∑N∣t∗i−W∗T⋅ϕ(Ai)∣
函数优化目标为
W
^
∗
=
a
r
g
m
i
n
W
∗
∑
i
N
∣
t
∗
i
−
W
∗
T
⋅
ϕ
(
A
i
)
∣
+
λ
∣
∣
W
∗
∣
∣
\hat W_*=\underset{W_*}{argmin}\ \sum_i^N|t_*^i-W_*^T\cdot\phi(A^i)|+\lambda||W_*||
W^∗=W∗argmin i∑N∣t∗i−W∗T⋅ϕ(Ai)∣+λ∣∣W∗∣∣
实际中使用 smooth-L1 损失
s
m
o
o
t
h
L
1
(
x
)
=
{
σ
2
x
2
2
∣
∣
x
∣
<
1
σ
2
∣
x
∣
∣
−
0.5
σ
2
o
t
h
e
r
w
i
s
e
smooth_{L1}(x)=\left\{\begin{matrix} \frac{\sigma^2x^2}{2} & ||x|<\frac{1}{\sigma^2}\\ |x||-\frac{0.5}{\sigma^2} & otherwise \end{matrix}\right.
smoothL1(x)={2σ2x2∣x∣∣−σ20.5∣∣x∣<σ21otherwise
清楚了 bbox regression 下面我们要做的就是在 RPN 的第二条路径对 proposal 进行 bbox regression,论文中通过
1
×
1
1\times1
1×1 的卷积实现,卷积的输出为 36,刚好对应一个点 9 个 anchor,每个 anchor 有 4 个回归偏量
Region Proposal Network
Faster RCNN 抛弃传统的滑动窗口和 ss(Selective Search)方法生成检测框,直接采用 RPN 生成检测框。RPN 网络分为两条线,一条通过 softmax 分类判断 anchor 是正样本分类还是负样本分类,一条计算 anchor 的 bbox regression 偏移量。后面的 proposal 层负责综合 positive anchor 和回归的偏移量获得 proposal,同时提出太小或超出边界的检测框
RPN 训练的整个损失函数可以表示为
L
(
{
p
i
}
,
{
t
i
}
)
=
1
N
c
l
s
∑
i
L
c
l
s
(
p
i
,
p
i
∗
)
+
λ
1
N
r
e
g
∑
i
p
i
∗
L
r
e
g
(
t
i
,
t
i
∗
)
L(\left\{p_i\right\},\left\{t_i\right\})=\frac{1}{N_{cls}}\sum_iL_{cls}(p_i,p_i^*)+\lambda\frac{1}{N_{reg}}\sum_ip_i^*L_{reg}(t_i,t_i^*)
L({pi},{ti})=Ncls1i∑Lcls(pi,pi∗)+λNreg1i∑pi∗Lreg(ti,ti∗)
p
i
p_i
pi 表示 positive softmax probability;如果第
i
i
i 个 anchor box 与 ground truth box 的 IoU > 0.7 则
p
i
∗
=
1
p_i^*=1
pi∗=1 ,如果 IoU < 0.3,
p
i
∗
=
0
p_i^*=0
pi∗=0,至于,IoU 落在 0.3 到 0.7 之间的 anchor 则不参与训练;
t
t
t 表示 predicted bounding box,
t
∗
t^*
t∗ 代表 positive anchor 对应的 ground truth box
回归损失乘以了一个系数 p i ∗ p_i^* pi∗ 表示我们只关心 positive anchor 的损失。由于实际计算中, N c l s N_{cls} Ncls 和 N r e g N_{reg} Nreg 的数量级相差较大,所以引入了平衡因子 λ \lambda λ
如前面所述,
L
r
e
g
L_{reg}
Lreg 使用 smooth-L1 损失
L
r
e
g
(
t
i
,
t
i
∗
)
=
∑
i
∈
{
x
,
y
,
w
,
h
}
s
m
o
o
t
h
L
1
(
t
i
−
t
i
∗
)
P
r
o
p
o
s
a
l
l
a
y
e
r
L_{reg}(t_i,t_i^*)=\sum_{i\in\left\{x,y,w,h\right\}}smooth_{L_1}(t_i-t_i^*)Proposal layer
Lreg(ti,ti∗)=i∈{x,y,w,h}∑smoothL1(ti−ti∗)Proposallayer
t x = ( x − x a ) / w a , t y = ( y − y a ) / h a t w = l o g ( w / w a ) , t h = l o g ( h / h a ) t x ∗ = ( x ∗ − x a ) / w a , t y ∗ = ( y ∗ − y ) / h a t w ∗ = l o g ( w ∗ / w a ) , t h ∗ = l o g ( h ∗ / h a ) t_x=(x-x_a)/w_a,\ t_y=(y-y_a)/h_a\\ t_w=log(w/w_a),\ t_h=log(h/h_a)\\ t_x^*=(x^*-x_a)/w_a,\ t_y^*=(y^*-y)/h_a\\ t_w^*=log(w^*/w_a),\ t_h^*=log(h^*/h_a) tx=(x−xa)/wa, ty=(y−ya)/hatw=log(w/wa), th=log(h/ha)tx∗=(x∗−xa)/wa, ty∗=(y∗−y)/hatw∗=log(w∗/wa), th∗=log(h∗/ha)
其中, x , x a , x ∗ x,x_a,x^* x,xa,x∗ 分别对应 predicted box,anchor box 和 ground truth box
proposal layer
proposal layer 负责综合回归偏量和 positive anchor,计算出精确的 proposal。除了回归偏量和 positive anchor 外,proposal layer 还有一个输入 im_info,以及一个参数 feature_stride = 16
- feature_stride 记录了 Conv Layers 的缩放程度,即经过 4 次池化,每次缩小为原来的一半,最终的 feature map 为 M 16 × N 16 \frac{M}{16}\times\frac{N}{16} 16M×16N
- 对于一张任意大小 P × Q P\times Q P×Q 的图像都会缩放到固定大小 M × N M\times N M×N,im_fo 记录的则是这一步的缩放信息,即 i m _ f o = [ M , N , s c a l e _ f a c t o r ] im\_fo = [M, N, scale\_factor] im_fo=[M,N,scale_factor]
proposal layer 具体的工作流程如下:
- 利用回归偏量对所有的 anchor 做位置修正生成 anchor
- 按照输入的 positive softmax socre 对 anchor 进行排序,然后提取前 12k 个(测试时 6k)修正位置后的 positive anchor
- 限定超出图像边界的 positive anchor 为图像边界,防止后续 RoI Pooling 时 proposal 超出图像边界
- 剔除尺寸非常小的 positive anchor
- 对剩余的 positive anchor 进行非最大抑制,然后取前 2k 个(测试时300 个) positive anchor
- 最后取挑出 128 个正样本和 128 个负样本用于训练
值得一提的是这里 proposal layer 的输出是对应 M × N M\times N M×N 输入尺度的,而不是 feature map 上的尺度
RoI Pooling
为什么需要 RoI Pooling 呢?
在历史上,网络训练好后输入图像的尺寸也就固定了,对于输入大小不同的图像有两种解决方法:(1)从图像中截取出固定大小的区域;(2)将图像 warp 成固定大小。但是这两种方式都存在一定的问题,第一种破坏了图像的完整结构,第二种破坏了图像的原始形状信息
而 RoI Pooling 的提出正是为了解决这些问题,对大小形状不同的 proposal 进行一个统一化的处理。RoI Pooling 在 Fast RCNN 中就已经提出,大致流程也是相同的:
- 由于前面传入的 proposal 尺寸对应 M × N M\times N M×N,所以先将其映射回 M 16 × N 16 \frac{M}{16}\times\frac{N}{16} 16M×16N 的 feature map 大小进行讨论
- 将每个 proposal 对应的区域分为 p o o l e d _ w × p o o l e d _ h pooled\_w\times pooled\_h pooled_w×pooled_h(e.g. 7 × 7 7\times7 7×7)大小的网格
- 最后进行 max pooling 操作
Classification
Classification 通过前面的 proposal feature map 经过全连接层和 softmax 计算每个 proposal 对应每个类别的得分。同时,在 Classification 中会再次利用 bbox regression 对每个 proposal 的位置进行精修
Faster RCNN 训练
RPN 和 Fast RCNN 都会要求利用 CNN 网络提取图像特征,所以论文的做法是使 RPN 和 Fast RCNN 共享同一个卷积网络。于是,Fast RCNN 的训练类似于一种弄迭代的过程:
- 先训练 RPN,然后使用得到的候选区域训练 Fast RCNN
- 接着使用 Fast RCNN 中关于卷积网络的部分去初始化 RPN,然后再次训练 RPN,这里不跟新关于卷积网络的内容,仅更新 RPN 特有的部分
- 最后再次训练 Fast RCNN,这里也是不更新关于卷积网络的部分,仅更新 Fast RCNN 特有的层
(现在,在 github 上开源的实现大多采用近似联合训练 approximate joint training,采用端到端的一步训练)
下面两幅图展示了 Fast RCNN 的完整流程