当步幅大于内核时,卷积中会发生什么?



我最近在Pytorch中试验卷积和转置卷积。我注意到使用nn.ConvTranspose2dAPI(我还没有尝试过使用普通卷积 API),您可以指定大于内核大小的步幅,卷积仍然可以工作。

在这种情况下发生了什么?我很困惑,因为如果步幅大于内核,这意味着输入图像中的某些像素不会被卷积。那么他们会发生什么?

我有以下代码片段,我在其中手动设置了nn.ConvTranspose2d图层的权重:

IN = 1
OUT = 1
KERNEL_SIZE = 2
proof_conv = nn.ConvTranspose2d(IN, OUT, kernel_size=KERNEL_SIZE, stride=4)
assert proof_conv.weight.shape == (IN, OUT, KERNEL_SIZE, KERNEL_SIZE)
FILTER = [
[1., 2.],
[0., 1.]
]
weights = [
[FILTER]
]
weights_as_tensor = torch.from_numpy(np.asarray(weights)).float()
assert weights_as_tensor.shape == proof_conv.weight.shape
proof_conv.weight = nn.Parameter(weights_as_tensor)
img = [[
[1., 2.],
[3., 4.]
]]
img_as_tensor = torch.from_numpy(np.asarray(img)).float()
out_img = proof_conv(img_as_tensor)
assert out_img.shape == (OUT, 6, 6)

步幅大于 2 的KERNEL_SIZE。然而,转置卷积仍然发生,我们得到 6x6 的输出。引擎盖下发生了什么?

这篇文章:了解Conv2DTranspose的PyTorch实现是有帮助的,但没有回答步幅大于内核的边缘情况。

正如您已经猜到的 - 当步幅大于内核大小时,有输入像素不参与卷积操作.
这取决于您 - 体系结构的设计者决定此属性是错误还是功能。在某些情况下,我利用此属性忽略了部分输入。

更新:
我认为您对proof_conv中的偏见术语感到困惑。尝试消除它:

proof_conv = nn.ConvTranspose2d(IN, OUT, kernel_size=KERNEL_SIZE, stride=4, bias=False)

现在你会得到out_img

[[[[1., 2., 0., 0., 2., 4.],
[0., 1., 0., 0., 0., 2.],
[0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0.],
[3., 6., 0., 0., 4., 8.],
[0., 3., 0., 0., 0., 4.]]]]

其中代表内核的 4 个副本,由输入图像加权,根据stride=4间隔 4 个像素。 输出图像的其余部分用零填充 - 表示对转置卷积没有贡献的像素。

ConvTranspose遵循与常规conv相同的"逻辑",只是以"转置"的方式。如果您查看用于计算输出形状的公式,您会发现您得到的行为是一致的。

我的理解是,无论stridekernel_size如何ConvTranspose2D都将始终使用输入图像中的所有像素。这与Conv2D不同。通过查看out_img中的实际值(如@Shai的答案所示),每个值都用于在图像的角落生成四组 2x2 值。 相反,ConvTranspose2D中的stride会影响输出图像的大小和间距。您可以看到,因为在这种情况下stride=4,2x2 输入和 2x2 内核的 4 个 2x2 结果相隔 4 个单位。中间空间用零填充,因为如果stride>kernel_size,某些输出像素将没有输入。

这本质上是某些输入单元格未在Conv2D中使用的推论,如果stride>kernel_size。我想也许这就是你想用你的问题来表达的。

最新更新