官方文档:https://pytorch.org/docs/master/generated/torch.nn.ConvTranspose2d.html#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然后进行常规的卷积运算。实际转换过程中存在的细节问题下文会提及。
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
1)在输入feature map的每2个像素之间增加(s-1)个0
2)在输入的底边和右边进行padding——(c+2p-k)mod(s),其中c的计算方式见下方。
3)最后根据公式进行外围的padding。
普通卷积输出的计算方式: 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
==============================================================
※torch.nn.ConvTranspose2d中的output_padding参数的设定为0或1就决定了c=5还是6。
整个过程满足: 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为原始尺寸
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.csdn.net/qq_41076797/article/details/114494990