Intro
关于Faster RCNN的介绍或者详解,网上已经有相当多的介绍,比如:一文读懂Faster RCNN。接下来结合实现,介绍一些容易让人产生疑惑的重点难点。
Anchor的生成
在我们日常的讨论中,Anchor一般都两种含义:
- 对GT框宽高值的一种先验估计,比如Faster RCNN中用到的9个anchor,为了避免混淆,我们称之为Base Anchor
- 将Base Anchor应用于回归Feature map的每个点,得到回归Feature Map中的每个Anchor对应的先验回归值。为了避免混淆,我们称之为Anchor Map
下面我们分别讨论这两种含义
Base Anchor的生成
在Faster RCNN中,作者并没有使用大小特定的Base Anchor,而是利用Output Feature Stride + 3个scale + 3个ratio的去表示Base Anchor。
此外,BaseAnchor本质上只需要2个数就可以表示,也就是宽高。但Faster RCNN为了计算过程的方便,使用4个数来表示,分别是Anchor的左上角坐标
(
x
0
,
y
0
)
(x_0, y_0)
(x0,y0)和右下角坐标
(
x
1
,
y
1
)
(x_1, y_1)
(x1,y1)
- Output Feature Stride: 相当于最终RPN输出的feature map大小与原图之间的比例。e.g.对于Faster RCNN(VGG backbone)而言,RPN输出的Feature Map大小为原来的1/16,此时Output Feature Stride = 16(下同)
- Scale: 根据 Output Feature Stride,我们定义参考Base Anchor宽高为 ( 16 , 16 ) (16, 16) (16,16),这个参考Base Anchor根据3个不同的Scale: 8, 16, 32,去生成3个宽高比为 1 : 1 1:1 1:1的Base Anchor,宽高为 ( 128 , 128 ) (128, 128) (128,128) ( 256 , 256 ) (256, 256) (256,256) ( 512 , 512 ) (512 ,512) (512,512)
- ratio: 根据3个不同的比例: ( 1 : 1 ) (1:1) (1:1), ( 1 : 2 ) (1:2) (1:2), ( 2 : 1 ) (2:1) (2:1),基于 ( 128 , 128 ) (128, 128) (128,128) ( 256 , 256 ) (256, 256) (256,256) ( 512 , 512 ) (512 ,512) (512,512)这3个Base Anchor继续扩展。 ( 1 : 1 ) (1:1) (1:1)就是这3个Base Anchor本身,而 ( 1 : 2 ) (1:2) (1:2)和 ( 2 : 1 ) (2:1) (2:1)则在保持Base Anchor面积的情况下,对Anchor进行缩放。基于3种尺度和3种比例,最终生成9个Base Anchor的宽高,分别是:
[[184, 96], [128, 128], [88, 176],
[368, 192], [256, 256], [176, 352],
[736, 384], [512, 512], [352, 704]]
这9个Base Anchor的宽高容易让人产生疑惑:数值上可能会和手算“在保持Base Anchor面积的情况下,对Anchor进行缩放”得到的结果不同。原因其实仅仅是数值计算方面的问题:因为Faster RCNN是先基于参考Base Anchor,算出不同ratio下的Base Anchor,四舍五入后再乘以对应的scale。详细可以看代码 generate_anchor.py
这样我们仅得到了Base Anchor的宽高,Faster RCNN用具体的坐标值来表示一个Base Anchor,于是我们需要进行一个转换:
(
A
w
,
A
h
)
(A_w, A_h)
(Aw,Ah) ->
(
A
x
0
,
A
y
0
,
A
x
1
,
A
y
1
)
(A_{x0}, A_{y0}, A_{x1}, A_{y1})
(Ax0,Ay0,Ax1,Ay1)。
- 首先,我们需要确定Base Anchor的中心,Faster RCNN将Base Anchor的中心设为Feature Stride的一半, e.g. A c = ( 16 − 1 ) / 2 A_c = (16 - 1) / 2 Ac=(16−1)/2, -1的操作是严格取坐标中心(0和15的中点)
- 然后就可以通过
(
A
w
,
A
h
)
(A_w, A_h)
(Aw,Ah)来计算
(
A
x
0
,
A
y
0
,
A
x
1
,
A
y
1
)
(A_{x0}, A_{y0}, A_{x1}, A_{y1})
(Ax0,Ay0,Ax1,Ay1)
- A x 0 = A c − A w ′ A_{x0} = A_c - A_{w'} Ax0=Ac−Aw′
- A w ′ = ( A w − 1 ) / 2 A_{w'} = (A_w - 1) / 2 Aw′=(Aw−1)/2
- 同理可得 A x 1 A_{x1} Ax1, A y 1 A_{y1} Ay1, A y 0 A_{y0} Ay0
- 最终得到9个Base Anchor的坐标:
A w A_w Aw | A h A_h Ah | A x 0 A_{x0} Ax0 | A y 0 A_{y0} Ay0 | A x 1 A_{x1} Ax1 | A y 1 A_{y1} Ay1 |
---|---|---|---|---|---|
184 | 96 | -84. | -40. | 99. | 55. |
128 | 128 | -56. | -56. | 71. | 71. |
88 | 176 | -36. | -80. | 51. | 95. |
368 | 192 | -176. | -88. | 191. | 103. |
256 | 256 | -120. | -120. | 135. | 135. |
176 | 352 | -80. | -168. | 95. | 183. |
736 | 384 | -360. | -184. | 375. | 199. |
512 | 512 | -248. | -248. | 263. | 263. |
352 | 704 | -168. | -344. | 183. | 359. |
将这9个Base Anchor放回原图,大致是下图的效果:
Anchor Map的生成
- 最终回归的Feature Map中的每一个点 ( x , y ) (x,y) (x,y),都有9个Anchor,也就是说生成一个 ( W ∗ H ∗ 9 ∗ 4 ) (W*H*9*4) (W∗H∗9∗4)的Feature Map
- 上述的9个Base Anchor,实质上是最终回归的Feature Map中 ( 0 , 0 ) (0, 0) (0,0)对应的Anchor
- ( x , y ) (x,y) (x,y)对应原图中的对应坐标为 ( x ∗ 16 , y ∗ 16 ) (x*16, y*16) (x∗16,y∗16)(因为stride = 16)
- ( x , y ) (x,y) (x,y)上的Anchor的计算方式: ( A x 0 + x ∗ 16 , A y 0 + y ∗ 16 , A x 1 + x ∗ 16 , A y 1 + y ∗ 16 ) (A_{x0} + x * 16, A_{y0} + y * 16, A_{x1} + x * 16, A_{y1} + y * 16) (Ax0+x∗16,Ay0+y∗16,Ax1+x∗16,Ay1+y∗16)
- 将每个点中的9个anchor都画出来的画,效果大致如下图所示(假设原图大小为1024*1024, )。黑色框内为图像区域(0,0) ~ (1023, 1023),显然,有些Anchor是超出了图像边界的,至于如何处理,在【Label的生成】部分会介绍