[论文笔记]Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition

参考自博客:http://sinb.github.io/Whatyouknowabout/spp-net-1/
https://blog.csdn.net/xzzppp/article/details/51377731
https://www.jianshu.com/p/9db81f1bb439

使用过卷积神经网络(CNN)的人都知道,训练数据的维度都是相同的,这样经过卷积池化后,得到的特征维度才能相同,进而才能将特征输入到分类器中训练分类器.输入维度相同这个限制太大了,这篇文章主要针对这个缺陷进行了改进,具体地就是加入了空间金字塔池化(Spatial Pyrimid Pooling),使得不同维度的输入最后都能得到相同维度的输出.所以SPP是Pooling的一种,在CNN中,Pooling层的作用主要有两个:

  • 引入invariance,包括translation-invariance,rotation-invariance,scale-invariance。
  • 完成feature map的聚合,实现数据降维,防止过拟合。

简介

作者认为,传统CNN所需要的固定维度输入这一限制,是造成任意尺度的图片识别准确率低的原因.传统的CNN需要先对训练图片进行处理,使其维度相同.具体有两种做法,裁剪(cropping)扭曲(warping).如下图.
[论文笔记]Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition
缺点是:裁剪了的区域可能并不包含整个物体,而扭曲则会带入几何方面的失真.另外,即使是裁剪和扭曲,我们仍然是认为规定了一个输入尺度,而真实的物体尺度很多,这个固定维度的输入直接忽略掉了这一点.
为何非要给CNN限制一个固定维度的输入?作者说,CNN就分两块,卷积层和全连层(fully-connected layer),卷积层的输出是特征图(feature map),这个特征图反映出了原始输入图片中对filter(卷积核)**的空间信息.卷积这一步是不需要固定大小的.是最后的全连层带来的这个限制.
作者针对这个问题,提出了在CNN的最后一个卷积层之后,加入一个SPP层,也就是空间金字塔池化,对之前卷积得到的特征进行”整合”(aggregation),然后得到一个固定长度的特征向量,再传到全连层去.如下图.
[论文笔记]Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition
SPP是词袋模型(Bag-of-Words)的扩展.为什么说是扩展?词袋模型没有特征的空间信息(就像它只能统计一个句子中每个单词的词频,而不能记录词的位置信息一样).在深层CNN里加入SPP会有3个优势:

  1. 相比之前的滑动窗池化(sliding window pooling),SPP可以对不同维度输入得到固定长度输出.
  2. SPP使用了多维的spatial bins(我的理解就是多个不同大小的窗),而滑动窗池化只用了一个窗.
  3. 因为输入图片尺度可以是任意的,SPP就提取出了不同尺度的特征.

作者说这3点可以提高深度网络的识别准确率.

SPP-net既然只在网络的最后几层(深层网络)中加入,而本质上就是池化,所以它可以加入到其他CNN模型中,比如AlexNet.作者的实验表明,加入了SPP的AlexNet效果确实提升了.作者认为SPP应该能提升更复杂的网络的能力.

原理

卷积和池化

一个CNN里,除了最后的全连层,前面的卷积层和池化层其实都可以看作是卷积运算(都是滑动窗).卷积操作得到的结果**(feature map)基本上和原始的输入图片是一个比例**.feature map的意义是,它不但表示了响应的强度,也记录了响应的位置信息.
对之前卷积得到的特征进行”整合”(aggregation),然后得到一个固定长度的特征向量,再传到全连层去.如下图.
[论文笔记]Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition
上图可视化了卷积和池化提取的特征的意义,就是feature map的意义,feature map上的每一个点(或者某一个区域)对应这实际物体的某种形状,也就是某种模式了.

SPP用法及原理

具体操作步骤:

1.把整张待检测的图片,输入CNN中,进行一次性特征提取,得到feature maps
2.然后在feature maps中找到各个候选框对应的区域
3.再对各个候选框对应的feature maps区域采用金字塔空间池化,提取出固定长度的特征向量
相对于R-CNN输入的是每个候选框,然后在进入CNN,因为SPP-Net只需要一次对整张图片进行特征提取

关键步骤解释

(1)如何在feature maps中找到原始图片中候选框的对应区域
候选框是通过一整张原图片进行检测得到的,而feature maps是经过原始图片卷积、下采样等一系列操作后得到的,feature maps的大小和原始图片的大小是不同的。

假设(x’,y’)表示特征图上的坐标点,坐标点(x,y)表示原输入图片上的点,那么它们之间有如下转换关系:(x,y)=(Sx’,Sy’),其中S的就是CNN中所有的步长(strides)的乘积;
反过来,通过(x,y)坐标求解(x’,y’),那么计算公式如下:x’=x/S+1
所以,输入原图片检测到的windows,可以得到每个矩形候选框的四个角点,然后再根据公式:

角点 换算公式
Left、Top x’=x/S+1
Right、Bottom x’=x/S-1

(2)空间金字塔池化如何提取特征,得到固定大小的特征向量

与传统的max pooling先确定滑动窗口大小和滑动步长的做法不同,SPP先确定最终pooling得到的featuremap大小
用一个简单的两层网络进行说明:输入一张任意大小的图片(通道数先假设为1,图片是找的无视那些层数。。。),假设其大小为(w,h),要求输出输出21个神经元。也就是我们输入一张任意大小的特征图的时候,我们希望提取出21个特征。空间金字塔特征提取的过程如下:
[论文笔记]Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition
如上图所示,当我们输入一张图片的时候,我们利用不同大小的刻度的网格(spatial bin),覆盖整个图片,对一张图片进行了划分。上面示意图中,利用了三种不同大小的刻度(4 * 4, 2 * 2 ,1 * 1),对一张输入的图片进行了划分,最后总共可以得到16+4+1=21个块,我们即将从这21个块中,每个块提取出一个特征,这样刚好就是我们要提取的21维特征向量。

  • 第一个网格有16个格子,把一张完整的图片,分成了16个块,也就是每个格子的大小就是(w/4,h/4);
  • 第二个网格,划分了4个块,每个bin的大小就是(w/2,h/2);
  • 把一整张图片作为了一个块,也就是bin的大小为(w,h)

空间金字塔最大池化的过程,其实就是从这21个图片块中,分别计算每个块的最大值,从而得到一个输出神经元。最后把一张任意大小的图片转换成了一个固定大小的21维特征(当然你可以设计其它维数的输出,增加金字塔的层数,或者改变划分网格的大小)。上面的三种不同刻度的划分,每一种刻度我们称之为:金字塔的一层,每一个图片块大小我们称之为:windows size了。如果你希望,金字塔的某一层输出n*n个特征,那么你就要用windows size大小为:(w/n,h/n)进行池化了。

SPP的原理其实就一句话,SPP的spatial bins是和输入图片(或feature map)的大小成比例的,而spatial bins的数目自定义的,和输入大小无关.具体地,在一个CNN里,把最以后一次池化层去掉,换成一个SPP去做最大池化操作(max pooling).如果最后一次卷积得到了k个feature map,也就是有k个filter,SPP有M个bin,那经过SPP得到的是一个kM维的向量.

总结

  • 在R-CNN中,每个候选框先resize到统一大小,然后分别作为CNN的输入,这样是很低效的。 所以SPP Net根据这个缺点做了优化:只对原图进行一次卷积得到整张图的feature map,然后找到每个候选框在feature map上的映射patch,将此patch作为每个候选框的卷积特征输入到SPP layer和之后的层。节省了大量的计算时间。
  • 和RCNN一样,训练过程仍然是隔离的,提取候选框 | 计算CNN特征| SVM分类 | Bounding Box回归独立训练,大量的中间结果需要转存,无法整体训练参数;
  • SPP-Net在无法同时Tuning在SPP-Layer两边的卷积层和全连接层,很大程度上限制了深度CNN的效果;
  • 在整个过程中,Proposal Region仍然很耗时
  • SPP的关键实现在于通过最后一层卷积层输出的feature map宽高和SPP目标输出的宽高计算spatial pyramid pooling层中不同分辨率的Bins对应的pooling window尺寸和其对应的pool stride

扩展内容(SPP的改进—ROI Pooling)

ROI(region of interest)

ROI Pooling将不同输入尺寸的feature map(ROI)通过分块池化的方法得到固定尺寸的输出,其思想来自于SPPNet。
rbg大神在Fast RCNN中使用时,将sppnet中多尺度的池化简化为单尺度,只输出固定尺寸为(w, h)的feature map。故RoI Pooling Layer是SPP-Layer的简化形式。SPP-Layer是空间金字塔Pooling层,包括不同的尺度;RoI Layer只包含一种尺度,如论文中所述77。这样对于RoI Layer的输入(r,c,h,w),RoI Layer首先产生77个rc(h/7)(w/7)的Block(块),然后用Max-Pool方式求出每一个Block的最大值,这样RoI Layer的输出是rc77。
[论文笔记]Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition
在Fast R-CNN网络中,原始图片经过多层卷积与池化后,得到整图的feature map。而由selective search产生的大量proposal经过映射可以得到其在feature map上的映射区域(ROIs),这些ROIs即作为ROI Pooling层的输入

ROI Pooling时,将输入的h * w大小的feature map分割成H * W个子窗口(每个子窗口的大小约为h/H,w/W,其中H、W为超参数,如设定为7 x 7),对每个子窗口进行max-pooling操作,得到固定输出大小的feature map。而后进行后续的全连接层操作。

Fast-RCNN具体步骤

1.输入一幅图像和Selective Search方法生成的一系列Proposals;
2.通过一系列卷积层和Pooling层生成feature map;
3.然后用RoI(region of ineterst)层处理最后一个卷积层得到的feature map为每一个proposal生成一个定长的特征向量roi_pool5;
4.RoI层的输出roi_pool5接着输入到全连接层产生最终用于多任务学习的特征并用于计算多任务Loss。全连接输出包括两个分支:(1)SoftMax Loss:计算K+1类的分类Loss函数,其中K表示K个目标类别,1表示背景;(2)Regression Loss:即K+1的分类结果相应的Proposal的Bounding Box四个角点坐标值;例如,以VGG16模型以初始化RoI Layer之前的所有层,则Fast R-CNN的网络结构整体可以总结如下:13个convolution layers + 4个pooling layers+RoI layer+2个fc layer+两个parrel层(即SoftmaxLoss layer和SmoothL1Loss layer)softmax classifer和bounding-box regressors联合训练的方式更新cnn网络所有层参数,两种Loss的权重比例为1:1;
5.最终将所有结果通过非极大抑制处理产生最终的目标检测和识别结果。

回顾SPP和ROI出现前的R-CNN网络的主要问题有:

  • 使用selective search产生proposal,操作耗时,且不利于网络的整体训练和测试
  • 产生的proposal需要经过warp操作再送入后续网络,导致图像的变形和扭曲
  • 每一个proposal均需要单独进行特征提取,重复计算量大
  • R-CNN中在获取到最终的CNN特征后先采用SVM进行类别判断,再进行bounding-box的回归得到位置信息。整个过程是个串行的流程。这极大地影响了网络的检测速度。

而ROI Pooling的加入,相对于R-CNN网络来说,至少有两个改善:

  • 由于ROI Pooling可接受任意尺寸的输入,warp操作不再需要,这有效避免了物体的形变扭曲,保证了特征信息的真实性
  • 不需要对每个proposal都提取特征,采用映射方式从整张图片的feature map上获取ROI feature区域
  • Fast R-CNN中则将Classification和regression的任务合二为一,变成一个multi-task的模型,实现了特征的共享与速度的进一步提升: