池化层(Pooling layers)-灵析社区

乌兰推

1.理论部分

在进行卷积层计算时候,有一个问题就是边缘的地方容易忽略,并且对位置是非常敏感的。池化层的做法是为了降低卷积层对位置的敏感性,同时降低对空间降采样表示的敏感性。 因此,除了卷积层,卷积网络也经常使用池化层来缩减模型的大小,提高计算速度,同时提高所提取特征的鲁棒性。与卷积层不同的是,池化层运算是确定性的,我们通常计算池化窗口中所有元素的最大值或平均值。这些操作分别称为最大池化层(maximum pooling)和平均池化层(average pooling)。先举一个池化层的例子
假如输入是一个4×4矩阵,用到的池化类型是最大池化(max pooling)。执行最大池化是一个2×2矩阵。执行过程非常简单,把4×4的输入拆分成不同的区域,我把这个区域用不同颜色来标记。对于2×2的输出,输出的每个元素都是其对应颜色区域中的最大元素值。


左上区域的最大值是9,右上区域的最大元素值是2,左下区域的最大值是6,右下区域的最大值是3。为了计算出右侧这4个元素值,我们需要对输入矩阵的2×2区域做最大值运算。

这里相当于是一个2×2的kernel,步幅为2。因为我们使用的过滤器为2×2,最后输出是9。然后向右移动2个步幅,计算出最大值2。然后是第二行,向下移动得到最大值6。最后向右移动,得到最大值3。这是一个2×2矩阵,即f=2f=2f=2,步幅是2,即s=2s=2s=2。

这是对最大池化功能的直观理解,你可以把这个4×4区域看作是某些特征的集合,也就是神经网络中某一层的非激活值集合。数字大意味着可能探测到了某些特定的特征,左上象限具有的特征可能是一个垂直边缘,最大化操作的功能就是只要在任何一个象限内提取到某个特征,它都会保留在最大化的池化输出里。所以最大化运算的实际作用就是,如果在过滤器中提取到某个特征,那么保留其最大值。如果没有提取到这个特征,可能在右上象限中不存在这个特征,那么其中的最大值也还是很小。

其中一个有意思的特点就是,它有一组超参数,但并没有参数需要学习。实际上,梯度下降没有什么可学的,一旦确定了fff和sss,它就是一个固定运算,梯度下降无需改变任何值。

目前来说,最大池化比平均池化更常用。但也有例外,就是深度很深的神经网络,你可以用平均池化来分解规模为7×7×1000的网络的表示层,在整个空间内求平均值,得到1×1×1000。但在神经网络中,最大池化要比平均池化用得更多。

2.代码实现

池化层代码非常简单,因为这里没有卷积核,输出为输入中每个区域的最大值或平均值,我们可以很简单的自定义一个池化层函数

import torch
from torch import nn
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

X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
X
# 测试我们刚刚的函数,默认最大池化层
pool2d(X, (2, 2))
tensor([[4., 5.],
        [7., 8.]])

3.填充与步幅

与卷积层一样,池化层也可以改变输出形状。和以前一样,我们可以通过填充(padding)和步幅(stride)以获得所需的输出形状。 这里我们直接使用pytorch内置的方法来演示,首先生成输入张量X,它是一个四维张量,其中样本数和通道数都是1。

X = torch.arange(16, dtype=torch.float32).reshape((1, 1, 4, 4))
X
tensor([[[[ 0.,  1.,  2.,  3.],
          [ 4.,  5.,  6.,  7.],
          [ 8.,  9., 10., 11.],
          [12., 13., 14., 15.]]]])

默认条件下,步幅和池化层的窗口大小一致。例如,我们使用3×33×33×3的池化层,那么步幅sss默认是3

pool2d = nn.MaxPool2d(3)
pool2d(X)
tensor([[[[10.]]]])

我们可以根据需要指定相应的步幅和填充,这里我们设置padding=1,stride=2通常情况下,我们不会使用填充(padding),因为这一部分可以在卷积层进行。

pool2d = nn.MaxPool2d(3, padding=1, stride=2)
pool2d(X)

4.多通道

在处理多通道输入数据时,池化层在每个输入通道上单独运算,而不是像卷积层一样在通道上对输入进行汇总。 这意味着汇聚层的输出通道数与输入通道数相同。和我们之前创建多通道数据一样,我们使用cat函数

X = torch.cat((X, X + 1), 1)
X

此时X的纬度是1×2×4×4,1个样本,两个通道

接下来我们使用一个2×2的池化层,步幅sss为2

pool2d = nn.MaxPool2d(2, stride=2)
pool2d(X)
tensor([[[[ 5.,  7.],
          [13., 15.]],

         [[ 6.,  8.],
          [14., 16.]]]])

可以看到结果仍然是一个两通道张量,这一点和卷积层完全不同。

总结

特点:

  • 输入通道数等于输出通道数
  • 没有可以学习的参数
  • 池化层的主要优点之一是减轻卷积层对位置的过度敏感
  • 最大池化层:返回窗口内的最大值,提取的是每个窗口中最强的信号,更常用
  • 平均池化层:平均汇聚层会输出该窗口内的平均值。

阅读量:1869

点赞量:0

收藏量:0