阅读本文的基础,是默认已经理解了图像处理中正向卷积的过程 (卷积特征提取 - UFLDL)。


什么是反卷积?

  • 上采样 (Upsample)

在应用在计算机视觉的深度学习领域,由于输入图像通过卷积神经网络 (CNN) 提取特征后,输出的尺寸往往会变小,而有时我们需要将图像恢复到原来的尺寸以便进行进一步的计算(e.g.: 图像的语义分割),这个采用扩大图像尺寸,实现图像由小分辨率到大分辨率的映射的操作,叫做上采样(Upsample)。

  • 反卷积 (Transposed Convolution)

上采样有 3 种常见的方法:双线性插值 (bilinear),反卷积 (Transposed Convolution),反池化 (Unpooling),我们这里只讨论反卷积。这里指的反卷积,也叫转置卷积,它并不是正向卷积的完全逆过程,用一句话来解释:

反卷积是一种特殊的正向卷积,先按照一定的比例通过补 反卷积(Transposed Convolution)详细推导 - 知乎 - 图1
来扩大输入图像的尺寸,接着旋转卷积核,再进行正向卷积。


反卷积的数学推导

  • 正向卷积的实现过程

假设输入图像 反卷积(Transposed Convolution)详细推导 - 知乎 - 图2
尺寸为 反卷积(Transposed Convolution)详细推导 - 知乎 - 图3
,元素矩阵为:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图4

卷积核 反卷积(Transposed Convolution)详细推导 - 知乎 - 图5
尺寸为 反卷积(Transposed Convolution)详细推导 - 知乎 - 图6
,元素矩阵为:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图7

步长 反卷积(Transposed Convolution)详细推导 - 知乎 - 图8
,填充 反卷积(Transposed Convolution)详细推导 - 知乎 - 图9
,即 反卷积(Transposed Convolution)详细推导 - 知乎 - 图10

则按照卷积计算公式 反卷积(Transposed Convolution)详细推导 - 知乎 - 图11
,输出图像 反卷积(Transposed Convolution)详细推导 - 知乎 - 图12
的尺寸为 反卷积(Transposed Convolution)详细推导 - 知乎 - 图13

  • 用矩阵乘法描述卷积

反卷积(Transposed Convolution)详细推导 - 知乎 - 图14
的元素矩阵展开成一个列向量 反卷积(Transposed Convolution)详细推导 - 知乎 - 图15

反卷积(Transposed Convolution)详细推导 - 知乎 - 图16

把输出图像 反卷积(Transposed Convolution)详细推导 - 知乎 - 图17
的元素矩阵展开成一个列向量 反卷积(Transposed Convolution)详细推导 - 知乎 - 图18

反卷积(Transposed Convolution)详细推导 - 知乎 - 图19

对于输入的元素矩阵 反卷积(Transposed Convolution)详细推导 - 知乎 - 图20
和 输出的元素矩阵 反卷积(Transposed Convolution)详细推导 - 知乎 - 图21
,用矩阵运算描述这个过程:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图22

通过推导,我们可以得到稀疏矩阵 反卷积(Transposed Convolution)详细推导 - 知乎 - 图23
反卷积(Transposed Convolution)详细推导 - 知乎 - 图24

反卷积的操作就是要对这个矩阵运算过程进行逆运算,即通过 反卷积(Transposed Convolution)详细推导 - 知乎 - 图25
反卷积(Transposed Convolution)详细推导 - 知乎 - 图26
得到 反卷积(Transposed Convolution)详细推导 - 知乎 - 图27
,根据各个矩阵的尺寸大小,我们能很轻易的得到计算的过程,即为反卷积的操作:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图28

但是,如果你代入数字计算会发现,反卷积的操作只是恢复了矩阵 反卷积(Transposed Convolution)详细推导 - 知乎 - 图29
的尺寸大小,并不能恢复 反卷积(Transposed Convolution)详细推导 - 知乎 - 图30
的每个元素值,本文最后会在 tensorflow 平台进行这个实验。

在此之前,我们先给出反卷积图像尺寸变化的公式。

  • 反卷积的输入输出尺寸关系

在进行反卷积时,简单来说,大体上可分为以下两种情况:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图31

Relationship 1:反卷积(Transposed Convolution)详细推导 - 知乎 - 图32

此时反卷积的输入输出尺寸关系为:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图33

反卷积(Transposed Convolution)详细推导 - 知乎 - 图34

如上图所示,我们选择一个输入 反卷积(Transposed Convolution)详细推导 - 知乎 - 图35
尺寸为 反卷积(Transposed Convolution)详细推导 - 知乎 - 图36
,卷积核 反卷积(Transposed Convolution)详细推导 - 知乎 - 图37
尺寸为 反卷积(Transposed Convolution)详细推导 - 知乎 - 图38
,步长 反卷积(Transposed Convolution)详细推导 - 知乎 - 图39
,填充 反卷积(Transposed Convolution)详细推导 - 知乎 - 图40
,即 反卷积(Transposed Convolution)详细推导 - 知乎 - 图41
,则输出 反卷积(Transposed Convolution)详细推导 - 知乎 - 图42
的尺寸为 反卷积(Transposed Convolution)详细推导 - 知乎 - 图43

Relationship 2: 反卷积(Transposed Convolution)详细推导 - 知乎 - 图44

此时反卷积的输入输出尺寸关系为:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图45

反卷积(Transposed Convolution)详细推导 - 知乎 - 图46

如上图所示,我们选择一个输入 反卷积(Transposed Convolution)详细推导 - 知乎 - 图47
的尺寸为 反卷积(Transposed Convolution)详细推导 - 知乎 - 图48
,卷积核 反卷积(Transposed Convolution)详细推导 - 知乎 - 图49
的尺寸为 反卷积(Transposed Convolution)详细推导 - 知乎 - 图50
,步长 反卷积(Transposed Convolution)详细推导 - 知乎 - 图51
,填充 反卷积(Transposed Convolution)详细推导 - 知乎 - 图52
,即 反卷积(Transposed Convolution)详细推导 - 知乎 - 图53
,则输出 反卷积(Transposed Convolution)详细推导 - 知乎 - 图54
的尺寸为反卷积(Transposed Convolution)详细推导 - 知乎 - 图55

  • 反卷积在 FCN 中的应用

在图像语义分割网络 FCN-32s 中,上采样反卷积操作的输入每张 {\E heatmap} 的尺寸是 反卷积(Transposed Convolution)详细推导 - 知乎 - 图56
,我们希望进行一次上采样后能恢复成原始图像的尺寸 反卷积(Transposed Convolution)详细推导 - 知乎 - 图57
,代入公式:
反卷积(Transposed Convolution)详细推导 - 知乎 - 图58

根据上式,我们可以得到一个关于 反卷积(Transposed Convolution)详细推导 - 知乎 - 图59
三者之间关系的等式:
反卷积(Transposed Convolution)详细推导 - 知乎 - 图60

通过实验,最终找出了最合适的一组数据:
反卷积(Transposed Convolution)详细推导 - 知乎 - 图61


在 tensorflow 中实现反卷积

  • 反卷积的具体计算步骤

下面我们用一组实验更直观的解释一下在 tensorflow 中反卷积的过程:

我们令输入图像为:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图62

卷积核为:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图63

case 1

如果要使输出的尺寸是 反卷积(Transposed Convolution)详细推导 - 知乎 - 图64
,步数 反卷积(Transposed Convolution)详细推导 - 知乎 - 图65
,tensorflow 中的命令为:

  1. transpose_conv = tf.nn.conv2d_transpose(value=input,
  2. filter=kernel,
  3. output_shape=[1,5,5,1],
  4. strides=2,
  5. padding='SAME')

当执行 transpose_conv 命令时,tensorflow 会先计算卷积类型、输入尺寸、步数和输出尺寸之间的关系是否成立,如果不成立,会直接提示错误,如果成立,执行如下操作:

  1. 现根据步数 反卷积(Transposed Convolution)详细推导 - 知乎 - 图66
    对输入的内部进行填充,这里 反卷积(Transposed Convolution)详细推导 - 知乎 - 图67
    可以理解成输入放大的倍数,即在 反卷积(Transposed Convolution)详细推导 - 知乎 - 图68
    的每个元素之间填充 反卷积(Transposed Convolution)详细推导 - 知乎 - 图69
    反卷积(Transposed Convolution)详细推导 - 知乎 - 图70
    的个数 反卷积(Transposed Convolution)详细推导 - 知乎 - 图71
    反卷积(Transposed Convolution)详细推导 - 知乎 - 图72
    的关系为:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图73

例如这里举例的 反卷积(Transposed Convolution)详细推导 - 知乎 - 图74
,即在 反卷积(Transposed Convolution)详细推导 - 知乎 - 图75
的每个元素之间填 反卷积(Transposed Convolution)详细推导 - 知乎 - 图76
反卷积(Transposed Convolution)详细推导 - 知乎 - 图77

反卷积(Transposed Convolution)详细推导 - 知乎 - 图78

因为卷积类型为 same,所以此时, 反卷积(Transposed Convolution)详细推导 - 知乎 - 图79

  1. 接下来,用卷积核 反卷积(Transposed Convolution)详细推导 - 知乎 - 图80
    对填充后的输入 反卷积(Transposed Convolution)详细推导 - 知乎 - 图81
    进行步长 反卷积(Transposed Convolution)详细推导 - 知乎 - 图82
    的正向卷积,根据正向卷积输出尺寸公式: 反卷积(Transposed Convolution)详细推导 - 知乎 - 图83
    得到输出尺寸是 反卷积(Transposed Convolution)详细推导 - 知乎 - 图84
    ,反卷积公式中我们给出的输出尺寸参数 反卷积(Transposed Convolution)详细推导 - 知乎 - 图85
    也是为 反卷积(Transposed Convolution)详细推导 - 知乎 - 图86
    ,两者相同,所以可以进行计算,结果为:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图87

与 tensorflow 的运行结果相同。

case 2

我们将 case 1 中的输出尺寸 反卷积(Transposed Convolution)详细推导 - 知乎 - 图88
改成 反卷积(Transposed Convolution)详细推导 - 知乎 - 图89
,其他参数均不变,tensorflow 中的命令为:

  1. transpose_conv = tf.nn.conv2d_transpose(value=input,
  2. filter=kernel,
  3. output_shape=[1,6,6,1],
  4. strides=2,
  5. padding='SAME')

卷积类型是 same,我们首先在外围填充一圈 反卷积(Transposed Convolution)详细推导 - 知乎 - 图90

反卷积(Transposed Convolution)详细推导 - 知乎 - 图91

这时发现,填充后的输入尺寸与 反卷积(Transposed Convolution)详细推导 - 知乎 - 图92
的卷积核卷积后的输出尺寸是 反卷积(Transposed Convolution)详细推导 - 知乎 - 图93
,没有达到 反卷积(Transposed Convolution)详细推导 - 知乎 - 图94
反卷积(Transposed Convolution)详细推导 - 知乎 - 图95
,这就需要继续填充 反卷积(Transposed Convolution)详细推导 - 知乎 - 图96
,tensorflow 的计算规则是优先在左侧和上侧填充一排 反卷积(Transposed Convolution)详细推导 - 知乎 - 图97
,填充后的输入变为:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图98

接下来,再对这个填充后的输入与 反卷积(Transposed Convolution)详细推导 - 知乎 - 图99
的卷积核卷积,结果为:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图100

与 tensorflow 的运行结果相同。

  • 反卷积只能恢复尺寸,不能恢复数值

最后,我们要验证一下前文中提到的 “如果你代入数字计算会发现,反卷积的操作只是恢复了矩阵 反卷积(Transposed Convolution)详细推导 - 知乎 - 图101
的尺寸大小,并不能恢复 反卷积(Transposed Convolution)详细推导 - 知乎 - 图102
的每个元素值”。

  1. 正向卷积:
    value = tf.reshape(tf.constant([[1., 2., 3.],
    [4., 5., 6.],
    [7., 8., 9.]]),
    [1, 5, 5, 1])
    filter = tf.reshape(tf.constant([[1., 0.],
    [0., 1.]]),
    [2, 2, 1, 1])
    output = tf.nn.conv2d(value, filter, [1, 2, 2, 1], ‘SAME’)

卷积的结果是:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图103

  1. 我们用和正向卷积完全相同的参数对这个结果进行反卷积:
    input = tf.reshape(tf.constant([[6., 8., 3.],
    [12., 14., 6.],
    [7., 8., 9.]]),
    [1, 3, 3, 1])
    kernel = tf.reshape(tf.constant([[1., 0.],
    [0., 1.]]),
    [2, 2, 1, 1])
    output = tf.nn.conv2d_transpose(value=input,
    filter=kernel,
    output_shape=[1, 3, 3, 1],
    strides=[1, 2, 2, 1],
    padding=’SAME’)

卷积的结果是:

反卷积(Transposed Convolution)详细推导 - 知乎 - 图104

可见,反卷积不能恢复数值,而且,在当 反卷积(Transposed Convolution)详细推导 - 知乎 - 图105
时,即便使用完全相同的参数进行转置卷积,输入的尺寸也不能恢复。

参考文献

Dumoulin V, Visin F. A guide to convolution arithmetic for deep learning[J]. arXiv preprint arXiv:1603.07285, 2016.
https://zhuanlan.zhihu.com/p/48501100