1. 转置卷积(Transposed Convolution)
论文:A guide to convolution arithmetic for deep learning
转置卷积(Transposed Convolution)也叫Fractionally-strided Convolution和Deconvolution,但用的最多的是Transposed Convolution。
Deconvolution这个名称是不建议使用的,因为该名称具有一定的误导性(和ZFNet的Deconvolution有歧义)。
1.1 注意事项
- 转置卷积不是卷积的逆运算
- 转置卷积也是一种卷积
1.2 转置卷积的目的
主要起到上采样(upsampling)的作用。
1.3 普通卷积与转置卷积的区别
1.3.1 普通卷积
1.3.2 转置卷积
对于这个转置卷积,输入是一个2×2的特征图,但是会在它的四周填充一些0元素,卷积核大小也是3×3,输出是一个4×4的特征图 -> 实现了特征图的上采样。
2. 转置卷积的运算步骤
- 在输入特征图元素间填充 行、列 的元素
- 在输入特征图四周填充 行、列的元素
- 将卷积核参数上下、左右翻转
- 做正常卷积运算(步长为1,填充为0)—— 此时不需要再对特征图进行填充了 —— 直接进行步长为1,padding为0的卷积运算
其中,为步长,为kernel size,为padding
2.1 几个例子
2.1.1 第一个例子:
- 在输入特征图元素间填充 行、列的元素 —— 不需要在特征图元素之间填充0元素
- 在输入特征图四周填充 行、列的元素 —— 在特征图四周填充2行2列的0元素
- 将卷积核参数上下、左右翻转
- 做正常卷积运算(步长为1,填充为0)—— 此时不需要再对特征图进行填充了 —— 直接进行步长为1,padding为0的卷积运算
2.1.2 第二个例子:
- 在输入特征图元素间填充 行、列的元素 —— 需要在特征图元素之间填充1行和1列0元素
- 在输入特征图四周填充 行、列的元素 —— 在特征图四周填充2行2列的0元素
- 将卷积核参数上下、左右翻转
- 做正常卷积运算(步长为1,填充为0)—— 此时不需要再对特征图进行填充了 —— 直接进行步长为1,padding为0的卷积运算
2.1.3 第三个例子:
- 在输入特征图元素间填充 行、列的元素 —— 需要在特征图元素之间填充1行和1列0元素
- 在输入特征图四周填充 行、列的元素 —— 在特征图四周填充1行1列的0元素
- 将卷积核参数上下、左右翻转
- 做正常卷积运算(步长为1,填充为0)—— 此时不需要再对特征图进行填充了 —— 直接进行步长为1,padding为0的卷积运算
2.2 输出特征图计算公式
2.2.1 普通卷积
2.2.2 空洞卷积
2.2.3 转置卷积
2.2.3.1 不带空洞卷积
2.2.3.2 带有空洞卷积
2.3 实例讲解转置卷积操作
- 先根据进行对应元素的填充
- 对kernel进行上下左右的翻转
- 普通卷积(stride=1, padding=0)
3. PyTorch中的转置卷积
通过在PyTorch官方的文档中可以看到,PyTorch内部集成了三种转置卷积:
torch.nn.ConvTranspose1d (Python class, in ConvTranspose1d)
torch.nn.ConvTranspose2d (Python class, in ConvTranspose2d)
torch.nn.ConvTranspose3d (Python class, in ConvTranspose3d)
以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)
在由多个输入平面组成的输入图像上应用 2D 转置卷积算子。
这个模块可以看作是 Conv2d 相对于其输入的梯度。 它也被称为分数步长卷积或反卷积(尽管它不是实际的反卷积操作,因为它不计算真正的卷积逆)。
该模块支持 TensorFloat32。
参数说明:
stride
controls the stride for the cross-correlation.
控制互相关的步幅 对于神经网络的卷积而言,互相关就是卷积运算(和信号与处理中的定义不同,区别在于后者会对卷积核进行上下左右翻转)
这里转置卷积用的是信号与处理中卷积的操作padding
controls the amount of implicit zero padding on both sides for dilation × (kernel_size – 1) – padding number of points. See note below for details.
控制膨胀两边的隐式 零填充量 × (kernel_size – 1) – 填充点数。output_padding
controls the additional size added to one side of the output shape. See note below for details. 默认为0
控制添加到输出形状一侧的附加大小
该参数一般是不会使用的dilation
controls the spacing between the kernel points; also known as the à trous algorithm. It is harder to describe, but the link here has a nice visualization of what dilation does.
控制内核点之间的间距;也称为 à trous 算法。很难描述,但这里的链接很好地可视化了扩张的作用 —— 就是空洞卷积的膨胀系数,默认为1(普通卷积)groups
controls the connections between inputs and outputs. in_channels and out_channels must both be divisible bygroups
.
控制输入和输出之间的连接。 in_channels 和 out_channels 都必须能被groups
整除。
For example,- At groups=1, all inputs are convolved to all outputs.
所有输入都卷积到所有输出 —— 传统的卷积 - At groups=2, the operation becomes equivalent to having two conv layers side by side, each seeing half the input channels and producing half the output channels, and both subsequently concatenated.
该操作等效于并排有两个卷积层,每个卷积层看到一半的输入通道并产生一半的输出通道,并且随后将两者连接起来 —— 组卷积 - At groups=
in_channels
, each input channel is convolved with its own set of filters (of size ). —— 深度卷积
每个输入通道都与自己的一组过滤器(大小为 )进行卷积
- At groups=1, all inputs are convolved to all outputs.
bias
如果为True则卷积操作会有一个可学习的偏置,默认为True
4. 转置卷积和普通卷积的运算过程对比
4.1 普通卷积 —— 滑动窗口
4.2 普通卷积 —— 另外一种计算方法
但在代码中真的是这样计算的吗? —— 并不是,因为这样计算效率低!更加高效的卷积操作如下:
注意:对于现在版本较新的框架如TensorFlow、PyTorch而言,这种计算方法也不再采用了,有更加高效的方法代替。
- 首先需要将卷积核转化为一个个的等效矩阵,过程如下:
- 对于每一个等效矩阵,首先构建一个与输入特征图同样大小的零矩阵
- 当滑动窗口第一次运算时,将滑动窗口中值(卷积核上的值)给刚才生成的零矩阵(也就是图中有红色的矩阵)
- 当滑动窗口向右滑动时,将滑动窗口中值(卷积核上的值)给刚才生成的零矩阵(也就是图中有黄色的矩阵)
- 当滑动窗口向下滑动时,将滑动窗口中值(卷积核上的值)给刚才生成的零矩阵(也就是图中有紫色的矩阵)
- 当滑动窗口向左滑动时,将滑动窗口中值(卷积核上的值)给刚才生成的零矩阵(也就是图中有绿色的矩阵)
- 此时就可以得到这4次滑动窗口的等效矩阵(也就是4个卷积核的等效矩阵)
- 针对每一个等效矩阵,将它与输入特征图进行和,就可以得到输出特征图的每一个数值
4.3 转置卷积运算
- 接下来将输入特征图进行展平,得到矩阵(向量) 。
- 再将刚刚构建的4个等效矩阵进行展平,得到矩阵 。
- 让矩阵和矩阵进行矩阵乘法,得到矩阵,矩阵中每一个数值就是输出特征图展平之后的结果
Q:已知矩阵和矩阵,是否可以求出矩阵?换句话说:卷积是否可逆?
将矩阵两边的右侧同时乘以矩阵的逆矩阵,那不就可以还原得到矩阵了吗?
—— 不可以!
A:需要注意的是,一个矩阵存在逆矩阵的条件是:它必须是一个方阵(非方阵没有逆矩阵,只有广义逆矩阵)。而这里的矩阵,并不是一个方阵,所以它不存在逆矩阵 -> 无法还原矩阵。
一般情况下,深度学习中的卷积是不可逆的。
Q:不要求还原原始输入矩阵,只想得到与输入矩阵相同大小的矩阵,可以吗?
A:可以。只需要在等号两边的右侧同时乘上矩阵的转置就可以了!运算如下:
很明显,矩阵和矩阵是不相等的。
对矩阵进行reshape处理就得到与输入特征图shape相同的特征图。
以上就是转置卷积的运算过程,即通过一个1×4的输入特征图(其实是一个2×2的特征图),得到一个4×4的输出特征图,完成了特征图的上采样。
这也就是为什么转置卷积会被成为Deconvolution,并非空穴来风😂。
4.4 另一种方式求 输入特征图的伪·逆矩阵
上面的操作是将输入和输出都展平成了一个向量,得到和。对于输入特征图的等效矩阵,将每一个等效矩阵也都展平了成一个列向量,并将它们拼接在一起,得到矩阵。
接下来进行逆向操作:
- 首先将矩阵还原为2×2的输入特征图
- 将矩阵的转置矩阵的每一列写成一个个2×2的等效矩阵(共16个)
- 将还原的2×2的特征图与的等效矩阵进行对应位置元素相乘和累加,得到矩阵每一个位置上的数值。
接下来看一下比较有趣的现象:
- 拿等效矩阵的第一个矩阵与输入特征图进行和,二者的结果为0,就是刚才我们求的伪·逆卷积的结果中的第一个值
看右下角,对于输入特征图先进行最外层的填充0,如果我们拿如图绿色的矩阵与其进行和,二者的结果也为0
-
接下来再拿等效矩阵的第一个矩阵与输入特征图进行和,二者的结果为2,就是刚才我们求的伪·逆卷积的结果中的第二个值
看右下角,对于输入特征图先进行最外层的填充0,如果我们拿如图绿色的矩阵与其进行和,二者的结果也为2 -
依次使用每一个等效矩阵与输入特征图进行运算
我们发现,我们可以通过绿色矩阵在填充过后的输入特征图上进行卷积,很轻松地求出伪·逆卷积的结果中的每一个值。
4.5 卷积核上下左右翻转的原因
问题来了:绿色的矩阵怎么得到呢?
我们看一下绿色的卷积和最开始的普通卷积的卷积核有什么区别和联系:
即实现了非常轻松的上采样!因为转置卷积后的矩阵就是输入矩阵的伪·逆矩阵!虽然信息有所丢失,但仍然有一定的联系。
这也就是为什么转置卷积运算的第四步,stride = 1,padding = 0。
5. 总结
- 转置卷积在大多数情况下起到的作用是上采样
- 转置卷积不是卷积的逆运算(Deconvolution)
- 转置卷积是一种卷积运算
参考
- https://www.bilibili.com/video/BV1mh411J7U4/?spm_id_from=333.788
- https://blog.csdn.net/qq_37541097/article/details/120709865
- https://github.com/vdumoulin/conv_arithmetic
- https://blog.csdn.net/tsyccnh/article/details/87357447
文章出处登录后可见!