在本节中我们介绍池化(pooling)层,它的提出是为了缓解卷积层对位置的过度敏感性

二维最大池化层与平均池化层

同卷积层一样,池化层每次对输入数据的一个固定形状窗口(又称池化窗口)中的元素计算输出。不同于卷积层里计算输入和核的互相关性,池化层直接计算池化窗口内元素的最大值或者平均值。该运算也分别叫做最大池化或平均池化。在二维最大池化中,池化窗口从输入数组的最左上方开始,按从左往右、从上往下的顺序,依次在输入数组上滑动。当池化窗口滑动到某一位置时,窗口中的输入子数组的最大值即输出数组中相应位置的元素。

池化层 - 图1

注意一下,要对tensor进行取均值操作的话,那么tensor必须是float型
代码:

  1. import torch
  2. from torch import nn
  3. def pool2d(x, pool_size, mode="max"):
  4. x = x.float()
  5. p_h, p_w = pool_size
  6. y = torch.zeros(x.shape[0] - p_h + 1, x.shape[1] - p_w + 1)
  7. for i in range(0, y.shape[0]):
  8. for j in range(0, y.shape[1]):
  9. if mode == "max":
  10. y[i][j] = x[i:i + p_h, j:j + p_w].max()
  11. if mode == "mean":
  12. y[i][j] = x[i:i + p_h, j:j + p_w].mean()
  13. return y
  14. if __name__ == '__main__':
  15. X = torch.tensor([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
  16. print(pool2d(X, (2, 2)))
  17. print(pool2d(X, (2, 2), "mean"))
  18. 结果:
  19. tensor([[4., 5.],
  20. [7., 8.]])
  21. tensor([[2., 3.],
  22. [5., 6.]])

填充与步幅

nn中的MaxPool2d即二维最大池化层可以进行方便的操作。MaxPool2d的构造函数可以支持指定步幅和填充。默认情况下,padding为0,步幅与池化窗口形状相同。
做一个实验:

  1. if __name__ == '__main__':
  2. X = torch.arange(16, dtype=torch.float).view((1, 1, 4, 4))
  3. pool2dx = nn.MaxPool2d(3)
  4. print(pool2dx(X))
  5. pool2dx = nn.MaxPool2d(3, stride=1)
  6. print(pool2dx(X))
  7. 结果:
  8. tensor([[[[10.]]]])
  9. tensor([[[[10., 11.],
  10. [14., 15.]]]])

也可以指定非正方形的池化窗口:

  1. pool2dx = nn.MaxPool2d((2, 4), padding=(1, 2), stride=(2, 3))
  2. print(pool2dx(X))
  3. 结果:
  4. tensor([[[[ 1., 3.],
  5. [ 9., 11.],
  6. [13., 15.]]]])

多通道

在处理多通道输入数据时,池化层对每个输入通道分别池化,而不是像卷积层那样将各通道的输入按通道相加。这意味着池化层的输出通道数与输入通道数相等。