池化层(Pooling layers)

池化层(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矩阵,即 <math xmlns="http://www.w3.org/1998/Math/MathML"> f = 2 f=2 </math>f=2,步幅是2,即 <math xmlns="http://www.w3.org/1998/Math/MathML"> s = 2 s=2 </math>s=2。

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

其中一个有意思的特点就是,它有一组超参数,但并没有参数需要学习 。实际上,梯度下降没有什么可学的,一旦确定了 <math xmlns="http://www.w3.org/1998/Math/MathML"> f f </math>f和 <math xmlns="http://www.w3.org/1998/Math/MathML"> s s </math>s,它就是一个固定运算,梯度下降无需改变任何值。

我们来看一个有若干个超级参数的示例,输入是一个5×5的矩阵。我们采用最大池化法,它的过滤器参数为3×3,即 <math xmlns="http://www.w3.org/1998/Math/MathML"> f = 3 f=3 </math>f=3,步幅为1, <math xmlns="http://www.w3.org/1998/Math/MathML"> s = 1 s=1 </math>s=1,输出矩阵是3×3。之前讲的计算卷积层输出大小的公式同样适用于最大池化, <math xmlns="http://www.w3.org/1998/Math/MathML"> n + 2 p − f s + 1 \frac{n + 2p - f}{s} + 1 </math>sn+2p−f+1,这个公式也可以计算最大池化的输出大小。

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

2.代码实现

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

python 复制代码
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

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

3.填充与步幅

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

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

默认条件下,步幅和池化层的窗口大小一致。例如,我们使用 <math xmlns="http://www.w3.org/1998/Math/MathML"> 3 × 3 3×3 </math>3×3的池化层,那么步幅 <math xmlns="http://www.w3.org/1998/Math/MathML"> s s </math>s默认是3

python 复制代码
pool2d = nn.MaxPool2d(3)
pool2d(X)
lua 复制代码
tensor([[[[10.]]]])

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

python 复制代码
pool2d = nn.MaxPool2d(3, padding=1, stride=2)
pool2d(X)

4.多通道

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

ini 复制代码
X = torch.cat((X, X + 1), 1)
X

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

接下来我们使用一个2×2的池化层,步幅 <math xmlns="http://www.w3.org/1998/Math/MathML"> s s </math>s为2

python 复制代码
pool2d = nn.MaxPool2d(2, stride=2)
pool2d(X)
lua 复制代码
tensor([[[[ 5.,  7.],
          [13., 15.]],

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

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

总结

总结一下,池化层的超参数包括过滤器大小 <math xmlns="http://www.w3.org/1998/Math/MathML"> f f </math>f和步幅 <math xmlns="http://www.w3.org/1998/Math/MathML"> s s </math>s,常用的参数值为 <math xmlns="http://www.w3.org/1998/Math/MathML"> f = 2 f=2 </math>f=2, <math xmlns="http://www.w3.org/1998/Math/MathML"> s = 2 s=2 </math>s=2,应用频率非常高,其效果相当于高度和宽度缩减一半。也有使用 <math xmlns="http://www.w3.org/1998/Math/MathML"> f = 3 f=3 </math>f=3, <math xmlns="http://www.w3.org/1998/Math/MathML"> s = 2 s=2 </math>s=2的情况。至于其它超参数就要看你用的是最大池化还是平均池化了。大部分情况下,最大池化很少用padding 。目前 <math xmlns="http://www.w3.org/1998/Math/MathML"> p p </math>p最常用的值是0,即 <math xmlns="http://www.w3.org/1998/Math/MathML"> p a d d i n g = 0 padding=0 </math>padding=0。最大池化的输入就是 <math xmlns="http://www.w3.org/1998/Math/MathML"> n H × n W × n c n_{H} \times n_{W} \times n_{c} </math>nH×nW×nc,假设没有padding ,则输出 <math xmlns="http://www.w3.org/1998/Math/MathML"> ⌊ n H − f s + 1 ⌋ × ⌊ n w − f s + 1 ⌋ × n c \lfloor\frac{n_{H} - f}{s} +1\rfloor \times \lfloor\frac{n_{w} - f}{s} + 1\rfloor \times n_{c} </math>⌊snH−f+1⌋×⌊snw−f+1⌋×nc。输入通道与输出通道个数相同,因为我们对每个通道都做了池化。需要注意的一点是,池化过程中没有需要学习的参数。执行反向传播时,反向传播没有参数适用于池化层。这些超参数都是设置的,可能是手动设置的,也可能是通过交叉验证设置的。

特点:

  • 输入通道数等于输出通道数
  • 没有可以学习的参数
  • 池化层的主要优点之一是减轻卷积层对位置的过度敏感
  • 最大池化层:返回窗口内的最大值,提取的是每个窗口中最强的信号,更常用
  • 平均池化层:平均汇聚层会输出该窗口内的平均值。
相关推荐
CareyWYR4 分钟前
每周AI论文速递(260323-260327)
人工智能
guoji778826 分钟前
安全与对齐的深层博弈:Gemini 3.1 Pro 安全护栏与对抗测试深度拆解
人工智能·安全
实在智能RPA34 分钟前
实在 Agent 和通用大模型有什么不一样?深度拆解 AI Agent 的感知、决策与执行逻辑
人工智能·ai
独隅39 分钟前
PyTorch 模型部署的 Docker 配置与性能调优深入指南
人工智能·pytorch·docker
lihuayong1 小时前
OpenClaw 系统提示词
人工智能·prompt·提示词·openclaw
黑客说1 小时前
AI驱动剧情,解锁无限可能——AI游戏发展解析
人工智能·游戏
踩着两条虫1 小时前
AI驱动的Vue3应用开发平台深入探究(十):物料系统之内置组件库
android·前端·vue.js·人工智能·低代码·系统架构·rxjava
小仙女的小稀罕1 小时前
听不清重要会议录音急疯?这款常见AI工具听脑AI精准转译
开发语言·人工智能·python
reesn1 小时前
qwen3.5 0.8B纠正任务实践
人工智能·语言模型