填充和步幅


假设输入形状是 \(n_h \times n_w\),卷积核窗口形状是 \(k_h \times k_w\),则输出形状是

\[(n_h - k_h + 1) \times (n_w - k_w + 1) \]

这里介绍卷积层的两个超参数填充和步幅,它们可以改变输出形状



1. 填充

填充(\(padding\))是指在输入高和宽的两侧填充元素(通常是0元素)。

输入形状 \(n_h \times n_w\),卷积核 \(k_h \times k_w\),如果在高的两侧一共填充 \(p_h\),宽的两侧一共填充 \(p_w\),那么输出形状

\[{\color{Blue}(n_h + p_h − k_h + 1) × (n_w + p_w − k_w + 1)} \]

输出的高和宽会分别增加 \(p_h、p_w\)

大多情况下,设置 \(p_h = k_h -1\)\(p_w = k_w -1\) 来使输入和输出具有相同的高和宽。假设 \(k_h\) 是奇数,在高的两侧填充 \(\frac{p_h}{2}\) 行。\(k_h\) 是偶数,在输入的顶端一侧填充 \(\lceil \frac{p_h}{2} \rceil\),在底端一侧填充 \(\lfloor \frac{p_h}{2} \rfloor\)。在宽的两侧填充同理。


示例:输入形状 \(n_h = n_w = 8\),二维卷积层 \(k_h = k_w = 3\),填充数 \(p_h = p_w = 1\)。求输出形状。

import torch
from torch import nn

# 定义一个函数来计算卷积层。它对输入和输出做相应的升维和降维
def comp_conv2d(conv2d, X):
    X = X.view((1, 1) + X.shape)	# (1, 1)代表批量大小和通道数均为1
    Y = conv2d(X)
    return Y.view(Y.shape[2:])		# 排除不关心的前两维:批量和通道

# 注意这里是两侧分别填充1行或列,所以在两侧一共填充2行或列
conv2d = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=(3,3), padding=1)

X = torch.rand(8, 8)
print(comp_conv2d(conv2d, X).shape)
torch.Size([8, 8])

当卷积核的高、宽不同时,可以设置高、宽不同的填充数使输出和输入有相同的形状。

示例 1:卷积核 \(k_h = 5, k_w = 3\),填充数 \(p_h=2, p_w=1\)。求输出形状。

# 使用高为5、宽为3的卷积核。在高和宽两侧的填充数分别为2和1
conv2d = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=(5, 3), padding=(2, 1))
print(comp_conv2d(conv2d, X).shape)
torch.Size([8, 8])

\[n_h + p_h − k_h + 1 = 8 + 2 * 2 - 5 + 1 = 8 \\ n_w + p_w − k_w + 1 = 8 + 2 * 1 - 3 + 1 = 8 \]



2. 步幅

卷积窗口每次滑动的行数和列数称为步幅\(stride\))。

\(5.3\) 展示了在高上步幅为 \(3\)、宽上步幅为 \(2\) 的二维互相关运算。

示例 2:令高和宽上的步幅均为 \(2\),从而使输入的高和宽减半。

conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
comp_conv2d(conv2d, X).shape
torch.Size([4, 4])

示例 3:

conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4))
comp_conv2d(conv2d, X).shape
torch.Size([2, 2])


3. 小结

  • 填充可以增加输出的高和宽。这常用来使输出与输入具有相同的高和宽。
  • 步幅可以减小输出的高和宽,例如输出的高和宽仅为输入的高和宽的 \(1/n\)\(n\) 为大于 \(1\) 的整数)。


来自:《动手学深度学习》

posted @ 2022-12-28 12:51  做梦当财神  阅读(107)  评论(0编辑  收藏  举报