理论部分全部可参考吴恩达讲解的CNN部分。

填充

填充过程中,在很多情况下,我们会设置填充与步幅 - 图1填充与步幅 - 图2来使输入和输出具有相同的高和宽。这样会方便在构造网络时推测每个层的输出形状。假设这里填充与步幅 - 图3是奇数,我们会在高的两侧分别填充填充与步幅 - 图4行。如果填充与步幅 - 图5是偶数,一种可能是在输入的顶端一侧填充填充与步幅 - 图6行,而在底端一侧填充填充与步幅 - 图7行。在宽的两侧填充同理。
在讲例子之前,先补充一下pytorch操作维度时的contactate也就是连接操作。可以看到x.view后的(1, 1)参数直接与x.shape进行了连接。这样就对张量进行了升维的操作。

  1. x = torch.rand(8, 8)
  2. x = x.view((1, 1) + x.shape)
  3. print(x.shape)
  4. 结果:
  5. torch.Size([1, 1, 8, 8])

在定义卷积层时可以通过padding参数设置填充,可以看到设置为1后经过卷积计算张量形状不变。

  1. def comp_conv2d(conv2d, x):
  2. x = x.view((1, 1) + x.shape)
  3. y = conv2d(x)
  4. return y.view(y.shape[2:])
  5. conv2d = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, padding=1)
  6. x = torch.rand(8, 8)
  7. print(comp_conv2d(conv2d, x).shape)
  8. conv2d = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=(5, 3), padding=(2, 1))
  9. print(comp_conv2d(conv2d, x).shape)
  10. 结果:
  11. torch.Size([8, 8])
  12. torch.Size([8, 8])

步幅

步幅就是卷积核一次移动的步长,非常简单。

  1. conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
  2. print(comp_conv2d(conv2d, x).shape)
  3. conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4))
  4. print(comp_conv2d(conv2d, x).shape)
  5. 结果:
  6. torch.Size([4, 4])
  7. torch.Size([2, 2])

小结

当输入的高和宽两侧的填充数分别为填充与步幅 - 图8时,我们称填充为填充与步幅 - 图9。特别地,当填充与步幅 - 图10时,填充为填充与步幅 - 图11。当在高和宽上的步幅分别为填充与步幅 - 图12时,我们称步幅为填充与步幅 - 图13。特别地,当填充与步幅 - 图14时,步幅为填充与步幅 - 图15。在默认情况下,填充为0,步幅为1。