引言
在卷积神经网络中,填充和步幅是两个重要的概念。填充是指在输入数据周围添加一定数量的虚拟数据,以便增加输出的大小。步幅则是指卷积核在输入数据上滑动的步长。本文将详细介绍填充和步幅的概念、应用以及计算方法,并使用PyTorch给出具体的例子。
填充
填充可以增加输出的大小,从而使得卷积层能够更好地保留输入数据的边缘信息。在卷积神经网络中,通常使用两种类型的填充:零填充和边缘填充。
理论推导
假设输入数据为 X X X,卷积核大小为 K K K,输出数据为 Y Y Y,则使用零填充的输出数据大小为:
Y s i z e = ( X s i z e − K s i z e + 2 P ) / S + 1 Y_{size} = (X_{size} - K_{size} + 2P) / S + 1 Ysize=(Xsize−Ksize+2P)/S+1
其中, P P P是填充大小, S S S是步幅大小。为了使输出大小与输入大小相等,可以解出 P P P的值:
P = ( K s i z e − 1 ) / 2 P = (K_{size} - 1) / 2 P=(Ksize−1)/2
这个公式适用于卷积核大小为奇数的情况。如果卷积核大小为偶数,则需要使用边缘填充。
计算步骤
以一个 3 × 3 3 \times 3 3×3的输入数据和 2 × 2 2 \times 2 2×2的卷积核为例,假设步幅为1,使用零填充的计算步骤如下:
- 将输入数据周围填充一圈0,填充后的大小为 5 × 5 5 \times 5 5×5。
- 卷积核从输入数据的左上角开始,按照步幅1的方式向右滑动,每次计算一个输出元素。
- 对于每个输出元素,计算其对应的输入子矩阵和卷积核的点积,得到一个标量值。
- 将计算得到的标量值赋值给对应的输出元素。
例子
使用PyTorch实现一个 3 × 3 3 \times 3 3×3的输入数据和 2 × 2 2 \times 2 2×2的卷积核,步幅为1,使用零填充的卷积操作:
import torch
# 输入数据
x = torch.tensor([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
], dtype=torch.float32).unsqueeze(0).unsqueeze(0)
# 卷积核
k = torch.tensor([
[1, 2],
[3, 4]
], dtype=torch.float32).unsqueeze(0).unsqueeze(0)
# 零填充
p = (k.size(-1) - 1) // 2
x = torch.nn.functional.pad(x, (p, p, p, p))
# 卷积操作
y = torch.nn.functional.conv2d(x, k, stride=1)
print(y)
输出结果为:
tensor([[[[12., 16., 20.],
[24., 28., 32.],
[36., 40., 44.]]]])
步幅
步幅是卷积核在输入数据上滑动的步长。使用步幅可以减少输出数据的大小,从而减少计算量。在卷积神经网络中,通常使用两种类型的步幅:常规步幅和空洞步幅。
理论推导
假设输入数据为 X X X,卷积核大小为 K K K,输出数据为 Y Y Y,则使用常规步幅的输出数据大小为:
Y s i z e = ( X s i z e − K s i z e ) / S + 1 Y_{size} = (X_{size} - K_{size}) / S + 1 Ysize=(Xsize−Ksize)/S+1
其中, S S S是步幅大小。如果使用空洞步幅,则输出数据大小为:
Y s i z e = ( X s i z e − K s i z e × D ) / S + 1 Y_{size} = (X_{size} - K_{size} \times D) / S + 1 Ysize=(Xsize−Ksize×D)/S+1
其中, D D D是空洞大小。空洞步幅可以在不增加计算量的情况下增加感受野的大小。
计算步骤
以一个 5 × 5 5 \times 5 5×5的输入数据和 3 × 3 3 \times 3 3×3的卷积核为例,假设步幅为2,使用常规步幅的计算步骤如下:
- 卷积核从输入数据的左上角开始,按照步幅2的方式向右滑动,每次计算一个输出元素。
- 对于每个输出元素,计算其对应的输入子矩阵和卷积核的点积,得到一个标量值。
- 将计算得到的标量值赋值给对应的输出元素。
例子
使用PyTorch实现一个 5 × 5 5 \times 5 5×5的输入数据和 3 × 3 3 \times 3 3×3的卷积核,步幅为2的卷积操作:
import torch
# 输入数据
x = torch.tensor([
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25]
], dtype=torch.float32).unsqueeze(0).unsqueeze(0)
# 卷积核
k = torch.tensor([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
], dtype=torch.float32).unsqueeze(0).unsqueeze(0)
# 卷积操作
y = torch.nn.functional.conv2d(x, k, stride=2)
print(y)
输出结果为:
tensor([[[[ 99., 129.],
[219., 249.]]]])
结构图
其中,输入数据经过卷积层后得到输出,同时可以进行填充和步幅操作,填充操作可以增加输入数据的维度,而步幅操作可以调整卷积层的感受野大小。
结论
填充和步幅是卷积神经网络中非常重要的概念。通过合理地使用填充和步幅,可以增强卷积神经网络的性能,提高模型的准确率和泛化能力。
参考文献
- PyTorch官方文档:torch.nn.functional.conv2d
- 李沐等人,《动手学深度学习》,人民邮电出版社,2020。