深度学习基础篇 第二章:转置卷积

简介: 简要介绍转置卷积。

参考教程:
https://arxiv.org/pdf/1603.07285.pdf


什么是转置卷积

在上一章我们说过,卷积有三种模式:full,valid,same。在full模式下,输出的特征图会比输入的特征图要大;valid模式下,输出的特征图会比输入的特征图要小;same模式下,输出的特征图会和输入的特征图大小保持一致。

full情况是很少见的,它要求卷积核的大小$k$比输入的特征图大,通过使用大小为$k-1$的padding扩充输入特征图,从而使得卷积的输出特征图大小变大。

在通常情况下,我们使用的都是valid或者same模式的卷积,并且搭配上stride=1或者stride=2,这就使得在卷积网络中逐层深入时,我们的特征图大小要么不变,要么折半,倾向于往越来越小的方向变化。

这就使得在某些要求特征图逐层变大的任务中,传统卷积就不是那么适用了。比如说语义分割任务,输出是像素级别的分割结果;或者超分辨率任务,输出图像大小至少为输入的两倍。我们当然可以用padding的方式把特征图变大,但是实际使用中效果并不好。

  1. 先padding再卷积。这个其实就是转置卷积在做的事情。
  2. 先卷积再padding。毫无疑问这种补全的结果对我们的任务来说是没有用的。

在这种情况下,就需要转置卷积的帮助。

转置卷积也是一种卷积操作,它实现的是我们常用的卷积的“反方向”的运算,即把一个卷积操作的输出结果还原回输入的形状,通常卷积实现的是下采样操作,转置卷积则是一种上采样方法。要注意的是这里只考虑“形状”。

如下图,输入是一个大小为4x4的特征图,使用大小为3x3的kernel进行卷积,得到大小为2x2的输出。它的转置过程,是用大小2x2的特征图做输入,得到大小4x4的输出,从结果上看,它类似于使用一个3x3的kernel在padding=(2,2,2,2)的2x2特征图上做卷积。
image.png

转置卷积有时候又称为反卷积,但是它本质上和反卷积还是有不同的。一方面在数学含义上反卷积是可以还原输入的值的,而转置卷积只还原形状;另一方面在深度学习中我们使用的转置卷积中的参数都是可学习的,非固定的,它的输出结果也是面向任务需求的。

转置卷积的思想

卷积操作可以形式化为一个矩阵乘法运算。

一维形式的理解

如下图,假设输入向量$x=[a,b,c,d,e,f,g]^T$,卷积核为$K=[x,y,z]$,卷积的滑动步长为2。
image.png

直观来看,大小为3x7的卷积矩阵A和大小为7x1的输入向量x相乘,得到大小为3x1的输出向量y。即
$$ y = Ax $$
转置卷积则是将上式中的输入输出互换:
$$ x = A^Ty $$
即使用大小为7x3的转置卷积矩阵$A^T$和大小为3x1的输出向量y相乘,得到大小为7x1的输入向量x。
这样的计算只还原了输入输出的大小,但是其中的数值已经发生了变化,所以只是在形状上保持一致。

二维形式的理解

参考了https://zhuanlan.zhihu.com/p/115070523?from_voters_page=true里的例子。

对于一个输入大小为3x3的输入和大小为2x2的卷积核。
$$ \begin{align} &X = \begin{bmatrix}x_{11}&x_{12}&x_{13}\\ x_{21}&x_{22}&x_{23}\\ x_{31}&x_{32}&x_{33} \end{bmatrix}\\ & W = \begin{bmatrix}w_{11}&w_{12}\\ w_{21}&w_{22} \end{bmatrix} \end{align} $$
我们用类似于一维形式的方法,也把卷积核表示成相应的稀疏矩阵C:
$$ C = \begin{bmatrix}w_{11}&w_{12}&0&w_{21}&w_{22}&0&0&0&0\\ 0&w_{11}&w_{12}&0&w_{21}&w_{22}&0&0&0\\ 0&0&0&w_{11}&w_{12}&0&w_{21}&w_{22}&0\\ 0&0&0&0&w_{11}&w_{12}&0&w_{21}&w_{22} \end{bmatrix} $$
同时输入向量也进行展开变为:
$$ x = \begin{bmatrix}x_{11}&x_{12}&x_{13}& x_{21}&x_{22}&x_{23}& x_{31}&x_{32}&x_{33}\end{bmatrix} $$
直观来看,大小为4x9的卷积矩阵C和大小为9x1的输入向量x相乘,得到大小为4x1的输出向量y。即
$$ y = Cx $$
转置卷积则是将上式中的输入输出互换:
$$ x = C^Ty $$
即使用大小为9x4的转置卷积矩阵$C^T$和大小为4x1的输出向量y相乘,得到大小为9x1的输入向量x。
这样的计算只还原了输入输出的大小,但是其中的数值已经发生了变化,所以只是在形状上保持一致。

卷积和转置的关系

去理解转置卷积在给定输入特征图 $x$ 上的运算结果,我们可以去想象这个输入特征图本身是某个正向的卷积在某特定特征图上$x'$的结果,转置卷积就是为了复原这个特定特征图$x'$的形状。

重温一下特征图大小计算公式:
$$ D_{output}=\frac{D_{input}-D_{kernel}+2\times Padding}{Stride}+1 $$
先放一个别的地方偷来的计算总结,后面再详细计算:
image.png


no pading, unit strides

image.png

假如$x'$是4x4大小的特征图,我们的标准卷积操作是使用一个大小3x3的卷积核,padding=0,stride=1,得到的结果$x$是一个大小为2x2的特征图。
现在我们的转置卷积要求将$x$复原为$x'$,我们在通过调整padding来实现这样的结果。
仍然使用大小为3x3的卷积核,stride=1,那么按照公式:
$$ 4 = \frac{2-3+2\times Padding}{1}+1 $$
代入后可以得到padding = 2。
更general的,我们列一个公式来算padding。
$$ \begin{align} &D_{output}=\frac{D_{input}-D_{kernel}+2\times Padding}{Stride}+1\\ &D_{input} = \frac{D_{output}-D_{kernel}+2\times Padding'}{Stride}+1\\ \end{align} $$
将式子4代入3中,在stride=1的情况下,可以得到
$$ Padding + 1 - D_{kernel} + Padding' = 0 $$
在padding=0的情况下,可得到:
$$ Padding' = D_{kernel}-1 $$
再将这个结果代入式子4,可以得到:
$$ D_{input} = D_{output} - D_{kernel} + 2\times(D_{kernel}-1) +1 = D_{output} + D_{kernel} - 1 $$


padding, unit strides

image.png

类似于no padding的情况,使用和上一节类似的公式,可以得到:
$$ Padding' = D_{kernel}-1-Padding $$
同样代入式子4,可以得到:
$$ \begin{align} D_{input} &= D_{output} - D_{kernel} + 2\times(D_{kernel}-1-Padding) +1 \\ &= D_{output} + D_{kernel} - 1 - 2\times Padding \end{align} $$


no padding, non-unit stride

image.png

上图表示一个stride!=1的情况,假如$x'$是5x5大小的特征图,我们的标准卷积操作是使用一个大小3x3的卷积核,padding=0,stride=2,得到的结果$x$是一个大小为2x2的特征图。
现在我们的转置卷积要求将$x$复原为$x'$。需要再$x$的元素之间进行填充,再进行卷积。
image.png

和之前的no padding的情况一样,我们的kernel大小仍使用3x3,padding使用前面两节得到的计算结果padding = k-1,那么我们来计算一下在填充后的图像上使用的新的stride是多少。

对于当前的问题,$x'$大小为5x5,$x$大小为2x2,在$x$的元素间填充stride-1 = 2-1 = 1个0,使它变成大小为3x3的$new\_x$。kernel大小为3x3,padding大小为2。

$$ 5 = \frac{3-3+2\times 2}{Stride}+1 $$
求得stride = 1。

更general的,我们列一个公式来算stride。
$$ \begin{align} &D_{output}=\frac{D_{input}-D_{kernel}+2\times Padding}{Stride}+1\\ &D_{output'} = D_{output} + (Stride-1)*(D_{output}-1)\\ &D_{input} = \frac{D_{output'}-D_{kernel}+2\times Padding'}{Stride}+1\\ &Padding' = D_{kernel} -1 \end{align} $$
公式联立后可得到:
$$ Stride\times D_{output} - Stride +D_{kernel}-1 = Stride\times(Stride\times D_{output} - Stride+D_{kernel}-1 - 2\times Padding ) $$
在Padding=0的情况下,可得 $Stride=1$。


padding,non-unit stride

image.png

在padding不等于0的情况下,使用之前得到的公式。
$$ Padding' = D_{kernel}-1-Padding $$
用这个式子和公式7、8、9联立,可以得到。
$$ Stride\times D_{output} - Stride +D_{kernel}-1 -2\times Padding= Stride\times(Stride\times D_{output} - Stride+D_{kernel}-1 - 2\times Padding ) $$
可得$Stride=1$。

pytorch中的转置卷积

根据上面的卷积和转置卷积的关系,我们来理一下它的具体实现。

转置卷积本质上就是对一个输入数据进行补零/上采样的普通卷积操作。
在有无padding,有无stride的多种情况下,kernel的大小是保持不变的。

  • 对于padding:
    1. 卷积中padding=0,转置卷积的padding’=k-1。
    2. 卷积中padding不为0,转置卷积的padding‘=k-padding-1。
      归纳为 padding’ = k-padding-1
  • 对于stride:
    1. 卷积中stride=1,转置卷积的stride=1,特征图不需要补0。
    2. 卷积中stride>1,转置卷积的stride=1,特征图元素间需要按stride-1的个数补0。
      归纳为,stride永远=1,但是特征图需要按stride-1进行补0。

对于一个大小为k,步长为s,padding为p的普通卷积,求它对应的转置卷积可以按如下步骤:

  1. 在特征图相邻数据间进行填充,在水平和垂直方向上元素间填充s-1个0。
  2. 在特征图边界进行填充,在四个边界分为进行大小为填充k-p-1的填充。
  3. 在得到的特征图上进行大小为k,步长为1的普通卷积操作。

看一下pytorch中的转置卷积的实现。

https://pytorch.org/docs/stable/generated/torch.nn.ConvTranspose2d.html#torch.nn.ConvTranspose2d

CLASS torch.nn.ConvTranspose2d(in_channels, out_channels, kernel_size, stride=1, padding=0, output_padding=0, groups=1, bias=True, dilation=1, padding_mode='zeros', device=None, dtype=None)

转置卷积和普通的卷积都继承了pytorch中的类_ConvNd,它们的初始化也没有什么区别,传参的参数名也大同小异。

我们在看介绍的时候可以看到,输入和输出的shape之间的关系是这样的。
image.png

从这个图可以看出来,实际上的操作是,output在使用当前卷积核运算处理后,得到input。这里的padding和stride都是针对output->input这一过程的。
但是在实际中我们做的是input->output这个过程,所以我们用的padding和stride都和给定的参数并不一致。

可以理解成,我们模拟了一个预想的输出使用卷积变成现在的输入的过程,然后用这个卷积的配置作为我们转置卷积的输入参数,基于此设计一个转置卷积。

使用了一个别人给的例子:
image.png

在这个例子中,我们的输入特征图大小是2x2,传入转置卷积的参数中,kernel_size=3,stride=1,padding=0。输出的特征图大小是4x4。

也就是我们用4x4的特征图做输入,使用kernel_size=3, stride=1, padding=0的卷积核,可以得到大小为2x2的输出特征图。

按照之前章节的公式理解,我们的转置卷积实际上做的操作是:

  1. 给2x2特征图的元素间填充stride-1 = 1-1 = 0个0。得到2x2大小的特征图。
  2. 给2x2的特征图进行大小为kernel_size-p-1 = 3-0-1-2的padding。得到大小为6x6的特征图。
  3. 在6x6的特征图上使用大小为3x3的卷积核,进行步长=1的卷积运算,得到大小为4x4的输出。
相关文章
|
1月前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的眼疾识别系统实现~人工智能+卷积网络算法
眼疾识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了4种常见的眼疾图像数据集(白内障、糖尿病性视网膜病变、青光眼和正常眼睛) 再使用通过搭建的算法模型对数据集进行训练得到一个识别精度较高的模型,然后保存为为本地h5格式文件。最后使用Django框架搭建了一个Web网页平台可视化操作界面,实现用户上传一张眼疾图片识别其名称。
105 5
基于Python深度学习的眼疾识别系统实现~人工智能+卷积网络算法
|
2月前
|
机器学习/深度学习 人工智能 算法
猫狗宠物识别系统Python+TensorFlow+人工智能+深度学习+卷积网络算法
宠物识别系统使用Python和TensorFlow搭建卷积神经网络,基于37种常见猫狗数据集训练高精度模型,并保存为h5格式。通过Django框架搭建Web平台,用户上传宠物图片即可识别其名称,提供便捷的宠物识别服务。
321 55
|
2月前
|
机器学习/深度学习 人工智能 算法
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
宠物识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了37种常见的猫狗宠物种类数据集【'阿比西尼亚猫(Abyssinian)', '孟加拉猫(Bengal)', '暹罗猫(Birman)', '孟买猫(Bombay)', '英国短毛猫(British Shorthair)', '埃及猫(Egyptian Mau)', '缅因猫(Maine Coon)', '波斯猫(Persian)', '布偶猫(Ragdoll)', '俄罗斯蓝猫(Russian Blue)', '暹罗猫(Siamese)', '斯芬克斯猫(Sphynx)', '美国斗牛犬
216 29
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
深入理解深度学习中的卷积神经网络(CNN)##
在当今的人工智能领域,深度学习已成为推动技术革新的核心力量之一。其中,卷积神经网络(CNN)作为深度学习的一个重要分支,因其在图像和视频处理方面的卓越性能而备受关注。本文旨在深入探讨CNN的基本原理、结构及其在实际应用中的表现,为读者提供一个全面了解CNN的窗口。 ##
|
3月前
|
机器学习/深度学习 人工智能 自然语言处理
深入理解深度学习中的卷积神经网络(CNN)
深入理解深度学习中的卷积神经网络(CNN)
|
3月前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的卷积神经网络(CNN): 从理论到实践
本文将深入浅出地介绍卷积神经网络(CNN)的工作原理,并带领读者通过一个简单的图像分类项目,实现从理论到代码的转变。我们将探索CNN如何识别和处理图像数据,并通过实例展示如何训练一个有效的CNN模型。无论你是深度学习领域的新手还是希望扩展你的技术栈,这篇文章都将为你提供宝贵的知识和技能。
440 7
|
3月前
|
机器学习/深度学习 自然语言处理 算法
深入理解深度学习中的卷积神经网络(CNN)
深入理解深度学习中的卷积神经网络(CNN)
119 1
|
3月前
|
机器学习/深度学习 人工智能 自然语言处理
探索深度学习中的卷积神经网络(CNN)及其在现代应用中的革新
探索深度学习中的卷积神经网络(CNN)及其在现代应用中的革新
|
3月前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
本文旨在通过深入浅出的方式,为读者揭示卷积神经网络(CNN)的神秘面纱,并展示其在图像识别领域的实际应用。我们将从CNN的基本概念出发,逐步深入到网络结构、工作原理以及训练过程,最后通过一个实际的代码示例,带领读者体验CNN的强大功能。无论你是深度学习的初学者,还是希望进一步了解CNN的专业人士,这篇文章都将为你提供有价值的信息和启发。
|
3月前
|
机器学习/深度学习 人工智能 网络架构
深入理解深度学习中的卷积神经网络(CNN)
深入理解深度学习中的卷积神经网络(CNN)
80 1