目录
前言
这篇文章是我根据 B 站 霹雳吧啦Wz 的《深度学习:语义分割篇章》中的 转置卷积(transposed convolution) 所作的学习笔记,涵盖内容如目录所示,希望能为正在学习语义分割的小伙伴们提供一些帮助ヾ(^▽^*))) 因为才刚刚开始接触语义分割,所以在表达上可能比较幼稚,希望王子公主们多多包涵啦!如果存在问题的话,请大家直接指出噢~
在做笔记的过程中,我还参考了这篇博客:语义分割|学习记录(2)转置卷积_coder_sure的博客-CSDN博客
一、什么是转置卷积
转置卷积的英文名称:transposed convolution(推荐)、fractionally-strided convolution、deconvolution(不推荐)。
转置卷积也是卷积,而不是卷积的逆运算,主要起到了 上采样 的作用。转置卷积与普通卷积的对比如下:
- 普通卷积(左)的 padding = 0 ,strides = 1 ,使用 3 x 3 的卷积核,输入 4 x 4 的图片,输出 2 x 2 的图片
- 转置卷积(右)的 padding = 0 ,strides = 1 ,使用 3 x 3 的卷积核,输入 2 x 2 的图片,输出 4 x 4 的图片
【补充】转置卷积的 padding 与普通卷积的 padding 不同,它是指上采样后的图对比原图是否进行了扩充。
【注意】转置卷积只是将特征层的大小还原回卷积之前的大小,其数值和卷积之前不同,因此转置卷积并非卷积的逆运算。
【拓展】如果小伙伴们想了解常见卷积的操作,可以参考这篇论文:A guide to convolution arithmetic for deep learning
二、转置卷积的运算步骤
转置卷积的运算步骤大致如下:
- 在输入特征图的元素间填充 s-1 行、列的 0
- 在输入特征图的四周填充 k-p-1 行、列的 0
- 将卷积核参数上下、左右翻转
- 做正常的卷积运算( 填充 0 ,步距 1 )
转置卷积的运算公式大致如下:
- 输出特征图的高
- 输出特征图的宽
【示例1】转置卷积: = 2 , = 2 , stride = 1 , padding = 0 , kernel_size = 3
- 输出特征图的高 = ( 2 - 1 ) x 1 - 2 x 0 + 3 = 4
- 输出特征图的宽 = ( 2 - 1 ) x 1 - 2 x 0 + 3 = 4
【示例2】转置卷积: = 2 , = 2 , stride = 2 , padding = 0 , kernel_size = 3
- 输出特征图的高 = ( 2 - 1 ) x 2 - 2 x 0 + 3 = 5
- 输出特征图的宽 = ( 2 - 1 ) x 2 - 2 x 0 + 3 = 5
【示例3】转置卷积: = 3 , = 3 , stride = 2 , padding = 1 , kernel_size = 3
- 输出特征图的高 = ( 2 - 1 ) x 2 - 2 x 1 + 3 = 5
- 输出特征图的宽 = ( 2 - 1 ) x 2 - 2 x 1 + 3 = 5
三、转置卷积的简单实例
因为视频教程中的 PPT 说明得非常清晰,所以我直接将其截图贴在下方啦 (๑•̀ㅂ•́)و✧ 相关笔记我用红框红字标出啦~
四、转置卷积的常见参数
1、torch.nn.ConvTranspose2d
torch.nn.ConvTranspose2d 官方文档:ConvTranspose2d — PyTorch 2.1 documentation
torch.nn.ConvTranspose2d 重要参数:
-
in_channels ( int ) – 输入图像的通道数
-
out_channels ( int ) – 通过卷积操作后,产生的输出图像的通道数
-
groups ( int, optional ) – 是否采用分组卷积,默认为 1 ,即普通卷积,若采用组卷积,设置为对应的组数即可
-
bias ( bool, optional ) – 偏置,代表卷积后的结果是否加减一个常数,默认为 True
-
dilation ( int or tuple, optional ) – 是否采用膨胀卷积(空洞卷积),卷积核之间的距离,默认为 1 ,即普通卷积
torch.nn.ConvTranspose2d 相关公式:
五、转置卷积的探究实例
1、普通卷积计算1(忽略偏置bias)
由于下图中的普通卷积计算比较常见,我就不再赘述啦,大家可以参考【三】的文字标注!
2、普通卷积计算2(忽略偏置bias)
实际上,计算机在做普通卷积计算时并不会采用逐个窗口滑动的形式,因为这样做的效率很低的哟 (´ー∀ー`) 它通常采用下面的方式计算:
【操作1】将卷积核转化为 卷积 kernel 等效矩阵 ,需先构造与输入 feature map 同样大小的全 0 矩阵,然后每滑动一步卷积核就可构造出一个等效矩阵,具体如图所示。最后将等效矩阵与输入 feature map 按对应位置相乘求和就可以得到输出 feature map 啦!
【操作2】将 输入 feature map 矩阵 展平,得到 1 x 16 的 矩阵 I ,如下图所示。
【操作3】将 卷积 kernel 等效矩阵 展平后转置,得到 16 x 4 的 矩阵 C ,如下图所示。
【操作4】将 矩阵 I 与 矩阵 C 进行矩阵相乘,得到 1 x 4 的 矩阵 O ,也就是 输出 feature map 矩阵 的展平,如下图所示。
3、逆向操作 & 转置卷积
进行到这里,我们已经知道矩阵 I 和 矩阵 C 相乘可以得到矩阵 O ,那如果已知矩阵 O 和矩阵 C ,是否可以反推得到矩阵 I 呢?答案当然是不能的,矩阵存在逆矩阵的条件包括 矩阵必须是方阵 ,显然这个条件 矩阵C 并不满足,由此也可见 卷积并不是可逆的 。
虽然我们无法通过反推得到矩阵 I ,但是我们可以通过两边都乘上 得到和矩阵 I 大小相同的矩阵 P ,将其 reshape 后就可以得到与卷积之前的输入 feature map 大小相同的矩阵啦!这也说明了转置卷积是一个 上采样 的过程 ( •̀ ω •́ )y
【补充】上面这两张图说明了转置卷积运算步骤中的第三步为何将卷积核参数上下、左右翻转。下面是转置卷积运算步骤的回顾图:
最后说些话
致亲爱的王子公主们:这篇文章中的部分语句可能比较绕口,也许会让大家看得有点不舒服 /(ㄒoㄒ)/~~ 主要是感觉这些理论稍微有些抽象,微臣不知该如何进行清晰的说明。在后面的创作过程中,微臣会尽量用比较简洁的语句来讲述!最后祝大家身体健康,生活顺利!