Skip to content

Instantly share code, notes, and snippets.

@YimianDai
Last active May 19, 2020 03:46
Show Gist options
  • Save YimianDai/567ed33454715e9a5b48669eeec8a898 to your computer and use it in GitHub Desktop.
Save YimianDai/567ed33454715e9a5b48669eeec8a898 to your computer and use it in GitHub Desktop.
Transposed Convolution

卷积的矩阵运算形式

要了解转置卷积,先要了解 卷积 的矩阵运算形式,因为转置是矩阵转置的意思。通常我们对卷积的认识就是按照卷积的定义来的,输入信号和卷积核依次匹配过去。如果是 4x4 的输入,卷积 Kernel 为 3x3, 没有 Padding / Stride, 则输出为 2x2,如下图所示。

但是,事实上,按照卷积的定义来实现卷积运算的话是非常低效的。在神经网络中,其实是用矩阵运算的形式实现的。那么卷积可以用矩阵运算的形式来实现吗?当然可以。卷积是线性运算,线性运算都可以写作矩阵乘法的形式。具体来看,

  1. 输入信号 4 x 4 的矩阵可展开为 16 维向量,记作 $x$
  2. 输出矩阵可展开为 4 维向量,记作 $y$
  3. 卷积运算可以表示为 $y = Cx$
  4. $C$ 是 3 x 3 的卷积核转化来的稀疏矩阵,大小为 16 x 4,即输入信号长度 x 输出信号长度。输出信号的每一个数值,都是输入信号 与 同输入信号相同大小的卷积权重矩阵 点乘后的结果。卷积权重矩阵大小不是 3 x 3 的卷积核大小,而是同输入信号大小相同。不同的输出信号上的点,只是权重在 卷积权重矩阵 上平移。这里平移的顺序是先从左到右,到最右后再换下一行(先从左向右,再从上到下)。$C$ 具体的元素如下所示。可以看到,这个矩阵其实是以第一行为标准,然后依次向右循环移位,这个矩阵叫作 Toeplitz matrix。注意,输出信号并不是 column-first 拉成的向量,而是 row-first 拉成的向量。
  5. 上面的 case 是没有 padding,stride = 1 的情形,先来看有 padding 会怎么样?padding 的话,相当于改变输入信号,如果 padding = 2,那么 4 x 4 的输入信号就变成 8 x 8 的矩阵,填充的都是 0。相应的,卷积权重矩阵也要变成 8 x 8 = 81,而真正非 0 的权重系数还是只有 3 x 3 = 9,因此 padding 会让 卷积权重矩阵 变得更大,也更加 sparse。
  6. Stride = 2 会怎么样?卷积权重矩阵这个 Toeplitz matrix 中的行向量平移不再是逐个平移了,对于从左向右的平移,变成一次平移两个;如果换行从上到下,则要多平移一行。

至此,我们来小结一下,卷积核 c,卷积运算 y = x * c 可以写作 y = C x 的矩阵形式,这里 C 的具体取值由 c 给定。

  1. 输入转为列矩阵
  2. weight 通过 toeplitz 规律转化为矩阵
  3. 相乘后的列矩阵再排回结果;

为“反”卷积的“反”正名

虽然很多时候 Transposed Convolution 也会被叫作 反卷积,但是其实这么叫是错误的。真正的反卷积的意思是,给定卷积的输出信号,还原出未知的输入信号。这里“反”卷积的反的意思并不在意还原输入信号,“反”的意思在于正常卷积 output 的 size 小于等于 input 的 size,而转置卷积(“反”卷积)通常是 output 的 size 大于等于 input 的 size,这个反就是尺寸大小变化相反的意思。事实上,转置卷积只能还原 shape 大小,不能还原 value.

重新写完后再来理解“反”卷积,我感觉这个反还可以理解成 输入信号 和 卷积核 交换,正常是 卷积核 移动分别点乘输入信号;反卷积可以是 卷积核不动,输入信号变成新的卷积核来移动,输入信号 和 卷积核 的角色刚好相反,对调了一下。

“反”卷积这个错误用法的来源:第一篇用 deconv 表示 transposed convolution 的是 ZF 的 Visualizing and Understanding Convolutional Neural Networks,论文提出了 ZFNet,而且是 ImageNet 2013 年的 winner,比较有影响力,之后大家就错误的用下去了 from https://www.zhihu.com/question/43609045/answer/135914409

通过卷积,小尺寸的 input 怎么变成大尺寸的 output?

Convolution arithmetic tutorial 这里有很详细的大小关系叙述。

那么通过卷积,怎么可以让小尺寸的 input 怎么变成大尺寸的 output?先看一下下面两幅图像的例子。 看下面 Transposed convolution 的动画,和上面 Convolution 的动画其实没有什么区别,都是 灰色的卷积核在移动,蓝色以及虚线的pad为输入,依次点积后就得到绿色的输出。两幅 GIF 唯一的差别就是正常 Convolution 是输入比较大,输出比较小,而 Transposed convolution 是输入比较小,输出比较大,怎么实现这种由小变大呢?

No padding, no strides, transposed No padding, strides, transposed

我们从普通卷积的角度来看,由上图可见,可以通过 Padding 和对 input 插 0 来实现。

以前面那副画为例,那就是从 2 x 2 的输入 Pad 成 6 x 6 的矩阵,那相应的 3 x 3 的卷积核变成 16 x 36 的卷积权重矩阵。

  1. 输入信号 2 x 2 => 6 x 6
  2. 3 x 3 的卷积核 => 16 x 36 卷积权重矩阵
  3. 输出信号 4 x 4 => 16 x 1: 16 x 1 = (16 x 36) x (36 x 1)

以后面那副画为例,那就是从 2 x 2 的输入通过 Pad 和 插 0 变成 7 x 7 的矩阵,那相应的 3 x 3 的卷积核变成 25 x 49 的卷积权重矩阵,这种方式实现的计算效率太低了,因为需要 pad 太多 0 了。

  1. 输入信号 2 x 2 => 7 x 7
  2. 3 x 3 的卷积核 => 25 x 49 卷积权重矩阵
  3. 输出信号 5 x 5 => 25 x 1: 25 x 1 = (25 x 49) x (49 x 1)

下图,我们把左图卷积出来的前 3 个输出 x1, x2, x3 是怎么得到的单独画出来,如下图所示。

那有上述图片过程的更简洁的描述方式吗?有,就是 $x = C^T y$。具体的来说,我们抛弃 3 x 3 卷积核在 Padding 后的 Input 移动的看法,而是固定 3 x 3 的卷积核不动,而是 2 x 2 的 Input 在卷积核上移动,考虑到 2 x 2 的输入变成了新卷积核,3 x 3 的原卷积核现输入信号要 Pad 成 5 x 5,因此输出会是 4 x 4。具体的示意图如下,卷积核旋转 180 度来的,然后 2 x 2 的输入信号是从右到左、从下到上依次移动过去。所以,是对 5 x 5 的 Pad 后的原卷积核、现输入信号 从右到左、从下到上 的采样,大小为 2 x 2。

要变大多一些,主要靠插 0(也就是 stride)。

那这种卷积 也可以用 矩阵乘法形式实现吗?

转置卷积

当然可以用矩阵乘法形式实现,形式恰恰是 x = C^T y,可以看一下下面 D.T 的前几行是不是刚好对应着上面图像里的权重。因此,转置卷积这个名字,更确切的说法应该是卷积核对应矩阵的转置,所以转置 transposed 这个词应该是这么来的。但事实上,D 是可以学习的,不一定一定就是卷积的转置。y = Cx,C 为 4 x 16,希望有一个新的矩阵 D,形状为 16 x 4,使得 x = Dy,事实上 D 只是和 C 转置的形状大小一样,并不是说 D 就是 C 的转置本身。除非 C 是正交矩阵,才可能 x = C^T y = C^T C x,但 C 不可能是正交矩阵,所以 D 肯定不是 C^T,只是两者形状一样而已。

>>> C  
Matrix([
[w_00, w_01, w_02,    0, w_10, w_11, w_12,    0, w_20, w_21, w_22,    0,    0,    0,    0,    0],
[   0, w_00, w_01, w_02,    0, w_10, w_11, w_12,    0, w_20, w_21, w_22,    0,    0,    0,    0],
[   0,    0,    0,    0, w_00, w_01, w_02,    0, w_10, w_11, w_12,    0, w_20, w_21, w_22,    0],
[   0,    0,    0,    0,    0, w_00, w_01, w_02,    0, w_10, w_11, w_12,    0, w_20, w_21, w_22]])
>>> C.T
Matrix([
[w_00,    0,    0,    0],
[w_01, w_00,    0,    0],
[w_02, w_01,    0,    0],
[   0, w_02,    0,    0],
[w_10,    0, w_00,    0],
[w_11, w_10, w_01, w_00],
[w_12, w_11, w_02, w_01],
[   0, w_12,    0, w_02],
[w_20,    0, w_10,    0],
[w_21, w_20, w_11, w_10],
[w_22, w_21, w_12, w_11],
[   0, w_22,    0, w_12],
[   0,    0, w_20,    0],
[   0,    0, w_21, w_20],
[   0,    0, w_22, w_21],
[   0,    0,    0, w_22]])

因此,不管是从卷积的角度还是矩阵乘法的角度,转置卷积 和 正常卷积 基本没有区别,都是要设置 size,stride,channel,padding 这些,唯一的区别是正常卷积output 的 size 小于等于 input 的 size,而 转置卷积 通常是 output 的 size 大于等于 input 的 size。Transposed Convolution 就是 Convolution 而已,之所以叫 Transposed,就是形状是转置而已。

给定 Input 和 Output 大小,怎么设置 Kernel 大小、Pad 大小和 Stride?

对于正向卷积,给定输入信号大小 I,卷积核大小为 K,Pad 大小为 P,Stride 大小为 S,则输出信号的大小 O = Ceil([(I + 2P) - (K-1)] / S),发现一个更好的公式是 $O = \frac{I + 2P - K}{S} + 1$

如果正常卷积的 Stride S = 1, Pad P = 0, 卷积核大小为 K,那么转置卷积的卷积核大小 K' = K, S' = S, P' = K - 1,如果转置卷积的输入大小是 I',那么转置卷积的输出的大小 O' = I' + 2(K - 1) - (K' - 1)

  1. 如果 $(O' + 2P' - K') % S' = 0$,则 $O' = S' (I' - 1) - 2P' + K'$
  2. 如果 $(O' + 2P' - K') % S' \neq 0$,则 $O' = S' (I' - 1) - 2P' + K' + (O' + 2P' - K') % S'$ 通用公式:

公式关系为正向卷积 s=1,p=0 那么转置卷积的 k'=k,s'=s,p'=k-1, 转置卷积的输出尺寸

转置卷积与 UpSampling 的区别

转置卷积 和 UpSampling 都可以把小的 Input 变成大的 Output,那么两者有什么区别呢?哪个更好呢?

  1. UpSampling 可以看作是 Pooling 的反向操作,就是采用 Nearest Neighbor interpolation 来进行放大、Resize,说白了就是复制行和列的数据来扩充 feature map 的大小,并不通过学习。
  2. 转置卷积(反卷积)就是卷积,想要把小的 Input 变成大的 Output,做法是通过对输入隔行补 0、pading 等方式,实现输出尺寸增大。转置卷积里面的 filter 都是可以学出来的,本质上是一种 Learnable Upsampling。

也有说法把 UpSampling 囊括为 Resize 和 转置卷积 这两类,这样的话 UpSampling 就是一个更大的概念了。

需要注意的是,FCN 中并没有使用转置卷积,FCN 是用的 UpSampling,具体的说是 bilinear interpolation,这也是造成 FCN 不能很好的处理边缘等细节的主要原因。将转置卷积用于图像分割,应该是出自这篇论文:Learning Deconvolution Network for Semantic Segmentation

其实 resize feature map 到更大的尺寸,然后卷积,以 padding='SAME' 的模式,不比 deconvolution 差

转置卷积与 Dilated Conv 的区别

从下图可以看出,转置卷积与 Dilated Conv 都是带洞卷积,只不过 转置卷积 是输入信号带洞,而 Dilated Conv 是卷积核带洞

No padding, strides, transposed No padding, no stride, dilation

与 Convolutional Sparse Coding 的关系

convolutional sparse coding 组成的网络也可能叫 deconvolutional network,看文章的时候要搞清楚。一个是用来做 visualizing,一个是用来做 upsampling。

Reference

参考资料

  1. Convolution、Transposed convolution、Dilated convolution 的 GIF 动画
  2. Keras 里 UpSampling2D 与 Conv2DTranspose 有什么区别吗?
  3. 如何理解深度学习中的 deconvolution networks?
  4. Convolution arithmetic tutorial

拓展阅读

  1. Deconvolution and Checkerboard Artifacts
  2. Is the deconvolution layer the same as a convolutional layer?
  3. A guide to convolution arithmetic for deep learning
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment