20 卷积层里的填充和步幅【动手学深度学习v2】

使用更大的卷积核可以更快地减小输出大小,在层数较大时,图像会变得过小。

解决方案1:填充

不填充的话边缘上用到的信息次数没有中间的多,填充后,可以增多边缘信息的读取次数。
下图展示了常用的填充列数和行数,基本思路是保持输出和输入数据形状不变。

解决方案2:步幅

步幅对输出形状的影响(调整步幅通常可以将数据成倍缩小)

卷积核大小、数据填充量、步幅等都是卷积层的超参数
总结:

代码实现
在所有侧边填充一个像素
import torch from torch import nn # 为了方便起见,我们定义了一个计算卷积层的函数。 # 此函数初始化卷积层权重,并对输入和输出提高和缩减相应的维数 def comp_conv2d(conv2d, X): # 这里的(1,1)表示批量大小和通道数都是1 X = X.reshape((1, 1) + X.shape) #此步是将二维数据X(8,8)转化为四维数据X(1,1,8,8) Y = conv2d(X) # 省略前两个维度:批量大小和通道 return Y.reshape(Y.shape[2:]) # 请注意,这里每边都填充了1行或1列,因此总共添加了2行或2列 conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1) X = torch.rand(size=(8, 8)) comp_conv2d(conv2d, X).shape
输出结果
torch.Size([8, 8])
填充不同的高度和宽度,同时调整卷积核大小,使输入输出数据形状不变
conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1)) comp_conv2d(conv2d, X).shape
torch.Size([8, 8])
将高度和宽度步幅设为2(stride控制步幅)
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2) comp_conv2d(conv2d, X).shape
torch.Size([4, 4])
一个稍微复杂的例子。
conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4)) comp_conv2d(conv2d, X).shape
torch.Size([2, 2])
补充知识:
填充(上下边总填充量)一般取核边长-1
卷积步幅最好取1,一般取2,在计算量过大时取更大值
卷积核边长一般取奇数,因为padding=kernel-1,而padding是分在图片上下的,kernel为奇数,padding就可以对半分。