• 池化(Pooling)的种类与具体用法——基于Pytorch


      池化操作通常在卷积神经网络中使用,并且与卷积操作配合使用,可以起到调节数据维数,并且具有抑制噪声、降低信息冗余、降低模型计算量、防止过拟合等作用。池化没有可以学习的参数,所以某种程度上与激活函数较为相似,池化在一维或多维张量上的操作与卷积层也有很多相似之处。

    一:.基本原理

      池化操作最初是用来减小数据大小,使模型更容易训练,这个过程即为下采样(downsampling),这里可以称为下池化。随着之后的发展,池化也可以增加数据大小,此时的池化操作为上采样(upsmapling)或上池化。

      数据的池化,根据被池化的张量维数的不同,一般可分为一维池化、二维池化与三维池化。池化操作都有一个固定的窗口,可以称为池化窗口,类似与卷积操作中的卷积核。

     对于池化,大多数都需要池化窗口kernel size、步长stride、填充padding、dilation这几个参数。池化窗口表示选取的数据范围,步长表示池化窗口每次沿某个方向的长度,padding表示对input池化前是否在周围补充0,dilation为膨胀率。  

     对于上图,红框即为池化窗口。

      对于上图,padding=1,stride=(1,1),kernel_size=(2,2),dilation=2。

    (注:在Pytorch中,padding大小不能超过池化窗口的一半,否则报错)

    二:下池化

    1.最大池化:MaxPool

    最大池化,即每次选取移动框内数的最大值。它可以分为一维、二维和三维张量数据的池化。

            1.1一维数据最大池化

     上图显示的便是kernel_size=3,stride=1,padding=0的一维最大池化。

    1. import torch
    2. from torch import nn
    3. input=torch.randint(0,2,size=(2,2,5),dtype=torch.float32)
    4. maxpool1d=nn.MaxPool1d(kernel_size=3,stride=1,padding=0,dilation=1)
    5. output=maxpool1d(input)
    6. print(input,output)

            1.2二维数据与三维数据最大池化

     对于二维数据与三维数据的最大池化,与一维情况基本相同。只不过此时的池化窗口为2维张量或三维张量。移动步长也分为两个或三个方向。

     上图显示的是一个kernel_size为(3,3),stride=(1,1),padding=0的二维最大池化。

    2.平均池化:AvgPool

     平均池化与前面最大池化所有的参数与意义完全相同,并且也分为1d、2d、3d池化。只不过它的输出是池化窗口所有数的平均值,而不是最大值。

    1. import torch
    2. from torch import nn
    3. input=torch.randint(0,2,size=(2,2,5,4),dtype=torch.float32)
    4. avgpool2d=nn.AvgPool2d(kernel_size=(3,3),stride=(2,1),padding=0)
    5. output=avgpool2d(input)
    6. print(input,output)

    3.LP池化:LPPool

     LP池化是一类受视觉皮层内阶层结构启发建立的池化模型。它的输出为池化窗口内每个数的p次方后求和再求均值,最后均值的1/p次方即为该部分窗口的输出结果。所以该函数需要参数norm_type,来指定p值,如果p为1,即与均值池化相同;如果p为无穷,则与最大池化相同。

    (注:该函数没有参数padding与dilation)

     在Pytorch中,LP池化只有一维与二维两种。

    1. import torch
    2. from torch import nn
    3. input=torch.randint(0,2,size=(2,2,5,4),dtype=torch.float32)
    4. lppool2d=nn.LPPool2d(kernel_size=(2,2),stride=1,norm_type=1.5)
    5. output=lppool2d(input)
    6. print(input,output)

    4.自适应最大/平均池化:AdaptiveMaxPool与AdaptiveAvgPool

     自适应池化的特点是:无论输入数据的size是多少,最终输出的size始终是函数指定的size。而背后的原理是:该函数可以根据输入size与我们指定的输出size来自动调整池化窗口、步长等参数。所以该函数没有kernel_size,stride,padding等参数,只需要指定输出size大小即可。如果需要让某一维度为原来大小,可以直接指定该部分参数为None。

    1. import torch
    2. from torch import nn
    3. input=torch.randint(0,2,size=(2,2,5,4),dtype=torch.float32)
    4. adaptivemaxpool2d=nn.AdaptiveMaxPool2d((None,2))
    5. output=adaptivemaxpool2d(input)

    5.分数阶最大池化:FractionalMaxPool

     关于分数阶最大池化,兔兔发现它似乎并没有太多的实际用处。函数中仍需要kernel_size,如果指定output_size,它就可以输出指定大小的张量,类似于自适应最大池化;如果指定output_ratio,它就会根据输出大小与输入大小的比例output_ratio来决定输出大小,所以output_ratio为0~1。并且函数不能同时接受output_ratio与output_size,毕竟这两个参数都决定输出大小,同时使用势必会引起冲突。

    1. input=torch.randint(0,20,size=(1,1,5,5),dtype=torch.float32)
    2. pool=nn.FractionalMaxPool2d(kernel_size=(3,3),output_ratio=0.7)
    3. out=pool(input)
    4. print(out)

    三:上池化

    1.反最大池化 :MaxUnpool

    反池化与前面的池化基本相同,参数一般仍然需要kernel_size,stride,padding等。对于反最大池化,我们还需要提供参数indices。indices表示下池化过程中池化窗口返回那个最大值的位置索引。事实上,在前面的最大池化中,参数return_indices即表示是否返回索引,只不过该函数默认为False。

    1. input=torch.randint(0,2,size=(1,1,5,5),dtype=torch.float32)
    2. pool=nn.MaxPool2d(kernel_size=3,stride=1,padding=0,return_indices=True)
    3. out=pool(input)
    4. print(input)
    5. print(out[0]) #池化后结果
    6. print(out[1]) #池化indice

     那么,现在对于反最大池化就比较好理解了,这个函数根据传入的参数indices,来使得上池化后该位置索引为池化窗口最大值,其余都为0。这里需要注意的是,indices不能传给nn.MaxUnpool,而是传给它的forward()函数中。

    1. input=torch.randint(0,2,size=(1,1,5,5),dtype=torch.float32)
    2. pool=nn.MaxPool2d(kernel_size=3,stride=1,padding=0,return_indices=True)
    3. out,indices=pool(input)
    4. unpool=nn.MaxUnpool2d(kernel_size=3,stride=1,padding=0)
    5. out=unpool(out,indices=indices)
    6. print(out)

    四:其它

     对于前面的讲到的池化,实际的池化种类远远不止这些,但Pytorch中也并未提供其它种类的池化方法,所以此时需要我们能够根据池化原理来设计池化层。兔兔在这里以一种随机池化为例,来实现该方法。

     随机池化(Stochastic Pooling)是每次以一定的概率来选取池化窗口的值,并且窗口中的值越大,被选中作为输出的概率越大。所以需要用窗口中每一个数除以窗口中所有数的和,此时每个位置的值即为该位置被选中输出的概率。

    1. import torch
    2. from torch import nn
    3. import numpy as np
    4. class stochasticPool2d(nn.Module):
    5. def __init__(self,kernel_size,stride):
    6. super().__init__()
    7. self.kernel_size=kernel_size
    8. self.stride=stride
    9. def forward(self,input):
    10. b,c,h,w=input.shape
    11. output=[]
    12. for B in range(b):
    13. batch=[]
    14. for C in range(c):
    15. channel=[]
    16. for i in range(0,h-self.kernel_size[0]+1,self.stride[0]):
    17. l=[]
    18. for j in range(0,w-self.kernel_size[1]+1,self.stride[1]):
    19. kernel=input[B,C,i:i+self.kernel_size[0],j:j+self.kernel_size[1]]
    20. num=kernel.detach().numpy().reshape((1,-1))[0]
    21. pro=(kernel/kernel.sum()).detach().numpy()
    22. pro=pro.reshape((1,-1))[0]
    23. out=np.random.choice(a=num,p=pro,replace=True)
    24. l.append(out)
    25. channel.append(l)
    26. batch.append(channel)
    27. output.append(batch)
    28. return torch.tensor(output,dtype=torch.float32)
    29. if __name__=='__main__':
    30. input=torch.randint(0,2,size=(1,1,5,5))
    31. pool=stochasticPool2d(kernel_size=(3,3),stride=(1,1))
    32. print(pool(input))

    四:总结

     池化作为深度学习中常用的一种方法,具有对于模型的优化具有重要意义。事实上,池化的种类是非常多的,但是在Pytorch中并未提供所有的方法。一方面我们可以根据Pytorch中已有的池化方法,调整其中的参数来实现我们想要的池化方法;另一方面,我们也应该学会在已有方案都无法实行的情况下,能够自己方法原理设计池化层。

  • 相关阅读:
    更改文本文件分隔符
    Linux nl 命令使用介绍
    【LeetCode】Day132-单词搜索
    Qt mysql客户端,测试
    基于PHP+MySQL的校园二手旧书回收捐赠系统
    健康打卡每日提醒累了?那就让自动化帮你---HiFlow,应用连接自动化助手
    ASP.NET Core Web API下基于Keycloak的多租户用户授权的实现
    2023年09月 Scratch(二级)真题解析#中国电子学会#全国青少年软件编程等级考试
    面试题之HashMap与HashTable的区别
    C Primer Plus(6) 中文版 第14章 结构和其他数据形式 14.3 定义结构变量
  • 原文地址:https://blog.csdn.net/weixin_60737527/article/details/127024456