抽丝剥茧,带你理解转置卷积(反卷积)

前言

转置卷积又叫反卷积、逆卷积。不过转置卷积是目前最为正规和主流的名称,因为这个名称更加贴切的描述了卷积的计算过程,而其他的名字容易造成误导。在主流的深度学习框架中,如TensorFlow,Pytorch,Keras中的函数名都是conv_transpose。所以学习转置卷积之前,我们一定要弄清楚标准名称,遇到他人说反卷积、逆卷积也要帮其纠正,让不正确的命名尽早的淹没在历史的长河中。

我们先说一下为什么人们很喜欢叫转置卷积为反卷积或逆卷积。首先举一个例子,将一个4x4的输入通过3x3的卷积核在进行普通卷积(无padding, stride=1),将得到一个2x2的输出。而转置卷积将一个2x2的输入通过同样3x3大小的卷积核将得到一个4x4的输出,看起来似乎是普通卷积的逆过程。就好像是加法的逆过程是减法,乘法的逆过程是除法一样,人们自然而然的认为这两个操作似乎是一个可逆的过程。但事实上两者并没有什么关系,操作的过程也不是可逆的。下面我们将一点一点的抽丝剥茧来深刻的理解转置卷积的思想。

普通卷积(直接卷积)

普通的卷积过程大家都很熟悉了,可以直观的理解为一个带颜色小窗户(卷积核)在原始的输入图像一步一步的挪动,来通过加权计算得到输出特征。 如下图。

在这里插入图片描述
但是实际在计算机中计算的时候,并不是像这样一个位置一个位置的进行滑动计算,因为这样的效率太低了。计算机会将卷积核转换成等效的矩阵,将输入转换为向量。通过输入向量和卷积核矩阵的相乘获得输出向量。输出的向量经过整形便可得到我们的二维输出特征。具体的操作如下图所示。由于我们的3x3卷积核要在输入上不同的位置卷积4次,所以通过补零的方法将卷积核分别置于一个4x4矩阵的四个角落。这样我们的输入可以直接和这四个4x4的矩阵进行卷积,而舍去了滑动这一操作步骤。
在这里插入图片描述
进一步的,我们将输入拉成长向量,四个4x4卷积核也拉成长向量并进行拼接,如下图。
在这里插入图片描述
我们记向量化的图像为 I I I ,向量化的卷积矩阵为 C C C, 输出特征向量为 O O O
则有:
I T ∗ C = O T I^T*C=O^T ITC=OT
如下图所示。
在这里插入图片描述
我们将一个1x16的行向量乘以16x4的矩阵,得到了1x4的行向量。那么反过来将一个1x4的向量乘以一个4x16的矩阵是不是就能得到一个1x16的行向量呢? 没错,这便是转置卷积的思想。

转置卷积

一般的卷积操作(我们这里只考虑最简单的无padding, stride=1的情况),都将输入的数据越卷越小。根据卷积核大小的不同,和步长的不同,输出的尺寸变化也很大。但是有的时候我们需要输入一个小的特征,输出更大尺寸的特征该怎么办呢?比如图像语义分割中往往要求最终输出的特征尺寸和原始输入尺寸相同,但在网络卷积核池化的过程中特征图的尺寸却逐渐变小。在这里转置卷积便能派上了用场。在数学上,转置卷积的操作也非常简单,把正常卷积的操作反过来即可。
对应上面公式,我们有转置卷积的公式:
O T ∗ C T = I T O^T*C^T=I^T OTCT=IT
如下图所示:
在这里插入图片描述
这里需要注意的是这两个操作并不是可逆的,对于同一个卷积核,经过转置卷积操作之后并不能恢复到原始的数值,保留的只有原始的形状。
所以转置卷积的名字就由此而来,而并不是“反卷积”或者是“逆卷积”,不好的名称容易给人以误解。

形象化的转置卷积

但是仅仅按照矩阵转置形式来理解转置卷积似乎有些抽象,不像直接卷积那样理解的直观。所以我们也来尝试一下可视化转置卷积。前面说了在将直接卷积向量化的时候是将卷积核补零然后拉成列向量,现在我们有了一个新的转置卷积矩阵,可以将这个过程反过来,把16个列向量再转换成卷积核。以第一列向量为例,如下图:
在这里插入图片描述
这里将输入还原为一个2x2的张量,新的卷积核由于只有左上角有非零值直接简化为右侧的形式。对每一个列向量都做这样的变换可以得到:
在这里插入图片描述
这是一个很有趣的结果,结合整体来看,仿佛有一个更大的卷积核在2x2大小的输入滑动。但是输入太小,每一次卷积只能对应卷积核的一部分。我们来把更大的卷积核补全,如下图:
在这里插入图片描述
这里和直接卷积有很大的区别,直接卷积我们是用一个“小窗户”去看一个“大世界”,而转置卷积是用一个“大窗户”的一部分去看“小世界”。这里有一点需要注意,我们定义的卷积核是左上角为a,右下角为i,但在可视化转置卷积中,需要将卷积核旋转180°后再进行卷积。由于输入图像太小,我们按照卷积核尺寸来进行补零操作,每边的补零数量显而易见是2,即3-1。这样我们就将一个转置卷积操作转换为对应的直接卷积。如下图:

在这里插入图片描述
总结一下将转置卷积转换为直接卷积的步骤:(这里只考虑stride=1,padding=0的情况)
设卷积核大小为k*k,输入为方形矩阵

  1. 对输入进行四边补零,单边补零的数量为k-1
  2. 将卷积核旋转180°,在新的输入上进行直接卷积

对上面的结论我们在TensorFlow中验证一下。
验证实验代码:

首先调用TensorFlow的conv_transpose函数来进行转置卷积

import tensorflow as tf

x = tf.reshape(tf.constant([[1,2],
                            [4,5]],dtype=tf.float32), [1, 2, 2, 1])
kernel = tf.reshape(tf.constant([[1,2,3],
                                 [4,5,6],
                                 [7,8,9]],dtype=tf.float32), [3, 3, 1, 1])
transpose_conv = tf.nn.conv2d_transpose(x, kernel, output_shape=[1, 4, 4, 1], strides=[1,1,1,1], padding='VALID')
sess = tf.Session()
print(sess.run(x))
print(sess.run(kernel))
print(sess.run(transpose_conv))

输出结果如下:

tf转置卷积
input:  1 2
        4 5
kernel: 1 2 3
        4 5 6
        7 8 9
output: 1  4  7  6
        8  26 38 27
        23 62 74 48
        28 67 76 45

接下来按照上面的方式,将转置卷积转换为一个等效的直接卷积

# 转换为等效普通卷积
x2 = tf.reshape(tf.constant([[0, 0, 0, 0, 0, 0],
                             [0, 0, 0, 0, 0, 0],
                             [0, 0, 1, 2, 0, 0],
                             [0, 0, 4, 5, 0, 0],
                             [0, 0, 0, 0, 0, 0],
                             [0, 0, 0, 0, 0, 0]],dtype=tf.float32), [1, 6, 6, 1])
kernel2  = tf.reshape(tf.constant([[9,8,7],
                                   [6,5,4],
                                   [3,2,1]],dtype=tf.float32), [3, 3, 1, 1])
conv = tf.nn.conv2d(x2,kernel2,strides=[1,1,1,1],padding='VALID')

print(sess.run(x2))
print(sess.run(kernel2))
print(sess.run(conv))

输出结果和转置卷积相同

等效直接卷积
input:  0 0 0 0 0 0
补零     0 0 0 0 0 0
        0 0 1 2 0 0
        0 0 4 5 0 0
        0 0 0 0 0 0
        0 0 0 0 0 0

kernel:    9 8 7
旋转180度   6 5 4
           3 2 1
output:  1  4  7  6
输出不变   8  26 38 27
         23 62 74 48
         28 67 76 45

实验结果和我们的预测一致。

总结

通过这一篇文章,仔细的梳理的了转置卷积由来以及其等效的直接卷积形式。希望以后在使用转置卷积的过程中可以做到心中有数,有画面。有关其他不同参数的转置卷积还有很多,比如当stride不为1时怎么办,padding不为0时怎么办。关于这些细节的讨论建议可以去参看参考文献:https://arxiv.org/pdf/1603.07285.pdf 。这里作者做了更加详尽的讨论,这里就不赘述了。

参考

https://arxiv.org/pdf/1603.07285.pdf
https://iksinc.online/tag/transposed-convolution/
https://zhuanlan.zhihu.com/p/48501100
https://blog.csdn.net/silence2015/article/details/78649734
https://blog.csdn.net/u014722627/article/details/60574260

<think>好的,我需要回答用户关于转置卷积反卷积的区别及应用场景的问题。首先,我得回顾一下用户提供的引用内容,特别是引用[2]和引用[3],因为这两个引用直接提到了这两个概念。 根据引用[2],反卷积(Deconvolution)这个术语最早出现在Zeiler的论文中,用于神经网络的可视化。而转置卷积(Transposed Convolution)和分数步长卷积(Fractional Strided Convolution)是反卷积的其他名称。这里似乎指出转置卷积反卷积是同一个概念的不同叫法,但用户的问题是关于它们的区别,所以可能存在需要澄清的地方。 接下来,引用[3]提到,反卷积在CNN可视化中实际上是卷积转置操作,而不是数学上的逆运算。同时,转置卷积在这里被用作上采样的一种方法,比如在图像分割或生成模型中。这暗示转置卷积可能更多是指技术实现中的转置操作,而反卷积可能是一个更广泛的概念,但有时候被混用。 我需要明确区分这两个术语。根据我的知识,转置卷积在数学上是通过对卷积核进行转置并使用步长来扩大输入尺寸的操作,而反卷积在数学上本应是卷积的逆运算,但在深度学习中通常指的是转置卷积。可能存在术语的混淆,需要指出这一点。 应用场景方面,引用[3]提到了三个方面:无监督学习中的稀疏编码、CNN可视化和上采样。转置卷积主要用于上采样和生成模型,而反卷积在文献中有时可能指不同的操作,但实际使用中两者常被混用。 因此,我的回答需要明确: 1. 转置卷积反卷积深度学习中的常见用法,指出它们的区别更多是术语上的,但有时可能有不同含义。 2. 转置卷积的具体数学操作和应用场景。 3. 反卷积在数学上的原始意义与深度学习中的实际应用的区别。 4. 应用场景如生成模型、图像分割等。 需要确保回答结构清晰,分点说明概念、区别和应用场景,并正确使用LaTeX格式,引用用户提供的引用内容,并在末尾添加相关问题。</think>### 转置卷积反卷积的区别及应用场景 #### 1. **基本概念** - **转置卷积(Transposed Convolution)** 是一种通过调整卷积核的排列方式实现输入特征图尺寸放大的操作。数学上,其核心是**对标准卷积的矩阵运算进行转置**。例如,标准卷积的矩阵形式为$Y = WX + b$,则转置卷积可表示为$X' = W^T Y'$。它通过填充(padding)和步长(stride)的调整实现上采样,常用于图像生成或分割任务[^2][^3]。 - **反卷积(Deconvolution)** 在数学上本应指卷积运算的逆运算(即解卷积),但在深度学习中这一术语常被**误用**为转置卷积的同义词。例如,Zeiler在CNN可视化中使用的“反卷积”实质是转置卷积操作,而非数学上的逆运算[^2][^3]。 #### 2. **核心区别** | 特性 | 转置卷积 | 反卷积(数学定义) | |---------------------|-----------------------------------|-----------------------------------| | **数学本质** | 卷积核的转置运算 | 严格意义上的卷积逆运算 | | **实现目标** | 上采样或特征图尺寸放大 | 从输出恢复原始输入信号 | | **深度学习中的应用**| 广泛用于生成模型、图像分割等任务 | 极少直接使用,多被转置卷积替代 | #### 3. **应用场景** - **转置卷积的典型应用** - **图像生成**:如GAN中生成高分辨率图像,通过转置卷积逐步扩大特征图尺寸。 - **语义分割**:在U-Net等模型中,通过转置卷积恢复空间分辨率以实现像素级预测。 - **特征可视化**:将深层特征映射回像素空间,解释网络的学习模式[^3]。 - **反卷积的原始意义** 数学上的反卷积在信号处理中用于去模糊或消除卷积效应,但在深度学习中几乎不直接应用,仅作为术语与转置卷积混淆使用[^2][^3]。 #### 4. **实现对比** - **转置卷积的步长与填充** 若标准卷积的步长为$s$,转置卷积通过插入$s-1$个零实现输入扩大。例如,输入尺寸为$n$,输出尺寸为$n' = s(n-1) + k$($k$为卷积核大小)[^3]。 - **代码示例(PyTorch)** ```python import torch.nn as nn # 转置卷积层:输入通道1,输出通道1,核大小3,步长2 transposed_conv = nn.ConvTranspose2d(1, 1, kernel_size=3, stride=2) ``` ---
评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值