空间金字塔池化(Spatial Pyramid Pooling, SPP)原理和代码实现(Pytorch)

想直接看公式的可跳至第三节 3.公式修正

一、为什么需要SPP

首先需要知道为什么会需要SPP。

我们都知道卷积神经网络(CNN)由卷积层和全连接层组成,其中卷积层对于输入数据的大小并没有要求,唯一对数据大小有要求的则是第一个全连接层,因此基本上所有的CNN都要求输入数据固定大小,例如著名的VGG模型则要求输入数据大小是 (224*224)

固定输入数据大小有两个问题:

1.很多场景所得到数据并不是固定大小的,例如街景文字基本上其高宽比是不固定的,如下图示红色框出的文字。

2.可能你会说可以对图片进行切割,但是切割的话很可能会丢失到重要信息。

综上,SPP的提出就是为了解决CNN输入图像大小必须固定的问题,从而可以使得输入图像高宽比和大小任意。

二、SPP原理

更加具体的原理可查阅原论文:Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition

上图是原文中给出的示意图,需要从下往上看:

  • 首先是输入层(input image),其大小可以是任意的
  • 进行卷积运算,到最后一个卷积层(图中是\(conv_5\))输出得到该层的特征映射(feature maps),其大小也是任意的
  • 下面进入SPP层
    • 我们先看最左边有16个蓝色小格子的图,它的意思是将从\(conv_5\)得到的特征映射分成16份,另外16X256中的256表示的是channel,即SPP对每一层都分成16份(不一定是等比分,原因看后面的内容就能理解了)。
    • 中间的4个绿色小格子和右边1个紫色大格子也同理,即将特征映射分别分成4X2561X256

那么将特征映射分成若干等分是做什么用的呢? 我们看SPP的名字就是到了,是做池化操作,一般选择MAX Pooling,即对每一份进行最大池化。

我们看上图,通过SPP层,特征映射被转化成了16X256+4X256+1X256 = 21X256的矩阵,在送入全连接时可以扩展成一维矩阵,即1X10752,所以第一个全连接层的参数就可以设置成10752了,这样也就解决了输入数据大小任意的问题了。

注意上面划分成多少份是可以自己是情况设置的,例如我们也可以设置成3X3等,但一般建议还是按照论文中说的的进行划分。

三、SPP公式

理论应该理解了,那么如何实现呢?下面将介绍论文中给出的计算公式,但是在这之前先要介绍两种计算符号以及池化后矩阵大小的计算公式:

1.预先知识

取整符号:

  • ??:向下取整符号 ?59/60?=0,有时也用 floor() 表示
  • ??:向上取整符号 ?59/60?=1, 有时也用ceil() 表示

池化后矩阵大小计算公式:

  • 没有步长(Stride):\((h+2p-f+1)*(w+2p-f+1)\)
  • 有步长(Stride):?\(\frac{h+2p-f}{s}\)+1?*?\(\frac{w+2p-f}{s}\)+1?

2.公式

假设

  • 输入数据大小是\((c, h_{in}, w_{in})\),分别表示通道数,高度,宽度
  • 池化数量:\((n,n)\)

那么则有

  • 核(Kernel)大小: \(?\frac{h_{in}}{n},\frac{w_{in}}{n}?=ceil(\frac{h_{in}}{n},\frac{w_{in}}{n})\)
  • 步长(Stride)大小: \(?\frac{h_{in}}{n},\frac{w_{in}}{n}?=floor(\frac{h_{in}}{n},\frac{w_{in}}{n})\)

我们可以验证一下,假设输入数据大小是\((10, 7, 11)\), 池化数量\((2, 2)\):

那么核大小为\((4,6)\), 步长大小为\((3,5)\), 得到池化后的矩阵大小的确是\(2*2\)。

3.公式修正

是的,论文中给出的公式的确有些疏漏,我们还是以举例子的方式来说明

假设输入数据大小和上面一样是\((10, 7, 11)\), 但是池化数量改为\((4,4)\):

此时核大小为\((2,3)\), 步长大小为\((1,2)\),得到池化后的矩阵大小的确是\(6*5\) ←[简单的计算矩阵大小的方法:(7=2+1*5, 11=3+2*4)],而不是\(4*4\)。

那么问题出在哪呢?

我们忽略了padding的存在(我在原论文中没有看到关于padding的计算公式,如果有的话。。。那就是我看走眼了,麻烦提示我一下在哪个位置写过,谢谢)。

仔细看前面的计算公式我们很容易发现并没有给出padding的公式,在经过N次使用SPP计算得到的结果与预期不一样以及查找各种网上资料(尽管少得可怜)后,现将加入padding后的计算公式总结如下。

\(K_h = ?\frac{h_{in}}{n}?=ceil(\frac{h_{in}}{n})\)
\(S_h = ?\frac{h_{in}}{n}?=ceil(\frac{h_{in}}{n})\)
\(p_h = ?\frac{k_h*n-h_{in}+1}{2}?=floor(\frac{k_h*n-h_{in}+1}{2})\)
\(h_{new} = 2*p_h +h_{in}\)

\(K_w = ?\frac{w_{in}}{n}?=ceil(\frac{w_{in}}{n})\)
\(S_w = ?\frac{w_{in}}{n}?=ceil(\frac{w_{in}}{n})\)
\(p_w = ?\frac{k_w*n-w_{in}+1}{2}?=floor(\frac{k_w*n-w_{in}+1}{2})\)
\(w_{new} = 2*p_w +w_{in}\)

  • \(k_h\): 表示核的高度
  • \(S_h\): 表示高度方向的步长
  • \(p_h\): 表示高度方向的填充数量,需要乘以2

注意核和步长的计算公式都使用的是ceil(),即向上取整,而padding使用的是floor(),即向下取整

现在再来检验一下:
假设输入数据大小和上面一样是\((10, 7, 11)\), 池化数量为\((4,4)\):

Kernel大小为\((2,3)\),Stride大小为\((2,3)\),所以Padding为\((1,1)\)。

利用矩阵大小计算公式:?\(\frac{h+2p-f}{s}\)+1?*?\(\frac{w+2p-f}{s}\)+1?得到池化后的矩阵大小为:\(4*4\)。

四、代码实现(Python)

这里我使用的是PyTorch深度学习框架,构建了一个SPP层,代码如下:

#coding=utf-8

import math
import torch
import torch.nn.functional as F

# 构建SPP层(空间金字塔池化层)
class SPPLayer(torch.nn.Module):

    def __init__(self, num_levels, pool_type='max_pool'):
        super(SPPLayer, self).__init__()

        self.num_levels = num_levels
        self.pool_type = pool_type

    def forward(self, x):
        num, c, h, w = x.size() # num:样本数量 c:通道数 h:高 w:宽
        for i in range(self.num_levels):
            level = i+1
            kernel_size = (math.ceil(h / level), math.ceil(w / level))
            stride = (math.ceil(h / level), math.ceil(w / level))
            pooling = (math.floor((kernel_size[0]*level-h+1)/2), math.floor((kernel_size[1]*level-w+1)/2))

            # 选择池化方式
            if self.pool_type == 'max_pool':
                tensor = F.max_pool2d(x, kernel_size=kernel_size, stride=stride, padding=pooling).view(num, -1)
            else:
                tensor = F.avg_pool2d(x, kernel_size=kernel_size, stride=stride, padding=pooling).view(num, -1)

            # 展开、拼接
            if (i == 0):
                x_flatten = tensor.view(num, -1)
            else:
                x_flatten = torch.cat((x_flatten, tensor.view(num, -1)), 1)
        return x_flatten

上述代码参考: sppnet-pytorch

为防止原作者将代码删除,我已经Fork了,也可以通过如下地址访问代码:
marsggbo/sppnet-pytorch

MARSGGBO?原创


2018-3-15


原文地址:https://www.cnblogs.com/marsggbo/p/8572846.html

时间: 2024-10-14 00:58:25

空间金字塔池化(Spatial Pyramid Pooling, SPP)原理和代码实现(Pytorch)的相关文章

SPPNet论文翻译-空间金字塔池化Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition

http://www.dengfanxin.cn/?p=403 原文地址 我对物体检测的一篇重要著作SPPNet的论文的主要部分进行了翻译工作.SPPNet的初衷非常明晰,就是希望网络对输入的尺寸更加灵活,分析到卷积网络对尺寸并没有要求,固定尺寸的要求完全来源于全连接层部分,因而借助空间金字塔池化的方法来衔接两者,SPPNet在检测领域的重要贡献是避免了R-CNN的变形.重复计算等问题,在效果不衰减的情况下,大幅提高了识别速度. 用于视觉识别的深度卷积网络空间金字塔池化方法 Spatial Py

Spatial pyramid pooling (SPP)-net (空间金字塔池化)笔记(转)

在学习r-cnn系列时,一直看到SPP-net的身影,许多有疑问的地方在这篇论文里找到了答案. 论文:Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition 转自:http://blog.csdn.net/xzzppp/article/details/51377731 另可参考:http://zhangliliang.com/2014/09/13/paper-note-sppnet/ http:/

空间金字塔池化(Spatial Pyramid Pooling,SPP)

基于空间金字塔池化的卷积神经网络物体检测 原文地址:http://blog.csdn.net/hjimce/article/details/50187655 作者:hjimce 一.相关理论 本篇博文主要讲解大神何凯明2014年的paper:<Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition>,这篇paper主要的创新点在于提出了空间金字塔池化.paper主页:http://researc

目标检测论文解读2——Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition

背景 用ConvNet方法解决图像分类.检测问题成为热潮,但这些方法都需要先把图片resize到固定的w*h,再丢进网络里,图片经过resize可能会丢失一些信息.论文作者发明了SPP pooling(空间金字塔池化)层,让网络可以接受任意size的输入. 方法 首先思考一个问题,为什么ConvNet需要一个固定size的图片作为输入,我们知道,Conv层只需要channel固定(彩色图片3,灰度图1),但可以接受任意w*h的输入,当然输出的w*h也会跟着变化:然而,后面的FC层却需要固定长度的

SPP(Spatial Pyramid Pooling)详解

一直对Fast RCNN中ROI Pooling层不解,不同大小的窗口输入怎么样才能得到同样大小的窗口输出呢,今天看到一篇博文讲得挺好的,摘录一下,方便查找. Introduction 在一般的CNN结构中,在卷积层后面通常连接着全连接.而全连接层的特征数是固定的,所以在网络输入的时候,会固定输入的大小(fixed-size).但在现实中,我们的输入的图像尺寸总是不能满足输入时要求的大小.然而通常的手法就是裁剪(crop)和拉伸(warp). 这样做总是不好的:图像的纵横比(ratio aspe

Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition

一.本文的主要思想 考虑到传统的CNN构架的输入图像的尺寸都是固定的(例如:256*256),这种人工改变输入图像的尺寸破坏了输入图像的尺度和长宽比例.作者认为卷积层的输入的尺寸可以是任意,全连接层的输入是固定不变.针对这个问题,作者提出了spatial pyramid pooling(SPP-net)结构,在目标检测方面,比R-CNN快30-170倍. 二.spatial pyramid pooling(SPP-net)的优势 1.针对不同尺寸的输入可以得到相同维度的输出,而siding wi

Tensorflow 池化层(pooling)和全连接层(dense)

一.池化层(pooling) 池化层定义在 tensorflow/python/layers/pooling.py. 有最大值池化和均值池化. 1. 最大池化层 tf.layers.max_pooling2d max_pooling2d( inputs, pool_size, strides, padding='valid', data_format='channels_last', name=None ) inputs: 进行池化的数据.pool_size: 池化的核大小(pool_heigh

SPP Net(Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition)论文理解

论文地址:https://arxiv.org/pdf/1406.4729.pdf 论文翻译请移步:http://www.dengfanxin.cn/?p=403 一.背景: 传统的CNN要求输入图像尺寸是固定的(因为全连接网络要求输入大小是固定的) crop处理,可能不包含整个物体,还会丢失上下文信息 warping处理,会导致图像变形 以上都会导致CNN对不同scale/size泛化能力不强 于是SPP做了如下改进,即将SPP层加在最后一个卷积层后面,然后再送入FC网络. 优点 不管输入尺寸为

池化层的作用和种类

原连接:https://blog.csdn.net/XX_123_1_RJ/article/details/86677482 池化的原理或者是过程:pooling是在不同的通道上分开执行的(就是池化操作不改变通道数),且不需要参数控制.然后根据窗口大小进行相应的操作.一般有max pooling.average pooling等. 一. 池化层主要的作用 首要作用,下采样(downsamping) 降维.去除冗余信息.对特征进行压缩.简化网络复杂度.减少计算量.减少内存消耗等等.各种说辞吧,总的