卷积结果对位置敏感,以检测垂直边缘为例:

X=[11000110001100011000]\mathbf{X }=\left[ \begin{array}{ccccc} 1&1&0&0&0\\ 1&1&0&0&0\\ 1&1&0&0&0\\ 1&1&0&0&0\\ \end{array} \right]

1 像素的位移就将导致 0 输出

考虑到照明、物体位置、比例、外观等等因图像而异,需要一定的平移不变性

二维最大池化

返回滑动窗口中的最大值

Untitled

max(0,1,3,4)=4\max(0,1,3,4)=4

还以检测垂直边缘为例:

X=[11000110001100011000]\mathbf{X }=\left[ \begin{array}{ccccc} 1&1&0&0&0\\ 1&1&0&0&0\\ 1&1&0&0&0\\ 1&1&0&0&0\\ \end{array} \right]

卷积输出:

Y=[01000010000100001000]\mathbf{Y}=\left[ \begin{array}{ccccc} 0&1&0&0&0\\ 0&1&0&0&0\\ 0&1&0&0&0\\ 0&1&0&0&0\\ \end{array} \right]

2×22\times2 最大池化:

[11000110001100011000]\left[ \begin{array}{ccccc} 1&1&0&0&0\\ 1&1&0&0&0\\ 1&1&0&0&0\\ 1&1&0&0&0\\ \end{array} \right]

可容 1 像素位移

填充、步幅和多通道

池化层与卷积层类似,都具有填充和步幅

池化层没有可学习的参数

在每个输入通道应用池化层以获得相应的输出通道

输出通道数 = 输入通道数

平均池化层

最大池化层保留每个窗口中最强的模式信号

平均池化层将最大池化层中的“最大”操作替换为“平均”

总结

  • 池化层返回窗口中最大或平均值
  • 缓解卷积层对位置的敏感性
  • 同样有窗口大小、填充和步幅作为超参数

代码实现

实现池化层的正向传播

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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

验证二维最大池化层的输出

1
2
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))
1
2
tensor([[4., 5.],
[7., 8.]])

验证平均池化层

1
pool2d(X, (2, 2), 'avg')
1
2
tensor([[2., 3.],
[5., 6.]])

填充和步幅

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

PyTorch 框架中默认的步幅与池化窗口的大小相同

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

填充和步幅可以手动设定

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

设定一个任意大小的矩形池化窗口,并分别设定填充和步幅的高度和宽度

1
2
pool2d = nn.MaxPool2d((2, 3), padding=(1, 1), stride=(2, 3))
pool2d(X)
1
2
3
tensor([[[[ 1.,  3.],
[ 9., 11.],
[13., 15.]]]])

池化层在每个输入通道上单独运算

1
2
X = torch.cat((X, X + 1), 1)
X
1
2
3
4
5
6
7
8
9
10
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.]]]])

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

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