空间金字塔池化(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个紫色大格子也同理,即将特征映射分别分成4X256和1X256份
那么将特征映射分成若干等分是做什么用的呢? 我们看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
空间金字塔池化(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-引入空间金字塔池化改进RCNN
转自: https://zhuanlan.zhihu.com/p/24774302?refer=xiaoleimlnote 继续总结一下RCNN系列.上篇RCNN- 将CNN引入目标检测的开山之作 介 ...
- Spatial pyramid pooling (SPP)-net (空间金字塔池化)笔记(转)
在学习r-cnn系列时,一直看到SPP-net的身影,许多有疑问的地方在这篇论文里找到了答案. 论文:Spatial Pyramid Pooling in Deep Convolutional Net ...
- 空间金字塔池化(Spatial Pyramid Pooling,SPP)
基于空间金字塔池化的卷积神经网络物体检测 原文地址:http://blog.csdn.net/hjimce/article/details/50187655 作者:hjimce 一.相关理论 本篇博文 ...
- SPP空间金字塔池化技术的直观理解
空间金字塔池化技术, 厉害之处,在于使得我们构建的网络,可以输入任意大小的图片,不需要经过裁剪缩放等操作. 是后续许多金字塔技术(psp,aspp等)的起源,主要的目的都是为了获取场景语境信息,获取上 ...
- 空间金字塔池化 ssp-net
<Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition>,这篇paper提出了空间金字 ...
- 深度学习论文翻译解析(九):Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition
论文标题:Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition 标题翻译:用于视觉识别的深度卷积神 ...
- 论文阅读笔记二十五:Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition(SPPNet CVPR2014)
论文源址:https://arxiv.org/abs/1406.4729 tensorflow相关代码:https://github.com/peace195/sppnet 摘要 深度卷积网络需要输入 ...
- 论文解读2——Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition
背景 用ConvNet方法解决图像分类.检测问题成为热潮,但这些方法都需要先把图片resize到固定的w*h,再丢进网络里,图片经过resize可能会丢失一些信息.论文作者发明了SPP pooling ...
随机推荐
- ps调整文字平滑
1. 选中文字 2. 调整字体样式,选择"平滑"
- 【学习笔记】Hibernate关联映射(Y2-1-6)
Hibernate关联映射 关联映射就是将关联关系映射到数据库里,在对象模型中就是一个或多个引用. 1.单向多对一关联 准备数据库 部门表和员工表 其中部门表有两列 部门编号和名称 员工表有三列 员工 ...
- 移动端页面点击a标签会有半透明的阴影或红色边框的bug
好久没有更新了,今天来一发 ^_^ 最近在写移动端页面,测试时发现一个a标签的bug:无论是iOS端还是Android端都存在,当点击a标签,会有一个矩形的透明的阴影闪一下(不同的浏览器阴影的颜色还不 ...
- Sphinx下载、安装、配置、Hello World、文档阅读
sphinx下载.安装.配置.Hello World.查看文档
- python+flask:实现POST接口功能
1.首先需要安装python和flask,这个是必须的嘛. 2.我们这里实现的是一个POST功能的简单接口. from flask import Flask, request, jsonify imp ...
- LOJ6277~6285 数列分块入门
Portals 分块需注意的问题 数组大小应为,因为最后一个块可能会超出的范围. 当操作的区间在一个块内时,要特判成暴力修改. 要清楚什么时候应该+tag[t] 数列分块入门 1 给出一个长为的数列, ...
- CentOS7网卡命名规则
CentOS6之前基于传统的命名方式如:eth1,eth0.... Centos7提供了不同的命名规则,默认是基于固件.拓扑.位置信息来分配.这样做的优点是命名是全自动的.可预知的,缺点是比eth0. ...
- select, poll, epoll的实现分析
select, poll, epoll都是Linux上的IO多路复用机制.知其然知其所以然,为了更好地理解其底层实现,这几天我阅读了这三个系统调用的源码. 以下源代码摘自Linux4.4.0内核. 预 ...
- R语言︱list用法、批量读取、写出数据时的用法
列表是一种特别的对象集合,它的元素也由序号(下标)区分,但是各元素的类型可 以是任意对象,不同元素不必是同一类型.元素本身允许是其它复杂数据类型,比如,列表 的一个元素也允许是列表.例如: > ...
- eclipse中添加Java代码注释模板
eclipse中添加Java代码注释模板 1.Window->Preference->Java->Code Style->Code Template,进入注释编辑界面 2.文件 ...