卷积和卷积转置互不抵消

Convolution and convolution transposed do not cancel each other

我正在尝试实现自动编码器 CNN。但是,我有以下问题:

我编码器的最后一个卷积层定义如下:

Conv2d(128, 256, 3, padding=1, stride=2)

该层的输入形状为 (1, 128, 24, 24)。因此,输出的形状为 (1, 256, 12, 12).

在这一层之后,我有 ReLU 激活和 BatchNorm。这些都不会改变输出的形状。

然后我将第一个 ConvTranspose2d 层定义为:

ConvTranspose2d(256, 128, 3, padding=1, stride=2)

但是这一层的输出形状为 (1, 128, 23, 23)。

据我所知,如果我们在 ConvTrapnpose2d 中使用与前面的 Conv2d 层相同的内核大小、步幅和填充,那么这 2 层块的输出必须与其输入具有相同的形状。

所以,我的问题是:我的理解有什么问题吗?我该如何解决这个问题?

我首先要注意 nn.ConvTranspose2d 层不是 nn.Conv2d 的逆层,如其文档页面中所述:

it is not an actual deconvolution operation as it does not compute a true inverse of convolution


As far as I know, if we use the same kernel size, stride, and padding in ConvTranspose2d as in the preceding Conv2d layer, then the output of this 2 layers block must have the same shape as its input.

这并不总是正确的!这取决于输入的空间维度。

根据空间维度,二维卷积将输出:

out = [(x + 2p - d(k - 1) - 1)/s + 1]

其中 [x]x 的全部部分。

而二维转置卷积将输出:

out = (x - 1)s - 2p + d(k - 1) + op + 1

其中 x = input_dimensionout = output_dimensionk = kernel_sizes = strided = dilationp = paddingop = output_padding

如果您查看 convT o conv 运算符( convT(conv(x))),那么您有:

out = (out_conv - 1)s - 2p + d(k - 1) + op + 1
    = ([(x + 2p - d(k - 1) - 1)/s + 1] - 1)s - 2p + d(k - 1) + op + 1

只有当我们有[(x + 2p - d(k - 1) - 1)/s + 1] = (x + 2p - d(k - 1) - 1)/s + 1时才等于x,也就是说:如果x奇数,在这种情况下:

out = ((x + 2p - d(k - 1) - 1)/s + 1 - 1)s - 2p + d(k - 1) + op + 1
    = x + op

out = xop = 0

否则如果 xeven 那么:

out = x - 1 + op

设置 op = 1 得到 out = x.


这是一个例子:

>>> conv = nn.Conv2d(1, 1, 3, stride=2, padding=1)

>>> convT = nn.ConvTranspose2d(1, 1, 3, stride=2, padding=1)
>>> convT(conv(torch.rand(1, 1, 25, 25))).shape # x even
(1, 1, 25, 25) #<- out = x

>>> convT = nn.ConvTranspose2d(1, 1, 3, stride=2, padding=1, output_padding=1)
>>> convT(conv(torch.rand(1, 1, 24, 24))).shape # x odd
(1, 1, 24, 24) #<- out = x - 1 + op