↑ 点击蓝字 关注极市平台

作者丨土豆@知乎

来源丨https://zhuanlan.zhihu.com/p/158933003

极市导读

转置卷积在一些文献中也被称为反卷积,人们如果希望网络学习到上采样方法,就可以采用转置卷积。它不会使用预先定义的插值方法,而具有可以学习的参数。在文末,作者通过观察pytorch框架,解答了读者关于卷积矩阵参数优化的问题。>>>极市七夕粉丝福利活动:炼丹师们,七夕这道算法题,你会解吗?

前言

本文翻译自《Up-sampling with Transposed Convolution》,即《用转置卷积进行上采样》。这篇文章对转置卷积(反卷积)有着很好的解释,这里将其翻译为中文,以飨国人。

对于上采用的需求

当我们用神经网络生成图片的时候,经常需要将一些低分辨率的图片转换为高分辨率的图片。

对于这种上采样(up-sampling)操作,目前有着一些插值方法进行处理:

最近邻插值(Nearest neighbor interpolation)

双线性插值(Bi-Linear interpolation)

双立方插值(Bi-Cubic interpolation)

以上的这些方法都是一些插值方法,需要我们在决定网络结构的时候进行挑选。这些方法就像是人工特征工程一样,并没有给神经网络学习的余地,神经网络不能自己学习如何更好地进行插值,这个显然是不够理想的。

为什么是转置卷积

转置卷积(Transposed Convolution)常常在一些文献中也称之为反卷积(Deconvolution)和部分跨越卷积(Fractionally-strided Convolution),因为称之为反卷积容易让人以为和数字信号处理中反卷积混起来,造成不必要的误解,因此下文都将称为转置卷积,并且建议各位不要采用反卷积这个称呼。

如果我们想要我们的网络可以学习到最好地上采样的方法,我们这个时候就可以采用转置卷积。这个方法不会使用预先定义的插值方法,它具有可以学习的参数。理解转置卷积这个概念是很重要的,因为它在若干重要的文献中都有所应用,如:

1、在DCGAN中的生成器将会用随机值转变为一个全尺寸(full-size)的图片,这个时候就需要用到转置卷积。

2、在语义分割中,会使用卷积层在编码器中进行特征提取,然后在解码层中进行恢复为原先的尺寸,这样才可以对原来图像的每个像素都进行分类。这个过程同样需要用到转置卷积。

卷积操作

让我们回顾下卷积操作是怎么工作的,并且我们将会从一个小例子中直观的感受卷积操作。假设我们有一个的矩阵,我们将在这个矩阵上应用的卷积核,并且不添加任何填充(padding),步进参数(stride)设置为1,就像下图所示,输出为一个的矩阵。

这个卷积操作在输入矩阵和卷积核中,对每个元素的乘积进行相加。因为我们没有任何填充和使用1为步进,因此我们只能对这个操作进行4次,因此我们的输出矩阵尺寸为。

这种卷积操作使得输入值和输出值之间存在有位置上的连接关系,举例来说,输入矩阵左上方的值将会影响到输出矩阵的左上方的值。更具体而言,的卷积核是用来连接输入矩阵中的9个值,并且将其转变为输出矩阵的一个值的。一个卷积操作是一个多对一(many-to-one)的映射关系。让我们记住这个,我们接下来将会用得着。

反过来操作吧

现在,假设我们想要反过来操作。我们想要将输入矩阵中的一个值映射到输出矩阵的9个值,这将是一个一对多(one-to-many)的映射关系。这个就像是卷积操作的反操作,其核心观点就是用转置卷积。举个例子,我们对一个的矩阵进行上采样为的矩阵。这个操作将会维护一个1对应9的映射关系。

因此就结论而言,卷积操作是多对一,而转置卷积操作是一对多,如下图所示,每一个“对”而言,都需要维护一个权值。

但是我们将如何具体操作呢?为了接下来的讨论,我们需要定义一个卷积矩阵(convolution matrix)和相应的转置卷积矩阵(transposed convolution matrix)。

卷积矩阵

我们可以将一个卷积操作用一个矩阵表示。这个表示很简单,无非就是将卷积核重新排列到我们可以用普通的矩阵乘法进行矩阵卷积操作。如下图就是原始的卷积核:

我们对这个的卷积核进行重新排列,得到了下面这个的卷积矩阵:

这个便是卷积矩阵了,这个矩阵的每一行都定义了一个卷积操作。下图将会更加直观地告诉你这个重排列是怎么进行的。每一个卷积矩阵的行都是通过重新排列卷积核的元素,并且添加0补充(zero padding)进行的。

为了将卷积操作表示为卷积矩阵和输入矩阵的向量乘法,我们将输入矩阵摊平(flatten)为一个列向量,形状为,如下图所示。

我们可以将这个的卷积矩阵和的输入列向量进行矩阵乘法,这样我们就得到了输出列向量。

这个输出的的矩阵可以重新塑性为一个的矩阵,而这个矩阵正是和我们一开始通过传统的卷积操作得到的一模一样。

简单来说,这个卷积矩阵除了重新排列卷积核的权重之外就没有啥了,然后卷积操作可以通过表示为卷积矩阵和输入矩阵的列向量形式的矩阵乘积形式进行表达。

所以各位发现了吗,关键点就在于这个卷积矩阵,你可以从16()到4()因为这个卷积矩阵尺寸正是的,然后呢,如果你有一个的矩阵,你就可以从4()到16()了,这不就是一个上采样的操作吗?啊哈!让我们继续吧!

转置卷积矩阵

我们想要从4()到16(),因此我们使用了一个的矩阵,但是还有一件事情需要注意,我们是想要维护一个1到9的映射关系。

假设我们转置这个卷积矩阵变为。我们可以对和列向量进行矩阵乘法,从而生成一个的输出矩阵。这个转置矩阵正是将一个元素映射到了9个元素。

这个输出可以塑形为的矩阵:

我们只是对小矩阵进行上采样为一个更大尺寸的矩阵。这个转置卷积矩阵维护了一个1个元素到9个元素的映射关系,因为这个关系正表现在了其转置卷积元素上。

需要注意的是:这里的转置卷积矩阵的参数,不一定从原始的卷积矩阵中简单转置得到的,转置这个操作只是提供了转置卷积矩阵的形状而已。

总结

转置卷积操作构建了和普通的卷积操作一样的连接关系,只不过这个是从反向方向开始连接的。我们可以用它进行上采样。另外,这个转置卷积矩阵的参数是可以学习的,因此我们不需要一些人为预先定义的方法。即使它被称为转置卷积,它并不是意味着我们将一些现存的卷积矩阵简单转置并且使用其转置后的值。

从本质来说,转置卷积不是一个卷积,但是我们可以将其看成卷积,并且当成卷积这样去用。我们通过在输入矩阵中的元素之间插入0进行补充,从而实现尺寸上采样,然后通过普通的卷积操作就可以产生和转置卷积相同的效果了。你在一些文章中将会发现他们都是这样解释转置卷积的,但是这个因为在卷积操作之前需要通过添加0进行上采样,因此是比较低效率的。

注意:转置卷积会导致生成图像中出现棋盘效应(checkerboard artifacts),这篇文章《Deconvolution and Checkerboard Artifacts》推荐了一种上采样的操作(也就是插值操作),这个操作接在一个卷积操作后面以减少这种现象。如果你的主要目的是生成尽可能少棋盘效应的图像,那么这篇文章就值得你去阅读。

补充内容

评论区有朋友提出了一个问题,我觉得可能有些朋友也会有类似的疑问因此在这里统一讨论下,问题为:

博主您好,我觉的转置卷积矩阵的参数随着训练过程不断被优化,但是它是在随机初始化的基础上进行优化,还是在原始卷积矩阵的基础上进行优化?

——CSDN user

这个问题其实可以通过观察深度学习框架的实现方式进行,我选用的是pytorch,我们打开torch.nn.ConvTranspose1d的源码,发现有:

class ConvTranspose1d(_ConvTransposeMixin, _ConvNd):    def __init__(self, in_channels, out_channels, kernel_size, stride=1,                 padding=0, output_padding=0, groups=1, bias=True, dilation=1):        kernel_size = _single(kernel_size)        stride = _single(stride)        padding = _single(padding)        dilation = _single(dilation)        output_padding = _single(output_padding)        super(ConvTranspose1d, self).__init__(            in_channels, out_channels, kernel_size, stride, padding, dilation,            True, output_padding, groups, bias)@weak_script_method    def forward(self, input, output_size=None):        # type: (Tensor, Optional[List[int]]) -> Tensor        output_padding = self._output_padding(input, output_size, self.stride, self.padding, self.kernel_size)        return F.conv_transpose1d(            input, self.weight, self.bias, self.stride, self.padding,            output_padding, self.groups, self.dilation)

不难发现其实我们的卷积核参数weights其实是在超类中定义的,我们转到_ConvNd,代码如:

class _ConvNd(Module):    __constants__ = ['stride', 'padding', 'dilation', 'groups', 'bias']    def __init__(self, in_channels, out_channels, kernel_size, stride,                 padding, dilation, transposed, output_padding, groups, bias):        super(_ConvNd, self).__init__()        if in_channels % groups != 0:            raise ValueError('in_channels must be divisible by groups')        if out_channels % groups != 0:            raise ValueError('out_channels must be divisible by groups')        self.in_channels = in_channels        self.out_channels = out_channels        self.kernel_size = kernel_size        self.stride = stride        self.padding = padding        self.dilation = dilation        self.transposed = transposed        self.output_padding = output_padding        self.groups = groups        if transposed:            self.weight = Parameter(torch.Tensor(                in_channels, out_channels // groups, *kernel_size))        else:            self.weight = Parameter(torch.Tensor(                out_channels, in_channels // groups, *kernel_size))        if bias:            self.bias = Parameter(torch.Tensor(out_channels))        else:            self.register_parameter('bias', None)        self.reset_parameters()

我们可以清楚的发现,其实weights或者是bias的初始化就是一般地初始化一个符合一定尺寸要求的Tensor即可了,我们也可以发现其在forward过程中并没有所真的去根据输入进行权值的所谓“转置”之类的操作。因此我认为只要一般地进行随机初始化即可了。

而且,我们如果同时去观察torch.nn.Conv2d的类的话,其实也可以发现,其参数都是通过_ConvNd去进行初始化的,因此Conv2dConvTranspose2D的参数初始化除了尺寸的区别,其他应该类似。

引用

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/]

觉得有用麻烦给个在看啦~  

一文搞懂转置卷积(反卷积)相关推荐

  1. 一文读懂什么是反卷积

    反卷积(Deconvolution)的概念第一次出现是Zeiler在2010年发表的论文Deconvolutional networks中,但是并没有指定反卷积这个名字,反卷积这个术语正式的使用是在其 ...

  2. DL之CNN:卷积神经网络算法简介之卷积矩阵、转置卷积(反卷积Transpose)、膨胀卷积(扩张卷积Dilated/带孔卷积atrous)之详细攻略

    DL之CNN:卷积神经网络算法简介之卷积矩阵.转置卷积(反卷积Transpose).膨胀卷积(扩张卷积Dilated/带孔卷积atrous)之详细攻略 目录 卷积矩阵的简介 卷积.转置卷积--Tran ...

  3. 一文搞懂HMM(隐马尔可夫模型)-Viterbi algorithm

    ***一文搞懂HMM(隐马尔可夫模型)*** 简单来说,熵是表示物质系统状态的一种度量,用它老表征系统的无序程度.熵越大,系统越无序,意味着系统结构和运动的不确定和无规则:反之,,熵越小,系统越有序, ...

  4. 卷积 反卷积 上采样 下采样 区别

    1.卷积 就是利用卷积核  步长前进 卷积整个图片 2.反卷积 反卷积的具体操作 原图输入尺寸为[1,3,3,3]对应[batch_size,channels,width,height] 反卷积tco ...

  5. 都2021年了,再不学ES6你就out了 —— 一文搞懂ES6

    JS干货分享 -- 一文搞懂ES6 导语:ES6是什么?用来做什么? 1. let 与 const 2. 解构赋值 3. 模板字符串 4. ES6 函数(升级后更爽) 5. Class类 6. Map ...

  6. 一文搞懂什么VR,什么是6Dof,欧拉角,四元数转视图矩阵

    目录 一.什么是VR 二.什么是3Dof,6Dof, 9Dof 三.欧拉角(姿态角) 四.Android手机的欧拉角与坐标系 五.安卓坐标系转换欧拉角 六.根据姿态四元数求视图矩阵 一文搞懂什么VR, ...

  7. 一文搞懂极大似然估计

    极大似然估计,通俗理解来说,就是利用已知的样本结果信息,反推最具有可能(最大概率)导致这些样本结果出现的模型参数值! 换句话说,极大似然估计提供了一种给定观察数据来评估模型参数的方法,即:" ...

  8. 一文搞懂 checkpoint 全过程

    前言 前面我们讲解了 一文搞懂 Flink 处理 Barrier 全过程 和 一文搞定 Flink Checkpoint Barrier 全流程 基本上都是跟 checkpoint 相关.这次我们就具 ...

  9. 一文搞懂RNN(循环神经网络)

    基础篇|一文搞懂RNN(循环神经网络) https://mp.weixin.qq.com/s/va1gmavl2ZESgnM7biORQg 神经网络基础 神经网络可以当做是能够拟合任意函数的黑盒子,只 ...

最新文章

  1. java中堆与栈的区别 彻底理解
  2. 自动计算表格html,表格怎么自动计算加减
  3. 跨域cookie传递
  4. C# WinForm TreeView用法总结
  5. php sprintf u,PHP sprintf()格式化用法详解
  6. 身边的设计模式(一):单例 与 RedisCacheManager
  7. 如何在JavaScript中区分深层副本和浅层副本
  8. php全局变量的关键字,php的static关键字和全局变量
  9. 2020中国教育行业生存实录
  10. 邯郸学院计算机科学与技术录取分,邯郸学院录取分数线2021是多少分(附历年录取分数线)...
  11. 数据结构--循环队列
  12. 利用反射和lambda获取变量名字
  13. javawebJSP餐厅点餐系统源码JSP点餐系统JSP网上订餐系统JSP在线订餐系统JSP外卖系统
  14. 基于CNN-LSTM的手写数字识别与应用实现(附tensorflow代码讲解)
  15. php照片管理源码,PHP图片管理 Coppermine Photo v1.5.22 多国语言版
  16. 攻防世界-Misc-新手练习记录
  17. 请使用netty框架实现高效稳定的websocket通信
  18. 解决@Autowired警告
  19. PMP项目管理中的重要角色
  20. oracle入门之登录-创建用户

热门文章

  1. 韩宇:如何准备天池深度学习比赛?
  2. 时序预测的三种方式:统计学模型、机器学习、循环神经网络
  3. KNN 分类算法原理代码解析
  4. AI视觉大牛朱松纯担任北大AI研究院院长,提出通过构建大任务平台走向通用AI...
  5. Python如何实现24个微信大群万人同步转发直播?
  6. 为什么平头哥做芯片如此迅猛?
  7. 澎思科技成立新加坡研究院,将与多家机构合作研发自动驾驶等项目
  8. 一文掌握异常检测的实用方法 | 技术实践
  9. 如何写出符合Python审美的代码风格?
  10. AI一分钟 | Windows负责人离职;华为2017年收入6036亿元,净利475亿元