专栏首页深度应用[开发技巧]·AdaptivePooling与Max/AvgPooling相互转换

[开发技巧]·AdaptivePooling与Max/AvgPooling相互转换

[开发技巧]·AdaptivePooling与Max/AvgPooling相互转换

个人网站--> http://www.yansongsong.cn

1.问题描述

自适应池化Adaptive Pooling是PyTorch的一种池化层,根据1D,2D,3D以及Max与Avg可分为六种形式。

自适应池化Adaptive Pooling与标准的Max/AvgPooling区别在于,自适应池化Adaptive Pooling会根据输入的参数来控制输出output_size,而标准的Max/AvgPooling是通过kernel_size,stride与padding来计算output_size:

output_size = ceil ( (input_size+2∗padding−kernel_size)/stride)+1

Adaptive Pooling仅存在与PyTorch,如果需要将包含Adaptive Pooling的代码移植到Keras或者TensorFlow就会遇到问题。

本文将提供一个公式,可以简便的将AdaptivePooling准换为Max/AvgPooling,便于大家移植使用。

2.原理讲解

我们已经知道了普通Max/AvgPooling计算公式为:output_size = ceil ( (input_size+2∗padding−kernel_size)/stride)+1

当我们使用Adaptive Pooling时,这个问题就变成了由已知量input_size,output_size求解kernel_size与stride

为了简化问题,我们将padding设为0(后面我们可以发现源码里也是这样操作的c++源码部分

stride = floor ( (input_size / (output_size) ) kernel_size = input_size − (output_size−1) * stride padding = 0

3.实战演示

下面我们通过一个实战来操作一下,验证公式的正确性

import torch as t
import math
import numpy as np

alist = t.randn(2,6,7)

inputsz = np.array(alist.shape[1:])
outputsz = np.array([2,3])

stridesz = np.floor(inputsz/outputsz).astype(np.int32)

kernelsz = inputsz-(outputsz-1)*stridesz

adp = t.nn.AdaptiveAvgPool2d(list(outputsz))
avg = t.nn.AvgPool2d(kernel_size=list(kernelsz),stride=list(stridesz))
adplist = adp(alist)
avglist = avg(alist)

print(alist)
print(adplist)
print(avglist)

输出结果

tensor([[[ 0.9095,  0.8043,  0.4052,  0.3410,  1.8831,  0.8703, -0.0839],
         [ 0.3300, -1.2951, -1.8148, -1.1118, -1.1091,  1.5657,  0.7093],
         [-0.6788, -1.2790, -0.6456,  1.9085,  0.8627,  1.1711,  0.5614],
         [-0.0129, -0.6447, -0.6685, -1.2087,  0.8535, -1.4802,  0.5274],
         [ 0.7347,  0.0374, -1.7286, -0.7225, -0.4257, -0.0819, -0.9878],
         [-1.2553, -1.0774, -0.1936, -1.4741, -0.9028, -0.1584, -0.6612]],

        [[-0.3473,  1.0599, -1.5744, -0.2023, -0.5336,  0.5512, -0.3200],
         [-0.2518,  0.1714,  0.6862,  0.3334, -1.2693, -1.3348, -0.0878],
         [ 1.0515,  0.1385,  0.4050,  0.8554,  1.0170, -2.6985,  0.3586],
         [-0.1977,  0.8298,  1.6110, -0.9102,  0.7129,  0.2088,  0.9553],
         [-0.2218, -0.7234, -0.4407,  1.0369, -0.8884,  0.3684,  1.2134],
         [ 0.5812,  1.1974, -0.1584, -0.0903, -0.0628,  3.3684,  2.0330]]])


tensor([[[-0.3627,  0.0799,  0.7145],
         [-0.5343, -0.7190, -0.3686]],

        [[ 0.1488, -0.0314, -0.4797],
         [ 0.2753,  0.0900,  0.8788]]])

tensor([[[-0.3627,  0.0799,  0.7145],
         [-0.5343, -0.7190, -0.3686]],

        [[ 0.1488, -0.0314, -0.4797],
         [ 0.2753,  0.0900,  0.8788]]])

可以发现adp = t.nn.AdaptiveAvgPool2d(list(outputsz))与avg = t.nn.AvgPool2d(kernel_size=list(kernelsz),stride=list(stridesz))结果一致

为了防止这是偶然现象,修改参数,使用AdaptiveAvgPool1d进行试验

import torch as t
import math
import numpy as np

alist = t.randn(2,3,9)

inputsz = np.array(alist.shape[2:])
outputsz = np.array([4])

stridesz = np.floor(inputsz/outputsz).astype(np.int32)

kernelsz = inputsz-(outputsz-1)*stridesz

adp = t.nn.AdaptiveAvgPool1d(list(outputsz))
avg = t.nn.AvgPool1d(kernel_size=list(kernelsz),stride=list(stridesz))
adplist = adp(alist)
avglist = avg(alist)

print(alist)
print(adplist)
print(avglist)

输出结果

tensor([[[ 1.3405,  0.3509, -1.5119, -0.1730,  0.6971,  0.3399, -0.0874,
          -1.2417,  0.6564],
         [ 2.0482,  0.3528,  0.0703,  1.2012, -0.8829, -0.3156,  1.0603,
          -0.7722, -0.6086],
         [ 1.0470, -0.9374,  0.3594, -0.8068,  0.5126,  1.4135,  0.3538,
          -1.0973,  0.3046]],

        [[-0.1688,  0.7300, -0.3457,  0.5645, -1.2507, -1.9724,  0.4469,
          -0.3362,  0.7910],
         [ 0.5676, -0.0614, -0.0243,  0.1529,  0.8276,  0.2452, -0.1783,
           0.7460,  0.2577],
         [-0.1433, -0.7047, -0.4883,  1.2414, -1.4316,  0.9704, -1.7088,
          -0.0094, -0.3739]]])


tensor([[[ 0.0598, -0.3293,  0.3165, -0.2242],
         [ 0.8237,  0.1295, -0.0461, -0.1069],
         [ 0.1563,  0.0217,  0.7600, -0.1463]],

        [[ 0.0718, -0.3440, -0.9254,  0.3006],
         [ 0.1606,  0.3187,  0.2982,  0.2751],
         [-0.4454, -0.2262, -0.7233, -0.6973]]])

tensor([[[ 0.0598, -0.3293,  0.3165, -0.2242],
         [ 0.8237,  0.1295, -0.0461, -0.1069],
         [ 0.1563,  0.0217,  0.7600, -0.1463]],

        [[ 0.0718, -0.3440, -0.9254,  0.3006],
         [ 0.1606,  0.3187,  0.2982,  0.2751],
         [-0.4454, -0.2262, -0.7233, -0.6973]]])

可以发现adp = t.nn.AdaptiveAvgPool1d(list(outputsz))与avg = t.nn.AvgPool1d(kernel_size=list(kernelsz),stride=list(stridesz))结果也是相同的。

4.总结分析

在以后遇到别人代码使用Adaptive Pooling,可以通过这两个公式转换为标准的Max/AvgPooling,从而应用到不同的学习框架中

stride = floor ( (input_size / (output_size) ) kernel_size = input_size − (output_size−1) * stride padding = 0

只需要知道输入的input_size ,就可以推导出stride 与kernel_size ,从而替换为标准的Max/AvgPooling

Hope this helps

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [python3 OpenCV3使用技巧]使用numpy矩阵实现RGB转HSI

    看到网上有很多博客都是通过循环遍历的方式来进行RGB转HSI操作,但是我们知道在python中使用Numpy数组并行操作可以更加简洁,速度也更快。

    小宋是呢
  • [Keras实用技巧]·错误Sequential has no attribution “validation_data”解决

    错误描述:Sequential has no attribution “validation_data”

    小宋是呢
  • [TensorFlow深度学习入门]实战十一·用双向BiRNN(LSTM)做手写数字识别准确率99%+

    此博文是我们在完成实战五·用RNN(LSTM)做手写数字识别的基础上使用BiRNN(LSTM)结构,进一步提升模型的准确率,1000steps准确率达到99%。

    小宋是呢
  • C语言中size_t和size_type 的区别

    1)size_tsize_t是用于数组的下标值类型,也可以用来“接收”sizeof操作符的返回值。

    ccf19881030
  • 短视频商城源码,制作彩色验证码

    yunbaokeji柯基
  • 55. 比较字符串

    比较两个字符串A和B,确定A中是否包含B中所有的字符。字符串A和B中的字符都是 大写字母 样例 给出 A = "ABCD" B = "ACD",返回 tru...

    和蔼的zhxing
  • 递归与分治之棋盘覆盖问题

    在一个2^k * 2^k个方格组成的棋盘中,若有一个方格与其他方格不同,则称该方格为一特殊方格,且称该棋盘为一个特殊棋盘。 显然特殊方格在棋盘上出现的位置有4^...

    欠扁的小篮子
  • C 库函数 - fread()

    C 库函数 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 从给定流 stre...

    心跳包
  • pytorch之Resize()函数具体使用详解

    CLASS torchvision.transforms.Resize(size, interpolation=2)

    砸漏
  • 880.Decoded String at Index

    思路 用size表示在i处,字符串进行解码后的长度。 如果有一个解码后的字符串为appleappleappleappleappleapple,且K=24,那...

    平凡的学生族

扫码关注云+社区

领取腾讯云代金券