文章《Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition》是在RCNN之后,是对RCNN的改进(关于RCNN可以查看R-CNN文章详细解读),先给出SPP-net总的框架图如下
该文章主要改进两点:
1. CNN需要固定输入图像的尺寸,导致不必要的精度损失
2. R-CNN对候选区域进行重复卷积计算,造成计算冗余
1.为什么CNNs要固定输入图像的尺寸?
CNN主要有两部分组成:卷积层和全连接层。卷积层以滑动窗口方式操作并输出表示各个响应激活空间分布的特征图。实际上,卷积层不需要输入的图像尺寸固定,并且可以产生任意尺寸的特征图。但另一方面,完全连接层需要具有固定大小/长度的输入。 因此,固定输入大小的约束只是来自存在于网络更深层阶段的全连接层。
解决办法(对比R-CNN, SPP-net):
R-CNN | SPP-net |
---|---|
固定输入图像的尺寸,在将图像输入CNN前,进行图片的缩放(详细情况查看R-CNN文章详细解读),这样会导致裁剪区域可能不包含整个对象,或者缩放时候产生的扭曲可能会导致不必要的几何失真 | 提出空间金字塔池化层简称SPP层,在最后一个卷积层的顶部添加一个SPP层。 SPP层对这些特征进行池化并生成固定长度的输出,然后将其输入到完全连接层(或其他分类器)。 |
如下图所示
第一行中的图像即为要求固定尺寸输入的CNN对图像的处理方式
第二行为要求固定尺寸输入的CNN (如R-CNN)的处理流程,先将图片按照类似第一行中的方式进行处理,然后输入卷积以及全连接层,最后输出结果
第三行为SPP-net的处理方式,不固定图像的大小,直接输入给卷积层处理,卷积出来的特征并不是直接输入给全连接层,而是先给SPP层处理,然后得到一个固定长度的输出传给全连接层,最后输出结果。
2.R-CNN为什么会有计算冗余?
如下图所示
R-CNN对于一张图片,先使用segment seletive方法提取出约2000个候选区域,然后将这两千个候选区域分别送入网络中,即一张图片要经历2000次前向传播,这样会造成大量冗余。
SPP-net则提出了一种从候选区域到全图的特征(feature map)之间的对应映射关系,通过此种映射关系可以直接获取到候选区域的特征向量,不需要重复使用CNN提取特征,从而大幅度缩短训练时间。每张图片只需进行一次前向传播即可。
下面来详细讲解一下改进的方法:
1.SPP层(spatial pyramid pooling)
首先要明确的是这一层的位置,这一层加在最后一个卷积层与全连接层之间,目的就是为了输出固定长度的特征传给要求固定输入的全连接层
SPP层的结构如下图所示
SPP层的输入:
如下图灰色框所示
最后一层卷积输出的特征(我们称为feature map),feature map为下图的黑色部分表示,SPP层的输入为与候选区域对应的在feature map上的一块区域
上面这句话可能有点绕,我们可以理解为一张图有约2000个候选区域,而对一张图做完卷积后得到feature map,在这个feature map上也有约2000个与候选区域对应的区域(这里的对应关系下面会详细讲解)
SPP层的输出:
SPP layer分成1x1,2x2,4x4三个pooling结构(这部分结构如下图所示),对每个输入(这里每个输入大小是不一样的)都作max pooling(论文使用的),出来的特征再连接到一起,就是(16+4+1)x256的特征向量。
无论输入图像大小如何,出来的特征固定是(16+4+1)x256维度。这样就实现了不管图像中候选区域尺寸如何,SPP层的输出永远是(16+4+1)x256特征向量。
2.候选区域在原图与feature map之间的映射关系
这部分的计算其实就是感受野大小的计算。
在CNN中感受野(receptive fields)是指某一层输出结果中一个元素所对应的上一层的区域大小,如下图所示。
先定义几个参数,参数的定义参考吴恩达在cousera讲解中对符号的定义,然后再讲解怎么计算
类型 | 大小 |
---|---|
第 l l l层的输入尺寸 | W [ l − 1 ] ∗ H [ l − 1 ] W^{[l-1]}*H^{[l-1]} W[l−1]∗H[l−1] |
第 l l l层的输出尺寸 | W [ l ] ∗ H l W^{[l]}*H^{l} W[l]∗Hl |
第 l l l层的卷积核大小 | f [ l ] ∗ f [ l ] f^{[l]}*f^{[l]} f[l]∗f[l] |
第 l l l层的卷积步长 | S [ l ] S^{[l]} S[l] |
第 l l l层的填充大小 | p [ l ] p^{[l]} p[l] |
输入的尺寸大小与输出的尺寸大小有如下关系:
W
[
l
]
=
(
W
[
l
−
1
]
+
2
p
[
l
]
−
f
[
l
]
)
/
S
[
l
]
+
1
W^{[l]}=(W^{[l-1]}+2p^{[l]}-f^{[l]})/S^{[l]}+1
W[l]=(W[l−1]+2p[l]−f[l])/S[l]+1
H
[
l
]
=
(
H
[
l
−
1
]
+
2
p
[
l
]
−
f
[
l
]
)
/
S
[
l
]
+
1
H^{[l]}=(H^{[l-1]}+2p^{[l]}-f^{[l]})/S^{[l]}+1
H[l]=(H[l−1]+2p[l]−f[l])/S[l]+1
上面是区域尺寸大小的对应关系,下面看一下坐标点之间的对应关系
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)
含义 | 符号 |
---|---|
在i层的坐标值 | p i p_i pi |
i层的步长 | s i s_i si |
i层的卷积核大小 | k i k_i ki |
i层填充的大小 | padding |
SPP-net对上面的坐标对应关系作了一定的简化,简化过程如下:
- 令每一层的padding都为
p a d d i n g = ⌊ k i / 2 ⌋ ⇒ p i = s i ⋅ p i + 1 + ( ( k i − 1 ) / 2 − ⌊ k i / 2 ⌋ ) padding = \lfloor k_i /2 \rfloor \Rightarrow pi = s_i \cdot p_{i+1} +( (k_i -1)/2 - \lfloor k_i /2 \rfloor) padding=⌊ki/2⌋⇒pi=si⋅pi+1+((ki−1)/2−⌊ki/2⌋) - 当 k_i 为奇数 ( ( 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有关。
那么对于下图的做法,就是SPP-net的映射方法,SPP-net 是把原始ROI的左上角和右下角 映射到 feature map上的两个对应点。 有了feature map上的两队角点就确定了 对应的 feature map 区域(下图中橙色)。
从原图坐标 ( x , y ) (x,y) (x,y)到特征图中坐标 ( 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
- 需要把上面公式进行级联得到 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)
- 对于feature map 上的 ( x ′ , y ′ ) (x',y') (x′,y′)它在原始图的对应点为 ( x , y ) = ( S x ′ , S y ′ ) (x,y) = (Sx', Sy') (x,y)=(Sx′,Sy′)
- 论文中的最后做法:把原始图片中的ROI映射为 feature map中的映射区域(上图橙色区域)其中 左上角取: 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;右下角的点取:界取 y ′ y' y′的 x x x值: x ′ = ⌈ x / S ⌉ − 1 , y ′ = ⌈ y / S ⌉ − 1 x' = \lceil x/S \rceil - 1, y' = \lceil y/S \rceil - 1 x′=⌈x/S⌉−1,y′=⌈y/S⌉−1。
到这里就把SPPNet的核心思想讲完了,SPPNet网络后面和R-CNN类似,详细参考R-CNN文章详细解读。该文章还用这些思想做了图像分类的实验,感兴趣可以细读原文的分类部分。
参考:
- http://www.robots.ox.ac.uk/~tvg/publications/talks/fast-rcnn-slides.pdf
- http://kaiminghe.com/iccv15tutorial/iccv2015_tutorial_convolutional_feature_maps_kaiminghe.pdf
- http://kaiminghe.com/eccv14sppnet/sppnet_ilsvrc2014.pdf
- https://zhuanlan.zhihu.com/p/24780433
- https://blog.csdn.net/u011974639/article/details/78053203#sppnet