池化操作的一个重要目的就是对卷积后得到的特征进行进一步处理(主要是降维),从而缓解计算时内存的压力。池化会选取一定大小的区域,将该区域内的像素值使用一个代表元素表示。如果使用平均值代替,称为平均值池化,如果使用最大值代替则称为最大值池化。这两种池化方式示意图如下图1所示。
在PyTorch中,提供了多种池化的类,分别是最大值池化(MaxPool)、最大值池化的逆过程(MaxUnPool)、平均值池化(AvgPool)、自适应池化(AdaptiveMaxPool,AdaptiveAvgPool) 等。并且均提供了一维、二维和三维的池化操作。
PyTorch中常用的池化操作有torch.nn.MaxPool1d()
、torch.nn.MaxPool2d()
、torch.nn.MaxPool3d()
、torch.nn.MaxUnPool1d()
、torch.nn.MaxUnPool2d()
、torch.nn.MaxUnPool3d()
、torch.nn.AvgPool1d()
、torch.nn.AvgPool2d()
、torch.nn.AvgPool3d()
、torch.nn.AdaptiveMaxPool1d()
、torch.nn.AdaptiveMaxPool2d()
、torch.nn.AdaptiveMaxPool3d()
、torch.nn.AdaptiveAvgPool1d()
、torch.nn.AdaptiveAvgPool2d()
、torch.nn.AdaptiveAvgPool3d()
。
以torch.nn.MaxPool2d()
池化操作相关参数的应用为例,其使用方法如下:
torch.nn.MaxPool2d(kernel_size,
stride=None,
padding=0,
dilation=1,
return_indices=False,
ceil_mode=False)
池化参数 | 说明 |
---|---|
kernel_size | 最大池化的窗口大小(整数或数组) |
stride | 最大池化窗口移动的步长,默认值是kernel_size(整数或数组,正数) |
padding | 输入的每一条边补充0的层数(整数或数组,正数) |
dilation | 一个控制窗口中元素步幅的参数(整数或者数组,正数),默认为1 |
return_indices | 如果为True,则返回输出最大值的索引,便于之后的torch.nn.MaxPool2d 操作 |
ceil_mode | 如果为True,计算输出信号大小时,会使用向上取整,默认是向下取整 |
torch.nn.MaxPool2d()
输入的张量为 ( N , C i n , H i n , W i n ) (N,C_{in},H_{in},W_{in}) (N,Cin,Hin,Win),输出张量为 ( N , C o u t , H o u t , W o u t ) (N,C_{out},H_{out},W_{out}) (N,Cout,Hout,Wout)。
其中,
H o u t = [ ( H i n − 1 ) × s t r i d e [ 0 ] − 2 × p a d d i n g [ 0 ] + k e r n e l s i z e [ 0 ] ] H_{out}=[({H_{in}-1)×stride[0]-2×padding[0]+kernel size[0]}] Hout=[(Hin−1)×stride[0]−2×padding[0]+kernelsize[0]]
W o u t = [ ( W i n − 1 ) × s t r i d e [ 1 ] − 2 × p a d d i n g [ 1 ] + k e r n e l s i z e [ 1 ] ] W_{out}=[({W_{in}-1)×stride[1]-2×padding[1]+kernel size[1]}] Wout=[(Win−1)×stride[1]−2×padding[1]+kernelsize[1]]
以torch.nn模块之卷积层详解中图3卷积后的结果为例,对其进行最大值池化、平均值池化与自适应平均值池化。(实现代码接着卷积层后面写)。
# 对卷积后的结果进行最大值池化
maxpool2 = nn.MaxPool2d(2, stride=2)
pool2_out = maxpool2(imconv2out)
pool2_out_im = pool2_out.squeeze()
print(pool2_out.shape)
>>>torch.Size([1, 2, 254, 254])
# 可视化最大池化后的结果
plt.figure(figsize=(12, 6))
plt.subplot(121), plt.imshow(pool2_out_im[0].data, cmap=plt.cm.gray)
plt.axis("off")
plt.subplot(122), plt.imshow(pool2_out_im[1].data, cmap=plt.cm.gray)
plt.axis("off")
plt.show()
最大值池化结果中可以看到,原始508×508
的特征映射在经过窗口为2×2
,步长为2的最大池化后,尺寸变为254×254
的特征映射。
使用nn.AvgPool2d()
函数,对卷积后的输出进行平均值池化,并进行可视化。
# 对卷积后的结果进行平均值池化
avgpool2 = nn.AvgPool2d(2, stride=2)
pool2_out = avgpool2(imconv2out)
pool2_out_im = pool2_out.squeeze()
print(pool2_out.shape)
>>>torch.Size([1, 2, 254, 254])
# 可视化平均值池化后的结果
plt.figure(figsize=(12, 6))
plt.subplot(121), plt.imshow(pool2_out_im[0].data, cmap=plt.cm.gray)
plt.axis("off")
plt.subplot(122), plt.imshow(pool2_out_im[1].data, cmap=plt.cm.gray)
plt.axis("off")
plt.show()
使用nn.AdaptiveAvgPool2d()
函数,对卷积后的输出进行自适应平均值池化,并进行可视化。
注: 在使用该函数时,可以使用
output_size
参数指定输出特征映射的尺寸。
# 对卷积后的结果进行自适应平均值池化
AdaAvgPool2 = nn.AdaptiveAvgPool2d(output_size=(100, 100))
pool2_out = AdaAvgPool2(imconv2out)
pool2_out_im = pool2_out.squeeze()
print(pool2_out.shape)
>>>torch.Size([1, 2, 100, 100])
# 可视化自适应平均值池化后的结果
plt.figure(figsize=(12, 6))
plt.subplot(121), plt.imshow(pool2_out_im[0].data, cmap=plt.cm.gray)
plt.axis("off")
plt.subplot(122), plt.imshow(pool2_out_im[1].data, cmap=plt.cm.gray)
plt.axis("off")
plt.show()
从图中可以看出,池化后的特征映射尺寸变小,图像变得更加模糊。