卷积和卷积转置互不抵消
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_dimension
、out = output_dimension
、k = kernel_size
、s = stride
、d = dilation
、p = padding
和 op = 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 = x
当op = 0
。
否则如果 x
是 even 那么:
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
我正在尝试实现自动编码器 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_dimension
、out = output_dimension
、k = kernel_size
、s = stride
、d = dilation
、p = padding
和 op = 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 = x
当op = 0
。
否则如果 x
是 even 那么:
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