nn.ConvTranspose2d详解

概述

  • 该函数是用来进行转置卷积的,它主要做了这几件事:首先,对输入的feature map进行padding操作,得到新的feature map;然后,随机初始化一定尺寸的卷积核;最后,用随机初始化的一定尺寸的卷积核在新的feature map上进行卷积操作。
  • 补充一下,卷积核确实是随机初始的,但是后续可以对卷积核进行单独的修改,比如使用双线性卷积核,这样的话卷积核的参数是固定的,不可以进行学习修改。
  • 下面对上面的过程进行演示。

1.得到新的feature map

  • 分两种情况,s(步长)=1或者>1,分别对应下面的情况。

s=1

在这里插入图片描述

  • 如上图所示,当s=1时,对于原feature map不进行插值操作,只进行padding操作,padding_NewSize=(kernel_size - padding - 1),这里的padding是卷积操作时设置的padding值,如果是valid卷积的话padding=0,kernel_size是转置卷积中卷积核的尺寸。下面用 H i n t H_{int} Hint代替原始feature map, H o u t H_{out} Hout代替新的feature map。经过padding之后,再经过卷积核进行卷积操作就得到了 H o u t H_{out} Hout,上图 H o u t = H i n t + 2 ∗ p a d d i n g N e w S i z e = 2 + 4 = 6 H_{out}=H_{int}+2*paddingNewSize=2+4=6 Hout=Hint+2paddingNewSize=2+4=6
  • 其实这种情况还是比较好处理的,直接遵循 k ′ = k , s ′ = s , p ′ = k − p − 1 k^{'}=k,s^{'}=s,p^{'}=k-p-1 k=k,s=s,p=kp1就好了,其中 ′ ' 表示执行转置卷积时的参数,没有 ′ ' 表示是转置卷积前的卷积操作的参数。

s>1

在这里插入图片描述

  • 当s>1时,进行插值操作,什么是插值呢?大家看上图, H i n H_{in} Hin的元素之间被分隔开了,具体间隔多少个呢?(s-1)个。也就是说,上图的s=2。插入的元素是0。上图padding的设置为1。其实包括s啊,kernel_size啊,padding啊都是传入该函数的参数,你在调用该函数前肯定得先算好这些参数传入的值才能保证经过转置卷积之后得到的尺寸是你心仪的尺寸,这些尺寸的设置其实不是你需要重点关注的内容,只需要套公式计算就好了。

  • 这里有个疑问,为什么要进行插值操作呢?如果不进行插值操作,那么你步长不是1,可能会跳过一些 H i n H_{in} Hin的元素值,就丢失了一部分信息。

  • 另外这个地方比较麻烦的一点是,不能直接使用s=1时的公式来确定 p ′ , s ′ , k ′ p^{'},s^{'},k^{'} p,s,k了,而是要对输入进行处理,主要分为两步:

  • 1.在输入的每两个像素之间增加s-1个0。

  • 2.在输入的底边和右边加入 ( c + 2 ∗ p − k ) m o d ( s ) (c+2*p-k)mod(s) (c+2pk)mod(s),其中c就是根据第一步中计算出来的转置卷积输出的大小。

  • 我们来看下第1和2步,其实我们都知道卷积公式,那么假设转置卷积的输入i=3,k=3,s=2,p=1,计算转置卷积的输出:
    在这里插入图片描述
    此时c有两种情况,当c=5时, ( c + 2 ∗ p − k ) m o d    s = ( 5 + 2 ∗ 1 − 3 ) m o d    2 = 0 , s − 1 = 1 (c+2*p-k)mod\,\, s=(5+2*1-3)mod \,\, 2=0,s-1=1 (c+2pk)mods=(5+213)mod2=0s1=1,因此对3x3的输入特诊图进行0填充,按第一步填充得到:
    在这里插入图片描述
    第二步中 ( c + 2 ∗ p − k ) m o d    s = ( 5 + 2 ∗ 1 − 3 ) m o d    2 = 0 (c+2*p-k)mod\,\, s=(5+2*1-3)mod \,\, 2=0 (c+2pk)mods=(5+213)mod2=0,故无需填充。
    这两步走完了,最后按照 k ′ = k , s ′ = s , p ′ = k − p − 1 得到 k ′ = 3 , s ′ = 1 , p ′ = k − p − 1 = 1 k^{'}=k,s^{'}=s,p^{'}=k-p-1得到k^{'}=3,s^{'}=1,p^{'}=k-p-1=1 k=k,s=s,p=kp1得到k=3,s=1,p=kp1=1
    此时 p ′ = 1 p^{'}=1 p=1,再对特征图进行填充:
    在这里插入图片描述
    然后按照 k ′ = 3 , s ′ = 1 k^{'}=3,s^{'}=1 k=3,s=1进行卷积得到结果:
    在这里插入图片描述

  • 在看若c=6:
    当c=6时, ( c + 2 ∗ p − k ) m o d    s = ( 6 + 2 ∗ 1 − 3 ) m o d    2 = 1 , s − 1 = 1 ,因此对 3 × 3 (c+2*p-k)mod\,\, s=(6+2*1-3)mod \,\, 2=1,s-1=1,因此对3 \times 3 (c+2pk)mods=(6+213)mod2=1s1=1,因此对3×3的输入特诊图进行0填充,按第一步填充得到:
    在这里插入图片描述
    第二步中 ( c + 2 ∗ p − k ) m o d    s = ( 6 + 2 ∗ 1 − 3 ) m o d    2 = 1 , (c+2*p-k)mod\,\, s=(6+2*1-3)mod \,\, 2=1, (c+2pk)mods=(6+213)mod2=1因此再在特诊图下面和右边填充一层
    在这里插入图片描述
    同样计算出参数 k ′ = 3 , s ′ = 1 , p ′ = 3 − 1 − 1 = 1 k^{'}=3,s^{'}=1,p^{'}=3-1-1=1 k=3,s=1,p=311=1,对特征图进行填充:
    在这里插入图片描述
    然后再卷积得到输出:
    在这里插入图片描述

  • 那大家可能会问了,如何用参数来决定c到底是几呢?大家可以看到上述c=5和6的区别就是 ( c + 2 ∗ p − k ) m o d    s = 几 (c+2*p-k)mod\,\, s=几 (c+2pk)mods=,我们设置这个值为0就相当于告诉函数我们要c=5,设置=1就相当于告诉函数我们要c=6,决定权在我们自己,只需要告诉函数就好了。而这个值是通过output_padding这个参数来设置的。

  • 上述部分只是举了个例子,给你了一个卷积之后的feature map,它卷积前的大小有很多种可能,计算转置卷积的输出的大小的时候,因为有向下取整操作,所以卷积输出的大小是不确定的,所以我们必须告诉函数选哪个,而output_padding的设置就是为了避免这种不确定性的。

2.确定卷积核的值

  • 卷积核的确定方式主要有两种,一是通过双线性插值固定卷积核的参数,不随着学习过程更新;二是随机初始化,并随着学习过程更新。
  • 其实我个人感觉,后者更好一点,因为特征点对于中心的贡献程度并不一定是线性的。
  • 随机初始化就不说了,而双线性插值固定卷积核是关于x轴和y轴对称的,如下图所示:
    在这里插入图片描述
    生成代码:

def bilinear_kernel(in_channels, out_channels, kernel_size):
    factor = (kernel_size + 1) // 2
    if kernel_size % 2 == 1:
        center = factor - 1
    else:
        center = factor - 0.5
    og = np.ogrid[:kernel_size, :kernel_size]
    filt = (1 - abs(og[0] - center) / factor) * \
           (1 - abs(og[1] - center) / factor)
    weight = np.zeros((in_channels, out_channels, kernel_size, kernel_size),
                      dtype='float32')
    weight[range(in_channels), range(out_channels), :, :] = filt
    return torch.from_numpy(np.array(weight))

这个很好理解,因为卷积核执行卷积操作其实就相当于得到了一个 H o u t H_{out} Hout的元素,而卷积核的范围是有限的,它是越处于卷积核中间的元素对于 H o u t H_{out} Hout的元素的值的贡献越高,所以呈现一个圆峰状的卷积核矩阵形状。这是符合常理的,因为卷积核所笼罩的范围相对于 H i n H_{in} Hin的位置正是映射到 H o u t H_{out} Hout的元素相对于 H o u t H_{out} Hout的位置,
如下图所示
在这里插入图片描述
上面红框元素相对于 H o u t H_{out} Hout的位置就是下面红框相对于 H i n H_{in} Hin的位置(或者说相对于 H o u t H_{out} Houtpadding之后的矩阵的位置)。上面红框的值由下面红框的值来推测,推测手段就是线性插值方法,所以使用的卷积核是双线性卷积核,就是对卷积核笼罩的像素点进行双线性插值推测得到了对于卷积核笼罩的中心像素点的像素值。

  • 再直观一点讲,假如用H代表下面的padding之后的矩阵,那么问题就变成了已知 H 2 , 2 H_{2,2} H2,2 H 2 , 4 H_{2,4} H2,4 H 2 , 6 H_{2,6} H2,6 H 4 , 2 H_{4,2} H4,2 H 4 , 4 H_{4,4} H4,4 H 4 , 6 H_{4,6} H4,6 H 6 , 2 H_{6,2} H6,2 H 6 , 4 H_{6,4} H6,4 H 6 , 6 H_{6,6} H6,6,然后使用双线性插值推测 H 2 , 2 H_{2,2} H2,2—— H 2 , 6 H_{2,6} H2,6 H 3 , 2 H_{3,2} H3,2—— H 3 , 5 H_{3,5} H3,5 H 4 , 2 H_{4,2} H4,2—— H 4 , 5 H_{4,5} H4,5 H 5 , 2 H_{5,2} H5,2—— H 5 , 5 H_{5,5} H5,5 H 6 , 2 H_{6,2} H6,2—— H 6 , 5 H_{6,5} H6,5的值,其中有些值已经已知了。

3.执行卷积操作

  • 只需要注意下尺寸的问题就好:在这里插入图片描述
    在调用nn.ConvTranspose2d的时候注意参数满足上述公式。其中H_out是原始feature map的尺寸,而H_in是输入图像的尺寸,也就是目标尺寸,想要通过上采样达到的尺寸。

引用

  • https://www.freesion.com/article/53151034051/
  • https://www.cnblogs.com/wanghui-garcia/p/10791328.html
  • https://blog.csdn.net/jiongnima/article/details/78578876?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-6.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-6.control
  • https://www.freesion.com/article/5924530862/
  • 侵删
  • 90
    点赞
  • 176
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
nn.ConvTranspose2d是PyTorch中的一个类,用于实现反卷积操作。它的参数包括输入通道数(in_channels)、输出通道数(out_channels)、卷积核大小(kernel_size)、步长(stride)、填充(padding)、输出填充(output_padding)、分组数(groups)、是否使用偏置(bias)、扩张率(dilation)、填充模式(padding_mode)等。\[2\] 反卷积操作可以通过插值和卷积两步操作来实现。在插值操作中,可以选择是否进行插值和padding操作,具体取决于步长(stride)的大小。如果步长为1,则不进行插值操作,只进行padding操作;如果步长大于1,则进行插值操作。接下来执行卷积操作,将插值后的输入与转置后的权重进行卷积运算。最后,可以将反卷积操作转换为卷积操作。\[1\]\[3\] 需要注意的是,torch.nn.ConvTranspose2d默认权重的排布方式和torch.nn.Conv2d是不同的,需要进行重新排布再进行常规的卷积操作。可以使用相应的函数将反卷积操作转换为插值和卷积两步操作。\[1\] 总结起来,nn.ConvTranspose2d是用于实现反卷积操作的类,可以通过插值和卷积两步操作来实现。在转换为卷积操作时,需要注意权重的排布方式。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* *3* [反卷积torch.nn.ConvTranspose2d详解(含转换成卷积运算的代码示例)](https://blog.csdn.net/cc__cc__/article/details/121444692)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CtrlZ1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值