目录
1.torch.nn.ConvTranspose2d参数介绍
torch.nn.ConvTranspose2d(in_channels, out_channels, kernel_size, stride=1, padding=0, output_padding=0, groups=1,
bias=True, dilation=1, padding_mode='zeros', device=None, dtype=None)
※反卷积可以认为先对feature map进行插值/padding操作得到新的feature map然后进行常规的卷积运算。实际转换过程中存在的细节问题下文会提及。
2.如何得到新的feature map
①s=1:不进行插值操作,只进行padding操作
H
o
u
t
=
H
i
n
+
2
∗
p
a
d
d
i
n
g
_
n
e
w
s
i
z
e
其
中
,
p
a
d
d
i
n
g
_
n
e
w
s
i
z
e
=
k
e
r
n
e
l
_
s
i
z
e
−
p
a
d
d
i
n
g
−
1
H_{out}=H_{in}+2*padding\_newsize \ \ \ 其中,padding\_newsize=kernel\_size-padding-1
Hout=Hin+2∗padding_newsize 其中,padding_newsize=kernel_size−padding−1
②s>1:进行插值操作

1)在输入feature map的每2个像素之间增加(s-1)个0
2)在输入的底边和右边进行padding——(c+2p-k)mod(s),其中c的计算方式见下方。
3)最后根据公式进行外围的padding。
eg: i=3, k=3, p=1, s=2
普通卷积输出的计算方式:
o
u
t
p
u
t
f
e
a
t
u
r
e
m
a
p
=
⌊
n
+
2
p
−
f
s
+
1
⌋
×
⌊
n
+
2
p
−
f
s
+
1
⌋
output\ feature\ map=\lfloor \frac{n+2p-f}{s}+ 1\rfloor×\lfloor \frac{n+2p-f}{s}+ 1\rfloor
output feature map=⌊sn+2p−f+1⌋×⌊sn+2p−f+1⌋
同样地,计算反卷积的输出:
3
=
⌊
c
+
2
∗
1
−
3
2
+
1
⌋
→
c
=
5
,
6
3=\lfloor \frac{c+2*1-3}{2}+ 1\rfloor→c=5,6
3=⌊2c+2∗1−3+1⌋→c=5,6
- 当c=5时,(5+2-3)mod(2)=0,∴第2)步无需填充
- 而根据p’=k-p-1=1,则需要在feature map外围padding一圈,即可按照k’=3,s’=1进行卷积操作。
- 上述操作依次如下图所示:



==============================================================
- 当c=6时,(6+2-3)mod(2)=1,所以首先在底边和右边padding一行/列
- 同样p’=1,再在上一步的基础上,在feature map外围padding一圈。
- 上述操作依次如下图所示:

※torch.nn.ConvTranspose2d中的output_padding参数的设定为0或1就决定了c=5还是6。
3.执行卷积操作
整个过程满足: H i n = ( H o u t ∗ s − 2 ∗ p + k e r n e l _ s i z e ) , 其 中 H i n 为 目 标 尺 寸 , H o u t 为 原 始 尺 寸 H_{in}=(H_{out}*s - 2*p + kernel\_size),其中H_{in}为目标尺寸,H_{out}为原始尺寸 Hin=(Hout∗s−2∗p+kernel_size),其中Hin为目标尺寸,Hout为原始尺寸
4.反卷积转换成卷积操作(代码示例)
1)插值操作
def interpolation(input, output_padding=0): # padding use conv2d
in_size = input.size()
assert in_size[2]==in_size[3]
inter_size = 2 * in_size[2] - 1
output = torch.zeros(in_size[0], in_size[1], inter_size, inter_size)
for i in range(in_size[0]):
for j in range(in_size[1]):
for m in range(in_size[2]):
for n in range(in_size[3]):
output[i][j][2*m][2*n] = input[i][j][m][n]
return output
2)卷积操作
※需要注意的是,torch.nn.ConvTranspose2d默认权重的排布方式和Conv2d是不同的,需要进行重新排布再进行常规的卷积操作。可以通过下方函数将反卷积操作转换为插值和卷积两步操作(这里的例子刚好没有底边和右边padding的情况)。
def compare_conv_deconv(input, weight, b, out):
inter_input = interpolation(input)
conv_wq = torch.flip(weight,dims=[2,3])
conv_wq = conv_wq.transpose(0,1)
test_out = torch.nn.functional.conv2d(inter_input, conv_wq, bias=b, stride=(1,1), padding=2, dilation=1, groups=1) # kernel_size=4
if out.equal(test_out):
print("all results are correct!")
return conv_wq, b
参考链接:https://blog.youkuaiyun.com/qq_41076797/article/details/114494990