虽然之前发过一篇转载类型的博客:
你想到的卷积类型这里都有,在里面的上篇有介绍转置卷积,但是他那篇的参考博客是国外的,一般看不了,我在这里就翻译一下,对自己加深印象也是好的。
在这里也给出原博客链接:
https://medium.com/activating-robotic-minds/up-sampling-with-transposed-convolution-9ae4f2df52d0
可以打开的也可以看看。
如果你曾经听说过转置卷积(transposed convolution)并对它感到很迷惑,那可以来看一下这篇文章。这篇文章的内容如下:
- 上采样的需要
- 为什么需要转置卷积?
- 卷积操作
- 逆向回去
- 卷积矩阵
- 转置卷积矩阵
- 总结
在我的Github上也有jupyter notebook对应部分。
上采样的需要
当我们使用神经网络去生成图像,通常会涉及到上采样操作,也就是从低分辨率到高分辨率。
有不同的方法可以进行上采样:
- 最近邻插值(Nearest neighbor interpolation)
- 双线性插值(Bi-linear interpolation)
- 双立方插值(Bi-cubic interpolation)
这些方法都涉及到一些插值的方法,所以我们在决定网络架构的的时候我们需要去选择一种。这有点像人工的特征工程(feature engineering),并且这个过程中网络没有网络可以学习的。
为什么需要转置卷积?
如果我们想要我们的网络学习怎样最优地进行上采样,我们能够使用转置卷积(transposed convolution)。它不使用预先定义的插值方法,它有可学习的参数。
去理解转置卷积是非常有用的,因为它被使用在重要的论文和项目中,例如:
- 在DCGAN中的生成器(generator)就把随机采样的值产生出一个full-size的图像;
- 在语义分割领域,在编码阶段就会使用卷积层来提取特征,然后在解码阶段又把特征恢复到原图大小,因此就可以将原图中的每一个像素都进行分类。
供参考(FYI):转置卷积也被称作:
- 小数步长的卷积(fractionally strided convolution)
- 反卷积(deconvolution)
在这篇文章里面,我们只使用转置卷积这个名称,但是你在别的文章里面可能会注意到别的名字。
卷积操作
让我们用一个简单的例子来解释一下卷积操作是怎么进行的。假设我们有一个4x4的矩阵,在其上使用3x3的核应用一个卷积操作,没有补零操作,步长设为1。如下图所示,结果是一个2x2的矩阵:
卷积操作就是计算输入矩阵和卷积核矩阵之间逐元素的乘积然后加和。因为我们没有补零,步长为1,我们只能做这样的操作4次,因此输出的矩阵就是2x2的。
一个重要的点就是:这样的卷积操作,在输入值和输出值之间存在位置连接关系的
例如,输入矩阵的左上方的值就会影响输出矩阵的左上方的值。
更确切地说就是,3x3的卷积核用来连接输入矩阵中的9个值和输出矩阵中对应的1个值。一个卷积操作形成了一个多对一的关系。让我们把这个观念牢记在心,因为之后我们还需要用到它。
逆向回去
现在,假设我们想要从另一个方向进行。我们想把一个矩阵中的1个值关联到另一个矩阵中的9个值。现在就是一个一对多的关系。这就像卷积操作的反向,这就是转置卷积的核心想法。
举个例子,我们把一个2x2的矩阵上采样到一个4x4的矩阵。这个操作就维持着1-to-9的关系。
但是我们怎么实现这样的操作呢?
在讲怎样实现之前,我们需要定义卷积矩阵(convolution matrix)和转置卷积矩阵(transposed convolution matrix)。
卷积矩阵
其实我们可以用一个矩阵来表达卷积操作。只要重排一下核矩阵,我们就能用矩阵相乘来实现卷积操作。
我们把这个3x3的卷积核重排成4x16的矩阵,就像下面这样:
这就是卷积矩阵(就是核矩阵重排后的矩阵)。每一行都定义了一个卷积操作。如果你没有看出来,下面这幅图会帮助你。卷积矩阵的每一行就是把核矩阵重排,然后在不同的位置进行补零。
为了使用这个卷积矩阵,我们把4x4的输入矩阵展平成一个列向量(16x1)。
我们把4x16的卷积矩阵和展平后的16x1的输入矩阵(也就是个16维的列向量)进行矩阵相乘:
输出的4x1的矩阵能够reshape成一个2x2的矩阵,这和我们上面的结果一致。
总的来说,一个卷积矩阵就是一个重排的核参数,并且卷积操作可以被表达为矩阵相乘。
那又怎么样?
关键点在于用了卷积矩阵,你就能从16(4x4)变到4(2x2),因为卷积矩阵是4x16的。那么,如果你有一个16x4的矩阵,那你就能从4(2x2)变到16(4x4)。
想不通了嘛?
接着看吧!!
转置卷积矩阵
我们需要从4(2x2)变到16(4x4),那我们就得使用16x4的矩阵。并且我们想要维持这个1 to 9的关系。
我们记卷积矩阵为C(4x16),它的转置记为C.T(16x4)。我们能够把这个转置后的矩阵C.T(16x4)和一个4x1的列向量进行矩阵相乘得到一个16x1的输出矩阵。这个转置的矩阵就把1个值联系到输出中的9个值。
输出能够reshape成4x4的;
刚刚,我们就把一个小一点的2x2的矩阵上采样成一个大一点的4x4的矩阵。其中转置卷积就维持了这种1对9的关系(由于权重矩阵的排列形似达到的)。
注意一下:事实上之后的权重值并不来自于原初的卷积矩阵。重要的是,之后的权重值的排列是之前卷积矩阵的一个转置形式。
总结
转置卷积操作组成了如正常卷一样的连接关系,只不过是一个反向的操作。
我们可以利用转置卷积进行上采样,并且,转置卷积矩阵中的权值是可以学习的,所以我们不需要一个预先定义的插值方法。
尽管它叫做转置卷积,但它并不是我们把之前存在的卷积矩阵进行转置并拿来使用。关键的点是,转置卷积过程和一个标准的卷积操作相比,输入和输出是以不同的方式进行处理的(一对多而不是多对一的联结)。
同样的,转置卷积不能算是卷积。但是我们能够用一个卷积来模仿转置卷积。你也可能会发现一些文章是这样来解释转置卷积的(这个我看到的地方我会再加进来):我们通过在输入矩阵的值之间加零进行上采样,然后在其上用一个直接的卷积操作来达到和转置卷积一样的效果。然而,这样由于在卷积之前通过加零对输入上采样,会更加低效率。
One caution:在生成图像是,转置卷积是造成棋盘效应(checkerboard artifacts)的起因。这篇文章推荐了一种上采样操作(如一种插值方法),借着一个卷积操作就能减小这样的问题。如果你的目的是为了生成没有棋盘效应的图像,那篇文章值得一读。
参考文献
[1] A guide to convolution arithmetic for deep learning
Vincent Dumoulin, Francesco Visin
https://arxiv.org/abs/1603.07285
[2] Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks
Alec Radford, Luke Metz, Soumith Chintala
https://arxiv.org/pdf/1511.06434v2.pdf
[3] Fully Convolutional Networks for Semantic Segmentation
Jonathan Long, Evan Shelhamer, Trevor Darrell
https://people.eecs.berkeley.edu/~jonlong/long_shelhamer_fcn.pdf
[4] Deconvolution and Checkerboard Artifacts
Augustus Odena, Vincent Dumoulin, Chris Olah
https://distill.pub/2016/deconv-checkerboard/