最近在学习目标检测sPPnet时看到ROI映射到featuremap中的方法,文中对此叙述较少,所以就此问题差了一些资料,在知乎上发现一片理解较好的文章(文末给出了参考文献),于此做一总结。
先谈一下感受视野,在学习卷积的时候,我们比较熟悉的是上一层图映射到下一层之后的尺寸,很少谈及感受野,这其实是一个重要的概念。
卷积中的感受视野
首先,我们知道上一层图的尺寸,去推测下一层的尺寸,如下公式即可,这个大家应该很熟悉
output field size = ( input field size - kernel size + 2*padding ) / stride + 1
(output field size 是卷积层的输出,input field size 是卷积层的输入,stride步长,padding填充像素,kernelsize卷积核尺寸)
随后,我们想如果知道后一层的尺寸,是不是就可以知道前一层的尺寸
答案必然是: input field size = (output field size - 1)* stride - 2*padding + kernel size
那么此时如果我们把最后一层的尺寸定为1,向前推是不是可以知道最后一层的一个小单位格子对应到原图的尺寸,也就是感受野了。
卷积神经网络CNN中,某一层输出结果中一个元素所对应的输入层的区域大小,被称作感受野receptive field。感受野的大小是由kernel size,stride,padding , outputsize 一起决定的。
我们可以看下面这张图更好的理解下
虽然原图很大,但我们考虑原图中的11*11的尺寸向后映射到map2变为77的尺寸,再向后映射到11.
7=(11-5)/1+1;
1=(7-7)/1+1;
是不是~~
之后我们反过来证明一下
最后一层向map2映射7 = (1-1)*1+7
map2向map1映射11 = (7-1)*1+5
了解了感受野,我们再看一下坐标变换
坐标变换
在感受野上面做坐标变换,实则是对中心位置做变换,如下图map3的一个点(位置为p3)它向上映射到map2的范围内中心位置是多少呢?
我们可以用下面这个公式来理解
对于 Convolution/Pooling layer:
p
i
=
s
i
⋅
p
i
+
1
+
(
(
k
i
−
1
)
/
2
−
p
a
d
d
i
n
g
)
p_i = s_i \cdot p_{i+1} +( (k_i -1)/2 - padding)
pi=si⋅pi+1+((ki−1)/2−padding)(P代表位置,k表示卷积核大小,s代表步长)
对于Neuronlayer(ReLU/Sigmoid/…) :
p
i
=
p
i
+
1
p_i = p_{i+1}
pi=pi+1
在此画了一个图方便理解,下面一层的绿色点反映一个1*1的点中对应到上一层绿色点,他其实是在最左侧的基本格子向右平移p(p就是下面那层的坐标)个stride(本层的步长)所以这部分坐标就是 s i ⋅ p i + 1 s_i \cdot p_{i+1} si⋅pi+1
然后还差一个基本格子的半个坐标就用 ( ( k i − 1 ) / 2 − p a d d i n g ) ( (k_i -1)/2 - padding) ((ki−1)/2−padding)来决定哈哈!完美!
我们最后再看一下下面这个图给出的计算!理解一下它的计算!
上面是感受野的映射公式,到了ROI对于上面的公式,何凯明在SPP-net中采用做了一个简化。其实就是巧妙的化简一下公式
p
i
=
s
i
⋅
p
i
+
1
+
(
(
k
i
−
1
)
/
2
−
p
a
d
d
i
n
g
)
pi = s_i \cdot p_{i+1} +( (k_i -1)/2 - padding)
pi=si⋅pi+1+((ki−1)/2−padding)
令每一层的padding都为
p
a
d
d
i
n
g
=
⌊
k
i
/
2
⌋
⇒
padding = \lfloor k_i /2 \rfloor \Rightarrow
padding=⌊ki/2⌋⇒
p
i
=
s
i
⋅
p
i
+
1
+
(
(
k
i
−
1
)
/
2
−
⌊
k
i
/
2
⌋
)
pi = s_i \cdot p_{i+1} +( (k_i -1)/2 - \lfloor k_i /2 \rfloor)
pi=si⋅pi+1+((ki−1)/2−⌊ki/2⌋)
当
k
i
k_i
ki 为奇数
(
(
k
i
−
1
)
/
2
−
⌊
k
i
/
2
⌋
)
=
0
( (k_i -1)/2 - \lfloor k_i /2 \rfloor) = 0
((ki−1)/2−⌊ki/2⌋)=0 所以
p
i
=
s
i
⋅
p
i
+
1
p_i = s_i \cdot p_{i+1}
pi=si⋅pi+1
当k_i 为偶数
(
(
k
i
−
1
)
/
2
−
⌊
k
i
/
2
⌋
)
=
−
0.5
( (k_i -1)/2 - \lfloor k_i /2 \rfloor) = -0.5
((ki−1)/2−⌊ki/2⌋)=−0.5 所以
p
i
=
s
i
⋅
p
i
+
1
−
0.5
p_i = s_i \cdot p_{i+1} -0.5
pi=si⋅pi+1−0.5
而
p
i
p_i
pi 是坐标值,不可能取小数 所以基本上可以认为
p
i
=
s
i
⋅
p
i
+
1
p_i = s_i \cdot p_{i+1}
pi=si⋅pi+1。公式得到了化简:感受野中心点的坐标
p
i
p_i
pi只跟前一层
p
i
+
1
p_{i+1}
pi+1 有关。
ROI映射变换
ROI映射的时候是将左上角和右小角映射到featuremap然后确定最后的区域。
考虑原图上的点不可能每一个点在featuremap中都有对应,所以我们就找最近的点。
例如图中左上角的点(x,y)映射到 feature map上的(x’,y’) : 使得 (x’,y’) 在原始图上感受野(上图绿色框)的中心点 与(x,y)尽可能接近。
在上面每层都填充padding/2 得到的简化公式 :
p
i
=
s
i
⋅
p
i
+
1
p_i = s_i \cdot p_{i+1}
pi=si⋅pi+1
我们考虑从featuremap传到原图得到
p
0
=
S
⋅
p
i
+
1
p_0 = S \cdot p_{i+1}
p0=S⋅pi+1 其中
(
S
=
∏
0
i
s
i
)
(S = \prod_{0}^{i} s_i)
(S=∏0isi)(所有步长量乘积~~)
呵呵简单了不少。把式子反过来就变为:
x
′
=
⌊
x
/
S
⌋
,
  
y
′
=
⌊
y
/
S
⌋
x' = \lfloor x/S \rfloor ,\;y' = \lfloor y/S \rfloor
x′=⌊x/S⌋,y′=⌊y/S⌋。
这样就实现了ROI坐标变换,sPPnet中改了一下:
x
′
=
⌊
x
/
S
⌋
+
1
,
  
y
′
=
⌊
y
/
S
⌋
+
1
x' = \lfloor x/S \rfloor +1 ,\;y' = \lfloor y/S \rfloor +1
x′=⌊x/S⌋+1,y′=⌊y/S⌋+1,加了一个1,有什莫用呢?笔者认为相当于把得到的坐标向里面缩一下保证准确性。
参考文献
[1]原始图片中的ROI如何映射到到feature map?
https://zhuanlan.zhihu.com/p/24780433
[2]目标检测CNN经典网络(二)SPPnet
https://blog.csdn.net/CLOUD_J/article/details/89893140