池化层是卷积神经网络(Convolutional Neural Network, CNN)中关键的组成部分。它位于卷积层之后,主要目的是对卷积层输出的特征图进行降采样,降低特征图的空间尺寸,同时保留重要的特征信息。通常使用的池化操作有最大池化(Max Pooling)和平均池化(Average Pooling)。
- 最大池化
- 原理:在特征图上滑动一个池化窗口,取窗口内的最大值作为池化后的结果。例如,对于一个 4×4 的特征图,使用 2×2 的池化窗口,步长为 2,经过最大池化后会得到一个 2×2 的特征图。每个元素都是原特征图中对应 2×2 区域的最大值。
- 作用:能够突出局部区域内的显著特征,对图像中的边缘、角点等重要特征具有较好的保留效果。并且对图像的平移具有一定的鲁棒性,即使图像有小幅平移,最大值的位置和大小变化相对较小,从而能够减少过拟合。
- 平均池化
- 原理:同样是在特征图上滑动池化窗口,取窗口内所有元素的平均值作为池化后的结果。以同样 4×4 的特征图和 2×2 的池化窗口为例,得到的 2×2 特征图中的每个元素是对应区域的平均值。
- 作用:可以平滑特征图,减少噪声的影响。因为它考虑了局部区域内的所有像素值,在一定程度上能够抑制一些随机的、微弱的噪声特征,使特征图更加平滑,有助于后续的特征提取和分类等任务。
池化层的优势:
1. 空间维度缩减
- 降低计算量:随着特征图尺寸的减小,后续卷积层和全连接层的计算量大幅减少。
- 例如,一个 32×32×64 的特征图经过一次 2×2 的池化操作后,变为 16×16×64,参数数量和计算量都大大降低,这使得网络能够更高效地进行训练和推理。
2. 特征抽象和语义提升
- 强调重要特征:通过池化操作,特征图变得更加抽象,突出显示了更高层次的语义信息。
- 例如,在图像分类任务中,卷积层提取的基础特征(如边缘、纹理等)经过池化后,能够逐渐抽象出更具代表性的物体局部或整体特征,有助于模型更好地理解和区分不同类别。
3. 提高模型的泛化能力
- 不变性增强:池化层的平移、缩放和旋转不变性使得模型对图像的一些局部变化不敏感。
- 例如,在识别猫的图像时,即使猫的位置在图像中有所移动或者图像有轻微的缩放,池化操作后的特征图仍然能够较好地捕捉到猫的关键特征,从而提高模型在不同场景下的泛化能力。
import torch
from torch import nn
from d2l import torch as d2l
def pool2d(X, pool_size, mode='max'):
p_h, p_w = pool_size
Y = torch.zeros((X.shape[0] - p_h + 1, X.shape[1] - p_w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
if mode == 'max':
Y[i, j] = X[i: i + p_h, j: j + p_w].max()
elif mode == 'avg':
Y[i, j] = X[i: i + p_h, j: j + p_w].mean()
return Y
X = torch.tensor([[0.0, 1.0, 2.0],
[3.0, 4.0, 5.0],
[6.0, 7.0, 8.0]])
pool2d(X, (2, 2))
输出:
tensor([[2., 3.],
[5., 6.]])
填充和步幅:
X = torch.arange(16, dtype=torch.float32).reshape((1, 1, 4, 4))
X
输出X为:
tensor([[[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]]]])
默认情况下,深度学习框架中的步幅与汇聚窗口的大小相同。
因此,如果我们使用形状为(3, 3)
的汇聚窗口,那么默认情况下,我们得到的步幅形状为(3, 3)
。
pool2d = nn.MaxPool2d(3)
pool2d(X)
输出:
tensor([[[[10.]]]])
填充和步幅可以手动设定。
pool2d = nn.MaxPool2d(3, padding=1, stride=2)
pool2d(X)
输出:
tensor([[[[ 5., 7.],[13., 15.]]]])
当然,我们可以设定一个任意大小的矩形汇聚窗口,并分别设定填充和步幅的高度和宽a度。
pool2d = nn.MaxPool2d((2, 3), stride=(2, 3), padding=(0, 1))
pool2d(X)
输出:
tensor([[[[ 5., 7.],[13., 15.]]]])
在处理多通道输入数据时,汇聚层在每个输入通道上单独运算,而不是像卷积层一样在通道上对输入进行汇总。
这意味着汇聚层的输出通道数与输入通道数相同。
下面,我们将在通道维度上连结张量X
和X + 1
,以构建具有2个通道的输入。
X = torch.cat((X, X + 1), 1)
X
输出:
tensor([[[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]],
[[ 1., 2., 3., 4.],
[ 5., 6., 7., 8.],
[ 9., 10., 11., 12.],
[13., 14., 15., 16.]]]])
如下所示,汇聚后输出通道的数量仍然是2。
pool2d = nn.MaxPool2d(3, padding=1, stride=2)
pool2d(X)
输出:
tensor([[[[ 5., 7.],
[13., 15.]],
[[ 6., 8.],
[14., 16.]]]])
总结:
对于给定输入元素,最大池化层会输出该窗口内的最大值,平均池化层会输出该窗口内的平均值。
池化层的主要优点之一是减轻卷积层对位置的过度敏感。
我们可以指定池化层的填充和步幅。
使用最大池化层以及大于1的步幅,可减少空间维度(如高度和宽度)。
池化层的输出通道数与输入通道数相同。