反卷积torch.nn.ConvTranspose2d详解(含转换成卷积运算的代码示例)

目录

        • 1.torch.nn.ConvTranspose2d参数介绍
        • 2.如何得到新的feature map
            • ①s=1:不进行插值操作,只进行padding操作
            • ②s>1:进行插值操作
          • eg: i=3, k=3, p=1, s=2
        • 3.执行卷积操作
        • 4.反卷积转换成卷积操作(代码示例)

1.torch.nn.ConvTranspose2d参数介绍

官方文档: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然后进行常规的卷积运算。实际转换过程中存在的细节问题下文会提及。

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+2padding_newsize   ,padding_newsize=kernel_sizepadding1
反卷积torch.nn.ConvTranspose2d详解(含转换成卷积运算的代码示例)_第1张图片

②s>1:进行插值操作
反卷积torch.nn.ConvTranspose2d详解(含转换成卷积运算的代码示例)_第2张图片

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+2pf+1×sn+2pf+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+213+1c=5,6

  • 当c=5时,(5+2-3)mod(2)=0,∴第2)步无需填充
  • 而根据p’=k-p-1=1,则需要在feature map外围padding一圈,即可按照k’=3,s’=1进行卷积操作。
  • 上述操作依次如下图所示:
反卷积torch.nn.ConvTranspose2d详解(含转换成卷积运算的代码示例)_第3张图片
反卷积torch.nn.ConvTranspose2d详解(含转换成卷积运算的代码示例)_第4张图片 反卷积torch.nn.ConvTranspose2d详解(含转换成卷积运算的代码示例)_第5张图片

==============================================================

  • 当c=6时,(6+2-3)mod(2)=1,所以首先在底边和右边padding一行/列
  • 同样p’=1,再在上一步的基础上,在feature map外围padding一圈。
  • 上述操作依次如下图所示:
反卷积torch.nn.ConvTranspose2d详解(含转换成卷积运算的代码示例)_第6张图片

※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=(Houts2p+kernel_size)HinHout

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.csdn.net/qq_41076797/article/details/114494990

你可能感兴趣的:(pytorch,深度学习,pytorch)