SPP - 空间金字塔池化

1 原理

  何恺明2015年于《Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition》中提出。SPP 在论文中的主要工作是解决 CNN 要求输入图片尺寸固定的问题。(其它解决方案有用 Conv 层替代 FC 层)

   如上图所示,输入层 input image 大小任意,通过 conv5 的卷积得到任意大小的输出特征映射 feature maps,而后送入 SPP 层。图中蓝、绿、灰三色格子分别代表将 feature maps 分成 16、4 和 1份(不一定是等分)。设定输出通道数为 256,对分割后的每一份进行池化操作,则通过 SPP 层可将 feature maps 转化成 16 × 256 + 4 × 256 + 1 × 256 = 21 × 256 16 \times 256 + 4 \times 256 + 1 \times 256 = 21 \times 256 16×256+4×256+1×256=21×256 的矩阵,在送入 FC 层时扩展成一维矩阵( 1 × 10752 1 \times 10752 1×10752),因此该 FC 层的参数就可以设置为 10752,如此便无需要求输入图片尺寸大小固定。

2 计算

  SPP 层输出运算。设核的高度为 K h K_h Kh,高度方向的步长为 S h S_h Sh,高度方向的填充数量为 P h P_h Ph(需要乘以 2),则相关公式如下:
K h = ⌈ h i n n ⌉ S h = ⌈ h i n n ⌉ P h = ⌊ K h ∗ n − h i n + 1 2 ⌋ h n e w = 2 ∗ P h + h i n K_h = \lceil \frac{h_{in}}{n} \rceil \\ S_h = \lceil \frac{h_{in}}{n} \rceil \\ P_h = \lfloor \frac{K_h * n - h_{in} + 1}{2} \rfloor \\ h_{new} = 2*P_h + h_{in} Kh=nhinSh=nhinPh=2Khnhin+1hnew=2Ph+hin
K w = ⌈ w i n n ⌉ S w = ⌈ w i n n ⌉ P w = ⌊ K w ∗ n − w i n + 1 2 ⌋ w n e w = 2 ∗ P w + w i n K_w = \lceil \frac{w_{in}}{n} \rceil \\ S_w = \lceil \frac{w_{in}}{n} \rceil \\ P_w = \lfloor \frac{K_w * n - w_{in} + 1}{2} \rfloor \\ w_{new} = 2*P_w + w_{in} Kw=nwinSw=nwinPw=2Kwnwin+1wnew=2Pw+win
池化后矩阵大小计算公式为:

  • 没有步长: ( h + 2 p − f + 1 ) ∗ ( w + 2 p − f + 1 ) (h+2p−f+1)∗(w+2p−f+1) (h+2pf+1)(w+2pf+1)
  • 有步长:
    ⌊ h + 2 p − f s + 1 ⌋ ∗ ⌊ w + 2 p − f s + 1 ⌋ ⌊h+2p−fs+1⌋*⌊w+2p−fs+1⌋ h+2pfs+1w+2pfs+1

  对上述公式进行检验。设输入数据为 (10, 7, 11),池化数量为 (4, 4),Kernel 大小为 (2, 3),Stride 大小为(2, 3),则 Padding 为 (1, 1)。利用上述公式计算得到池化后的矩阵大小为:4 ∗ 4。

3 代码

  使用 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

参考

  1. SPP,PPM、ASPP和FPN结构理解和总结
  2. 空间金字塔池化(Spatial Pyramid Pooling, SPP)原理和代码实现(Pytorch)
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值