池化常在卷积神经网络中使用,可以调节数据维数,抑制噪声、降低信息冗余、降低模型计算量、防止过拟合等作用。池化没有可学习的参数,与激活函数较为相似,池化在一维或多维张量上的操作与卷积层也有相似之处。
池化最初作用是降低数据量,使模型更容易训练,称为下采样(down-sampling)或下池化。后来池化也可以增加数据大小,此时为上采样(up-smapling)或上池化。
根据被池化的张量维数的不同,可分为一维池化、二维池化与三维池化。池化有固定的窗口,可以称为池化窗口,类似与卷积中的卷积核。需要池化窗口kernel size、步长stride、填充padding、dilation这几个参数。池化窗口表示选取的数据范围,步长表示池化窗口每次沿某个方向的长度,padding表示对input池化前是否在周围补充0,dilation为膨胀率。
最大池化
每次选取移动框内数的最大值,分为一维、二维和三维张量数据的池化。
如TextCNN中卷积后的一维最大池化,每个卷积核的输出大小根据句长,步长,padding等计算获得,一维最大池化的 kernel_size 即为该值。
import torch from torch import nn input=torch.randint(0, 2, size=(2,2,5),dtype=torch.float32) maxpool1d=nn.MaxPool1d(kernel_size=3, stride=1, padding=0, dilation=1) output=maxpool1d(input) print(input,output)
二维数据与三维数据的最大池化,与一维情况相同,但池化窗口为2维张量或三维张量,移动步长也分为两个或三个方向,kernel_size,stride 可为元组值,如果只有一个int值则为square的。
平均池化
前面最大池化所有的参数与意义完全相同,分为1d、2d、3d池化,输出是池化窗口所有数的平均值,而不是最大值;nn.AvgPool2d(kernel_size=(3,3),stride=(2,1),padding=0)。
LP池化
受视觉皮层内阶层结构启发建立的池化模型。输出为池化窗口内每个数的 p 次方后求和再求均值,最后均值的1/p次方即为该部分窗口的输出结果。该函数需要参数 norm_type 指定 p 值,如果 p 为1,即与均值池化相同;如果p为无穷,则与最大池化相同。Pytorch中 LP 池化只有一维与二维两种;nn.LPPool2d(kernel_size=(2,2),stride=1,norm_type=1.5)。
自适应池化
最终输出的size始终是函数指定的size,原理是:该函数可以根据输入size与我们指定的输出size来自动调整池化窗口、步长等参数,该函数没有kernel_size,stride,padding等参数,只需要指定输出size大小即可。如果需要让某一维度为原来大小,可以直接指定该部分参数为None;nn.AdaptiveMaxPool2d((None,2))。
随机池化
Stochastic Pooling,自定义的一种池化方式,每次以一定的概率来选取池化窗口的值,窗口中的值越大,被选中作为输出的概率越大。需要用窗口中每一个数除以窗口中所有数的和,此时每个位置的值即为该位置被选中输出的概率。
import torch from torch import nn import numpy as np class StochasticPool2d(nn.Module): def __init__(self, kernel_size, stride): super().__init__() self.kernel_size = kernel_size self.stride = stride def forward(self, input): b, c, h, w = input.shape output = [] for B in range(b): batch = [] for C in range(c): channel = [] for i in range(0, h - self.kernel_size[0] + 1, self.stride[0]): l = [] for j in range(0, w - self.kernel_size[1] + 1, self.stride[1]): kernel = input[B, C, i:i + self.kernel_size[0], j:j + self.kernel_size[1]] num = kernel.detach().numpy().reshape((1, -1))[0] pro = (kernel / kernel.sum()).detach().numpy() pro = pro.reshape((1, -1))[0] out = np.random.choice(a=num, p=pro, replace=True) l.append(out) channel.append(l) batch.append(channel) output.append(batch) return torch.tensor(output, dtype=torch.float32) if __name__ == '__main__': input = torch.randint(0, 2, size=(1, 1, 5, 5)) pool = StochasticPool2d(kernel_size=(3, 3), stride=(1, 1)) print(pool(input))
参考: