万字长文带你看尽深度学习中的各种卷积网络(上篇)
雷锋网 AI 科技评论按:深度学习中的各种卷积网络大家知多少?对于那些听说过却又对它们没有特别清晰的认识的小伙伴们, Kunlun Bai 这篇文章非常值得一读。Kunlun Bai 是一位人工智能、机器学习、物体学以及工程学领域的研究型科学家,在本文中,他详细地介绍了 2D、3D、1x1 、转置 、空洞(扩张)、空间可分离、深度可分离、扁平化、 分组等十多种卷积网络类型。雷锋网 (公众号:雷锋网) AI 科技评论编译如下。
如果你曾听过深度学习的各种卷积网络(例如 2D/3D/ 1x1 / 转置 /空洞(扩张)/ 空间可分离 / 深度可分离 /扁平化 / 分组 / 混洗分组卷积)并疑惑它们到底都是什么的话,你可以通过这篇文章了解它们实际的工作原理。
在文中,我概括性地介绍了在深度学习中常见的几种卷积,并采用了大家都能够明白的方式来解释它们。针对这一主题,这篇文章以外也有其他的一些文章可供大家参考,我将这些文章的链接附在了文末参考部分,大家可前往阅读。
希望这篇文章能够帮助大家建立起对这几种卷积的认知,并为大家的学习/研究带来有用的参考价值。
本文的内容包括:
1. 卷积 VS 互关联
2. 深度学习中的卷积网络(单通道版,多通道版)
3.3D 卷积
4. 1x1 卷积
5. 卷积算法
6. 转置卷积(反卷积,棋盘效应)
7. 空洞卷积(扩张卷积)
8. 可分离卷积(空间可分离 卷积,深度可分离卷积)
9. 扁平化卷积
10. 分组卷积
11. 混洗分组卷积
12. 逐点分组卷积
1. 卷积 VS 互关联
卷积是一项广泛应用于信号处理、图像处理以及其他工程/科学领域的技术。在深度学习中,卷积神经网络(CNN)这一模型架构就由这项技术命名的。然而,深度学习中的卷积本质上就是信号/图像处理中的互关联(cross-correlation)。二者间只有细微的差别。
不深入考虑细节的话,二者的区别在于:在信号/图像处理中,卷积被定义为:
它的定义是:一个函数经过翻转和移动后与另一个函数的乘积的积分。下面的图像形象化地展示了这个思想:
信号处理中的卷积。过滤函数 g 经过翻转然后沿着横轴滑动。对于该函数在横轴上滑过的每个点的位置,都计算出函数 f 与翻转后的函数 g 的重合区域。这个重合的区域就是函数 g 在横轴上滑过的某个特定位置的卷积值。图像来源: https://fourier.eng.hmc.edu/e161/lectures/convolution/index.html
在这里,函数 g 是一个过滤函数。这个函数经过翻转然后沿着横轴滑动。对于该函数在横轴上滑过的每个点的位置,都计算出函数 f 与翻转后的函数 g 的重合区域。这个重合的区域就是函数 g 在横轴上滑过的某个特定位置的卷积值。
而另一方面,互关联是这两个函数的滑动的点积(dot product)或滑动的内积(inner-product)。互关联的过滤函数不经过翻转,它直接滑动通过函数 f。函数 f 和函数 g 的重合区域就是互关联。下图展示了卷积和互关联的区别:
在信号处理中,卷积和互关联的区别。图像来源: https://en.wikipedia.org/wiki/Convolution
在深度学习中,卷积中的过滤函数是不经过翻转的。严格来说,它就是互关联。我们本质上就是在执行 element-wise 乘法和加法。但是,这个「卷积」仅在深度学习中被称为卷积,可以这样做的原因是因为卷积在训练期间就学到了过滤函数的权重,如果上面示例中的经翻转的函数 g 是正确的函数,那么经过训练后,卷积所学到的过滤函数就会找到翻转后的函数 g。因此,在正确的卷积中,就不需要在训练前早早地翻转过滤函数。
2. 深度学习中的卷积
执行卷积的目的就是从输入中提取有用的特征。在图像处理中,执行卷积操作有诸多不同的过滤函数可供选择,每一种都有助于从输入图像中提取不同的方面或特征,如水平/垂直/对角边等。类似地,卷积神经网络通过卷积在训练期间使用自动学习权重的函数来提取特征。所有这些提取出来的特征,之后会被「组合」在一起做出决策。
进行卷积操作有许多优势,例如权重共享(weights sharing)和平移不变性(translation invariant)。此外,卷积也可以考虑到像素的空间关系。这些优势都非常有帮助,尤其是在许多的计算机视觉任务中,因为这些任务往往涉及到对某些组成部分与其他组成部分有某些空间关系的目标进行识别(例如一只狗的身体通常是跟它的脑袋、四条腿以及尾巴相连的)。
2.1 卷积:单通道版
面向单通道的卷积,图像源自: https://towardsdatascience.com/intuitively-understanding-convolutions-for-deep-learning-1f6f42faee1
在深度学习中,卷积就是元素级别( element-wise) 的乘法和加法。对于一张仅有 1 个通道的图像,卷积过程如上图所示,过滤函数是一个组成部分为 [[0, 1, 2], [2, 2, 0], [0, 1, 2]] 的 3 x 3 矩阵,它滑动穿过整个输入。在每一个位置,它都执行了元素级别的乘法和加法,而每个滑过的位置都得出一个数字,最终的输出就是一个 3 x 3 矩阵。(注意:在这个示例中,卷积步长=1;填充=0。我会在下面的算法部分介绍这些概念。)
2.2 卷积:多通道版
在许多应用中,我们处理的是多通道的图像。一个典型的案例就是 RGB 图像,如下图所示,每一个 RGB 通道都分别着重于原始图像的不同方面。
每一个 RGB 通道都分别着重于原始图像的不同方面,图片拍摄于:中国云南元阳
另一个多通道数据的案例就是卷积神经网络中的层。一个卷积网络层往往都由多个通道(一般为数百个通道)组成,每一个通道描述出前一个层的不同方面。那我们如何实现不同深度的层之间的过渡呢?又如何将深度为 n 的层转化为后面的深度为 m 的层呢?
在介绍这个过程之前,我们先搞清楚几个名词:层(layer)、通道(channel)、特征映射(feature map)、过滤器(filter)以及卷积核(kernel)。从层级角度来说,「层」和「过滤器」的概念属于一个层级,而「通道」和「卷积核」都在下一个层级。「通道」和「特征映射」是指同一个东西。一层可以有多个通道(或特征映射);如果输入的是 RGB 图像,那这个输入层有 3 个通道。「通道」一般用来形容「层」的架构。类似地,「卷积核」则用来形容「过滤器」的架构。
「层」(「过滤器」)和「通道」(「卷积核」)之间的区别
过滤器和卷积核之间的区别非常微妙,有时候,二者可以交替使用,这无疑就制造了些困惑。但根本上来讲,二者还是有些细微区别的:「卷积核」指的是指权重组成的 2D 数组 ;「过滤器」则是由多个卷积核堆叠在一起的 3D 架构概念。对于一个 2D 过滤器来说,过滤器就相当于卷积核,但是对于一个 3D 过滤器以及深度学习中的大多数卷积而言,一个过滤器由一组卷积核组成。每个卷积核都是独一无二的,强调了输入通道的不同方面。
带着对这些概念的了解,下面让我们一起来看看多通道卷积。生成一个输出通道,就需要将每一个卷积核应用到前一层的输出通道上,这是一个卷积核级别的操作过程。我们对所有的卷积核都重复这个过程以生成多通道,之后,这些通道组合在一起共同形成一个单输出通道。下图可以让大家更清晰地看到这个过程。
这里假设输入层是一个 5 x 5 x 3 矩阵,它有 3 个通道。过滤器则是一个 3 x 3 x 3 矩阵。首先,过滤器中的每个卷积核都应用到输入层的 3 个通道,执行 3 次卷积后得到了尺寸为 3 x 3 的 3 个通道。
面向多通道的 2D 卷积的第一步:过滤器每个卷积核分别应用到输入层的 3 个通道上。图片源自: https://towardsdatascience.com/intuitively-understanding-convolutions-for-deep-learning-1f6f42faee1
之后,这 3 个通道都合并到一起(元素级别的加法)组成了一个大小为 3 x 3 x 1 的单通道。这个通道是输入层(5 x 5 x 3 矩阵)使用了过滤器(3 x 3 x 3 矩阵)后得到的结果。
面向多通道的 2D 卷积的第二步:3 个通道都合并到一起(元素级别的加法)组成了一个大小为 3 x 3 x 1 的单通道。图片源自: https://towardsdatascience.com/intuitively-understanding-convolutions-for-deep-learning-1f6f42faee1
同样地,我们可以将这个过程视作将一个 3D 过滤器矩阵滑动通过输入层。注意,这个输入层和过滤器的深度都是相同的(即通道数=卷积核数)。这个 3D 过滤器仅沿着 2 个方向(图像的高&宽)移动(这也是为什么 3D 过滤器即使通常用于处理 3D 体积数据,但这样的操作还是被称为 2D 卷积)。在每一个滑过的位置,我们都执行元素级别的乘法和加法,最终得出一个数值。下面这个例子中,过滤器横向滑过 5 个位置、纵向滑过 5 个位置。全部完成后,我们得到了一个单输出通道。
看待 2D 卷积的另一个角度:将这个过程视作将一个 3D 过滤器矩阵滑动通过输入层。注意,这个输入层和过滤器的深度都是相同的(即通道数=卷积核数)。这个 3D 过滤器仅沿着 2 个方向(图像的高&宽)移动(这也是为什么 3D 过滤器即使通常用于处理 3D 体积数据,但这样的操作还是被称为 2D 卷积)。输出是一个 1 层的矩阵。
现在我们可以看到如何在不同深度的层之间实现过渡。假设输入层有 Din 个通道,而想让输出层的通道数量变成 Dout ,我们需要做的仅仅是将 Dout 个过滤器应用到输入层中。每一个过滤器都有 Din 个卷积核,都提供一个输出通道。在应用 Dout 个过滤器后,Dout 个通道可以共同组成一个输出层。
标准 2D 卷积。通过使用 Dout 个过滤器,将深度为 Din 的层映射为另一个深度为 Dout 的层。
3.3D 卷积
在上部分的最后一张图中,我们看到了将卷积在 3D 体积上的执行情况。但是一般而言,我们依旧将这一操作视为深度学习中的 2D 卷积——3D 体积数据上的 2D 卷积:其过滤器和输入层的深度是一样的;3D 过滤器仅沿着 2 个方向(图像的高&宽)移动。这样操作得出的结果就是一个 2D 图像(仅有 1 个通道)。
有 2D 卷积,自然就有 3D 卷积。3D 卷积是 2D 卷积的一般化。在 3D 卷积中,过滤器的深度要比输入层的深度更小(卷积核大小<通道大小),结果是,3D 过滤器可以沿着所有 3 个方向移动(高、宽以及图像的通道)。每个位置经过元素级别的乘法和算法都得出一个数值。由于过滤器滑动通过 3D 空间,输出的数值同样也以 3D 空间的形式呈现,最终输出一个 3D 数据。
在 3D 卷积中,过滤器的深度要比输入层的深度更小(卷积核大小<通道大小),结果是,3D 过滤器可以沿着所有 3 个方向移动(高、宽以及图像的通道)。每个位置经过元素级别的乘法和算法都得出一个数值。由于过滤器滑动通过 3D 空间,输出的数值同样也以 3D 空间的形式呈现,最终输出一个 3D 数据 。
和对 2D 区域中目标的空间关系进行解码的 2D 卷积相似,3D 卷积也可以描述 3D 空间中目标的空间关系。对于一些应用来说,这种 3D 关系很重要,例如在 CT 和 MRI 等生物医学图像的 3D 分割/重建中,这些图像的目标如血管都是蜿蜒分布在 3D 空间中的。
4. 1x1 卷积
由于我们在前一个部分——3D 卷积中探讨了深度级别的操作,接下来让我们了解另一个有趣的操作,1 x 1 卷积。
你或许想知道为什么这个卷积是有帮助作用的。我们刚刚是否让输入层中的每个数值都乘以了一个数值?是,也不是。对于仅有 1 个通道的层来说,这项操作不重要。在上面的示例中,我们让每一个组成部分都乘以了一个数值。
如果输入层有多个通道,那事情就变得非常有趣了。下图阐述了 1 x 1 卷积在一个维度为 H x W x D 的输入层上的操作方式。经过大小为 1 x 1 x D 的过滤器的 1 x 1 卷积,输出通道的维度为 H x W x 1。如果我们执行 N 次这样的 1 x 1 卷积,然后将这些结果结合起来,我们能得到一个维度为 H x W x N 的输出层。
过滤器大小为 1 x 1 x D 的 1 x 1 卷积
1 x 1 卷积最初是在 Network-in-network 的论文(论文阅读地址: https://arxiv.org/abs/1312.4400 )中被提出的,之后在谷歌的 Inception 论文(论文阅读地址: https://arxiv.org/abs/1409.4842 )中被大量使用。1 x 1 卷积具有如下几个优势:
减少维度以实现更有效率的计算;
进行更有效率的低维度嵌入,或者对特征进行池化;
卷积以后反复应用非线性特征。
前两个优势我们可以从上面的图像中观察到。执行 1 x 1 卷积后,我们明显减少了维度的深度级别。假设原始输入有 200 个通道,1 x 1 卷积会将这些通道(特征)嵌入到一个单通道中。第三个优势在 1 x 1 卷积执行后才显现出来,它会将线性整流函数(ReLU)等非线性激活函数添加进模型中。非线性特征让网络学习更复杂的函数。
谷歌的 Inception 论文中也对这些优势进行了描述:
「上面这个模块(至少在这个朴素的形式中)的一个大问题是,即便是数量适度的 5 x 5 卷积,在有大量过滤器的卷积层之上的计算也会过于昂贵。
这就给提出的框架带来了第二个思路:明智地减少维度并进行投影,不然就会过度增加对于计算的要求。这是基于成功实现嵌入上的:即便是低维度的嵌入也可以容纳大量关于相对较大的图像块的信息... 也就是说,在执行计算昂贵的 3 x 3 卷积和 5 x 5 卷积前,往往会使用 1 x 1 卷积来减少计算量。此外,它们也可以利用调整后的线性激活函数来实现双重用途。」
针对 1 x 1 卷积,Yann LeCun 提出了一个非常有趣的角度:「在卷积网络中,不存在像「全连接层」这样的东西,而只有含有一些 1x1 卷积核和 1 个全连接表的卷积层」
5. 卷积算法
我们现在知道了如何处理卷积的深度。接下来讨论一下怎样处理在其他两个方向(高&宽)中的卷积,以及重要的卷积算法(onvolution arithmetic)。
这里有一些需要了解的名词:
卷积核大小(Kernel size):卷积核在前一部分已经讨论过了。卷积核大小确定卷积的视野。
卷积步长(Stride):它确定的是卷积核滑动通过图像的步长。步长为 1 表示卷积核一个像素一个像素地滑动通过图像;步长为 2 则表示卷积核在图像上每滑动一次就移动了 2 个像素(即跳过 1 个像素)。对于下面这个案例中的图像,我们采用大于或等于 2 的步长。
填充(Padding):填充定义如何处理图像的边界。如果有必要的话,可以通过将输入边界周围的填充设置为 0,这样的话,经过填充后的卷积(Tensorflow 中的「相同」填充)就可以保持空间输出维度与输入图像的维度一样。另一方面,如果不在输入边界周围添加 0 填充,未填充的卷积(Tensorflow 中的「有效」填充)仅对输入图像的像素执行卷积,输出大小也会小于输入大小。
下图表示使用卷积核大小为 3、步长为 1;填充为 1 的 2D 卷积:
这里有一篇不错的文章(A guide to convolution arithmetic for deep learning, https://arxiv.org/abs/1603.07285 )详细地描述了算法,大家可前往阅读。这篇文章对其进行了详细介绍,并针对不同的卷积核大小、卷积步长以及填充分别进行了案例分析。这里我仅仅概括出了最常用的结果:
对于一个大小为 i、卷积核大小为 k、填充为 p 以及卷积步长为 s 的输入图像,经过卷积的输出图像的大小为 o:
6. 转置卷积(反卷积)
对于许多应用以及在许多网络架构中,我们通常需要朝与标准卷积相反的方向做转换,例如,当我们想要执行上采样(up-sampling)时。这些案例其中就包括生成高分辨率图像以及在自动编码器或语义分割中将低维度特征映射映射到高维度空间中。(在随后的案例中,语义分割首先在编码器中提取特征映射,然后在解码器中还原原始图像的大小从而能够在原始图像中对每一个像素进行分类。)
传统上,研究者可以通过应用插值(interpolation)方案或者手动创建规则来实现上采样。神经网络等现代架构则反过来趋向于让网络自己自动学习合适的转换,而不需要人类的干预。我们可以使用转置卷积来实现这一点。
在书面表达上,转置卷积也称作反卷积(deconvolution),或小数步长的卷积(fractionally strided convolution)。不过值得一提的是,将其称作「反卷积」并不是那么合适,因为转置卷积并不完全是信号/图像处理中所定义的反卷积。从技术上来说,信号处理中的反卷积是卷积的逆向操作,跟这里所说的转置卷积不一样。正因为此,一些论文作者强烈反对将转置卷积称作反卷积,而大众要这样称呼主要是为了简单起见。随后,我们会探讨为什么将这种操作称作转置卷积才是自然且更合适的。
我们可以直接使用卷积来实现转置卷积。例如在下图的案例中,我们 2 x 2 的输入上做转置卷积:其卷积核为 3 x 3,卷积步长为 1,填充为 2 x 2 的空格。上采样的输出大小为 4 x 4。
将 2 x 2 输入上采样为 4 x 4 输出,图片源自: https://github.com/vdumoulin/conv_arithmetic
非常有趣的是,研究者可以通过应用花式填充和步长,将相同的 2 x 2 输入图像映射出不同的图像大小。下图中,在同一个卷积核为 3 x 3,卷积步长为 1,填充为 2 x 2 空格的 2 x 2 的输入(输入之间插入了一个空格)上做转置卷积,得出的输出大小为 5 x 5。
将 2 x 2 输入上采样为 5 x 5 输出,图片源自: https://github.com/vdumoulin/conv_arithmetic
通过观察上述案例中的转置卷积,我们可以初步建立一些认知。但是要想较好地掌握它的应用,在电脑上看看它怎样通过矩阵乘法来实现会比较有用。从中,我们还可以了解到为什么「转置卷积」这个名字更合适。
在卷积中,我们设定卷积核为 C,输入图像为 Large,卷积输出的图像为 Small。在做卷积(矩阵乘法)后,我们将大图像下采样(down-sample)为小的输出图像。矩阵乘法中的卷积实现遵循 C x Large = Small。
下面案例显示了这项操作如何实现。它将输入也压平为 16 x 1 矩阵,之后将卷积核转换为一个稀疏矩阵 (4 x 16),接着在稀疏矩阵和压平的输入间执行矩阵乘法运算,最终得出的矩阵(4 x 1)转换回 2 x 2 的输出。
卷积的矩阵乘法:从大小 4 x 4 为 Large 输入图像到大小为 2 x 2 的 Small 输出图像
现在,如下图所示,如果我们对等式两边的矩阵 CT 进行多次转置,并利用一个矩阵和其转置矩阵相乘得出一个单元矩阵的属性,我们可以得出下面的运算公式:CT x Small = Large。
卷积的矩阵乘法:从大小 2x 2 为 Large 输入图像到大小为 4 x 4 的 Small 输出图像
正如你在这里看到的,转置卷积执行的是从小图像到大图像的上采样。这也是我们所要实现的。而现在,你也可以了解到「转置卷积」这个名字的由来。
转置卷积的通用算法可以在《深度学习的卷积算法指南》「A guide to convolution arithmetic for deep learning」这篇文章的「Relationship 13」和「Relationship 14」章节中找到。
6.1 棋盘效应(Checkerboard artifacts)
所谓的「棋盘效应」是研究人员在使用转置卷积时可以观察到的一种令人不快的现象(奇怪的棋盘格状伪影)。
「棋盘效应」的一些案例。图片源自论文「 Deconvolution and Checkerboard Artifacts」, https://distill.pub/2016/deconv-checkerboard/
《反卷积和棋盘效应》(Deconvolution and Checkerboard Artifacts, https://distill.pub/2016/deconv-checkerboard )对于这一现象有一个非常好的阐述。大家可以前往阅读这篇文章了解详细内容。这里我仅仅概括出关键点。
造成棋盘效应的原因是转置卷积的「不均匀重叠」(uneven overlap)。这种重叠会造成图像中某个部位的颜色比其他部位更深。
在下图中,顶部这层是输入层,底部这层则是操作转置卷积后的输出层。在转置卷积过程中,小的这层映射到大的那层。
在案例(a)中,其卷积步长为 1,过滤器大小为 2。正红线所标出的,输入图像上的第一个像素映射为输出图像上的第一个和第二个像素。绿线标出的则是输入图像上的第二个像素映射为输出图像上的第二个和第三个像素。这样的话,输出图像上的第二个像素就收到了输入图像上的第一个和第二个像素的双重信息,而整个卷积过程中,输出图像中间部分的像素都从输入图像中接收到了同样多的信息,这样就导致了卷积核重叠的区域。而在案例(b)中,当过滤器的大小增加到 3 时,这个接收到最多信息的中间部分缩小了。但是这样的话问题不大,因为重叠部分依旧是均匀的。在输出图像中间部分的像素从输入图像中接收到同样多的信息。
图片源自并修改于论文「Deconvolution and Checkerboard Artifacts」, https://distill.pub/2016/deconv-checkerboard/
现在针对下面的案例,我们将卷积步长改为 2。在案例(a)中,过滤器的大小为 2,输出图像上的所有像素从输入图像中接收到同样多的信息,它们都从输入图像中接收到一个像素的信息,这里就不存在转置卷带来的重叠区域。
图片源自并修改于论文「Deconvolution and Checkerboard Artifacts」, https://distill.pub/2016/deconv-checkerboard/
而在案例(b)中,当我们将过滤器大小增至 4 时,均匀的重叠区域缩小了,但是研究者依旧可以将输出图像的中间部分用作有效的输出,其中每个像素从输入图像中接收到的信息是同样多的。
然而,在案例(c)和(d)中,当过滤器大小变成 3 或 5 时,情况就变得非常有趣了。在这两个案例中,输出图像上的每个像素与其毗邻的像素所接收到的信息量都不相同。研究者在输出图像上无法找到一个连续并均匀的重叠区域。
当过滤器大小无法被卷积步长整除时,转置卷积就会出现「不均匀重叠」。这种「不均匀重叠」会造成图像中某个部位的颜色比其他部位更深,因而会带来「棋盘效应」。实际上,不均匀重叠区域会在二维上更加极端。因为二维上的两个模式会相乘,因而最终的不均匀性是原来的平方。
在应用转置卷积时,可以做两件事情来减轻这种效应。第一,确认使用的过滤器的大小是能够被卷积步长整除的,从而来避免重叠问题。第二,可以采用卷积步长为 1 的转置卷积,来减轻「棋盘效应」。然而,正如在最近许多模型中所看到的,这种效益依旧可能会显露出来。
这篇论文进一步提出了一个更好的上采样方法:首先调整图像大小(使用最近邻域内插法(Nearest Neighbor interpolation)和双向性内插法(bilinear interpolation)),然后制作一个卷积层。通过这样做,论文作者成功避免了这一「棋盘效应」。大家或许也想要在自己的应用中尝试一下这个方法吧。
(上篇)
via: https://towardsdatascience.com/a-comprehensive-introduction-to-different-types-of-convolutions-in-deep-learning-669281e58215 雷锋网
。