近年来,功能强大、功能多样的深度学习框架的出现,使得将卷积层实现到深度学习模型成为可能,这是一项极其简单的任务,通常只需一行代码即可完成。
然而,理解卷积,尤其是第一次理解卷积,常常会让人感到有些困难,因为内核、过滤器、通道等术语都是相互叠加的。然而作为一个概念的卷积是迷人地强大的、高度可扩展的。
在这篇文章中,我们将分解卷积操作的机制,一步一步地将其与标准的完全连接的网络联系起来,并探索它们如何建立强大的视觉层次结构,使其成为图像的强大功能提取器。
2D卷积:操作
2D卷积本质上是一个相当简单的操作:从一个内核开始,这只是一个小的权重矩阵。该内核在2D输入数据上“滑动”,与当前输入的部分进行元素相乘,然后将结果汇总为单个输出像素。
标准卷积
内核为其滑过的每个位置重复此过程,将2D特征矩阵转换为另一个2D特征矩阵。输出特征基本上是输入特征的加权和(权重是内核本身的值),其大致位于输入层上输出像素的相同位置。
输入特征是否落在这个大致相同的位置内,直接由它是否在产生输出的内核区域中确定。这意味着内核的大小直接决定了在生成新输出特征时合并了多少(或几个)输入特征。
这与完全连接的层形成鲜明对比。在上面的例子中,我们有5×5 = 25个输入特征,3×3 = 9个输出特征。如果这是一个标准的完全连接层,你将拥有一个25×9 = 225个参数的权重矩阵,每个输出特征都是每个输入特征的加权和。卷积允许我们只使用9个参数进行此转换,用每个输出特征,而不是查看每个输入特征,只查看来自大致相同位置的输入特征。
一些常用的技术
在我们继续之前,有必要研究在卷积层中常见的两种技术:Padding和Strides。
Padding:如果你看到上面的动画,请注意在滑动过程中,边缘基本上被修剪掉,将5×5特征矩阵转换为3×3特征矩阵。边缘上的像素永远不会位于内核的中心,因为内核没有任何东西可以扩展到边缘之外。这并不理想,因为我们通常希望输出的大小等于输入。
相同的Padding
Padding非常聪明地解决了这个问题:用额外的假像素填充边缘(通常值为0,因此经常使用的术语“零填充”)。这样,滑动时的内核可以允许原始边缘像素位于其中心,同时延伸到边缘之外的伪像素,产生与输入相同大小的输出。
Striding:通常在运行卷积层时,你需要一个尺寸小于输入的输出。这在卷积神经网络中是常见的,其中当增加信道数量时,空间维度的大小减小。实现此目的的一种方式是通过使用pooling层(例如,取每2×2网格的平均值/最大值来将每个空间维度减半)。另一种方法是使用stride:
stride的想法是跳过内核的一些滑动位置。1的步幅意味着选择一个像素分开的滑动,所以基本上每个滑动都作为标准卷积。2的步幅意味着分开2个像素的滑动,在此过程中跳过每个其他滑动,缩小大约2倍,3的步幅意味着每2个滑动跳过,大约缩小3倍,依此类推。
更现代的网络,例如ResNet架构,完全放弃了内层的pooling层,在需要减小输出尺寸时,有利于stride卷积。
多渠道版本
当然,上面的图仅涉及图像具有单个输入通道的情况。实际上,大多数输入图像都有3个通道,而且这个数字只会随着网络的深入而增加。一般来说,我们很容易把渠道看作是整体形象的一个视角,强调某些方面,而不强调其他方面。
大多数时候,我们处理具有三个通道的RGB图像
过滤器:内核的集合
因此,这是术语之间的关键区别派上用场的地方:术语之间的关键区别就派上了用场:而在1通道的情况下,术语过滤器和内核是可互换的,在一般情况下,它们实际上是非常不同的。实际上,每个过滤器都是内核的集合,对于该层的每个输入通道都有一个内核,并且每个内核都是惟一的。
卷积层中的每个过滤器都会产生一个且只有一个输出通道,它们就是这样做的:
过滤器的每个内核在其各自的输入通道上滑动,产生每个的处理版本。一些内核可能具有比其他内核更强的权重,以更多地强调某些输入通道而不是其他内核(例如,过滤器可能具有比其他内核具有权重更大的红色内核通道,因此,对红色通道特征的差异的响应比其他更多)。
然后将每个通道处理的版本汇总在一起形成一个通道。过滤器的每个内核生成每个通道的一个版本,过滤器作为一个整体生成一个整体输出通道。
最后,还有偏项。这里偏项的工作方式是每个输出过滤器都有一个偏项。到目前为止,偏差被添加到输出通道以产生最终输出通道。
对于单个过滤器,任何数量的过滤器的情况都是相同的:每个过滤器使用它自己的、不同的内核集处理输入,并使用上面描述的过程处理标量偏差,从而生成一个输出通道。然后将它们连接在一起,生成总体输出,输出通道的数量就是过滤器的数量。通常在将这个作为输入传递给另一个卷积层之前应用非线性,然后这个卷积层重复这个过程。
2D卷积:直觉
卷积仍然是线性变换:
即使卷积层的机制简化,要将它与标准的前馈网络联系起来仍然是很困难的,而且它仍然不能解释为什么卷积可以扩展到图像数据,并且对图像数据的处理效果要好得多。
假设我们有一个4×4输入,我们想将其转换为2×2网格。如果使用前馈网络,我们将4×4输入重新整形为长度为16的向量,并将其传递到具有16个输入和4个输出的密集连接层。可以看到一个层的权重矩阵W:
总而言之,有64个参数
尽管卷积内核操作起初看起来有点奇怪,但它仍然是一个带有等价变换矩阵的线性变换。如果我们在重构的4×4输入上使用大小为3的内核K来获得2×2输出,则等价变换矩阵将是:
这里只有9个参数
注意:虽然上面的矩阵是一个等价的变换矩阵,但实际操作通常为一个非常不同的矩阵乘法。
那么整个卷积仍然是一个线性变换,但与此同时它也是一种截然不同的变换。对于具有64个元素的矩阵,只有9个参数本身可以多次重复使用。每个输出节点只能看到选定数量的输入(内核中的输入)。没有任何其他输入的交互,因为它们的权重设置为0。
将卷积运算视为权重矩阵的一个hard prior是有用的。在此情境中,先验是指预定义的网络参数。例如,当用预训练的模型进行图像分类时,你使用预训练的网络参数作为先验参数,作为最终密集连接层的特征提取器。
从这个意义上说,与其他选择相比为什么两者都如此高效,存在一个直接的直觉。与随机初始化相比,迁移学习的数量级有效,因为你只需要优化最终完全连接层的参数,这意味着你可以在每个类只有几十张图像的情况下获得出色的性能。
在这里,不需要优化所有64个参数,因为我们将它们中的大多数设置为零(并且它们将保持这种方式),其余的我们将转换为共享参数,从而导致仅优化9个实际参数。这种效率非常重要,因为当你从MNIST的784输入移动到真实世界的224×224×3图像时,就会有超过15万个输入。尝试将输入减半到75000个输入的密集层仍然需要超过100 亿个参数。相比之下,整个 ResNet-50有大约2500万个参数。
因此将一些参数固定为0,并且将参数绑定可以提高效率,但与迁移学习案例不同,我们知道先验很实用,因为它适用于大量的一般图像集,我们怎么知道这会带来什么好处呢?
答案在于先前引导参数学习的特征组合。
局部性
在本文前面的部分,我们讨论过:
- 内核仅组合来自小的局部区域的像素以形成输出。也就是说,输出特征仅看到来自小局部区域的输入特征。
- 内核在整个图像中全局应用以生成输出矩阵。
因此,随着反向传播从网络的分类节点一路而来,内核有一个有趣的任务:学习权重,只从一组本地输入生成特性。此外,由于内核本身应用于整个映像,因此内核学到的特性必须足够通用,可以来自映像的任何部分。
如果这是任何其他类型的数据,例如应用程序安装的分类数据,这将是一场灾难,因为你的应用程序安装数量和应用程序类型列彼此相邻,并不意味着它们具有与应用程序安装日期相同的任何本地,共享功能和使用的时间。
当然,这四个可能有一个潜在的更高级别的功能(例如,找到人们最想要的应用程序),但这使我们没有理由相信前两个参数与后两个参数完全相同。这四个可能是任何(一致的)顺序,并且仍然有效!
然而,像素总是以一致的顺序出现,并且附近的像素影响像素,例如,如果所有附近的像素都是红色,则很可能像素也是红色的。如果有偏差,这是一个有趣的异常,可以转换成一个特征,所有这些都可以通过比较一个像素与其相邻像素,以及其所在位置的其他像素检测出来。
而这个想法实际上是许多早期计算机视觉特征提取方法的基础。例如,对于边缘检测,可以使用Sobel边缘检测滤波器,具有固定参数的内核,就像标准的单通道卷积一样运行:
对于包含非边缘的网格(例如背景天空),大多数像素都是相同的值,因此该点内核的总输出为0。
对于具有垂直边缘的网格,存在差异边缘左侧和右侧的像素,内核计算该差异为非零,激活并显示边缘。内核一次只能处理3×3网格,检测局部尺度上的异常,但是当应用于整个图像时,足以在图像中的任何位置检测全局范围内的某个特征。
因此,深度学习的关键不同之处在于,我们要问这样一个问题:我们能学到有用的内核吗?
对于在原始像素上操作的早期层,我们可以合理地期望相当低级别的特征检测器,如边缘、线等。
深入学习研究的整个分支专注于使神经网络模型可解释。其中最强大的工具之一是使用优化的特征可视化。核心思想很简单:优化图像(通常用随机噪声初始化)以尽可能强烈地激活滤波器。这确实具有直观意义:如果优化的图像完全被边缘填充,那就是过滤器本身正在寻找并被激活的强有力证据。使用这个,我们可以查看学习过滤器,结果令人惊叹:
从GoogLeNet的第一卷积层开始,对3个不同的通道进行特征可视化。注意,虽然它们检测不同类型的边缘,但它们仍然是低级边缘检测器。
来自第2和第3卷的通道12的特征可视化
这里要注意的一件重要事情是卷积图像仍然是图像。从图像左上角开始的小像素网格输出仍然位于左上角。因此,你可以在另一个卷积层(例如左侧的两个)上运行另一个卷积层,以提取可视化更深层次的特征。
然而,无论我们的特征探测器有多深,在没有进一步改变的情况下,它们仍将在非常小的图像块上运行。无论你的探测器有多深,你都无法从3×3网格中探测到面部。接下来就应该引入接受域了。
接受域
任何CNN架构的基本设计选择是从网络的开始到结束,输入大小越来越小,而信道的数量越来越多。如前所述,这通常通过跨步或汇集层来完成。局部性决定了输出可以看到前一层的输入。感知字段确定输出可以看到的整个网络的原始输入的哪个区域。
至于跨步卷积,是我们只处理固定距离的幻灯片,并跳过中间的幻灯片。从不同的角度来看,我们只将输出保持固定的距离,并删除剩余的。
3×3卷积,步幅2
然后,将非线性应用于输出,并且按照惯例,然后在顶部堆叠另一个新的卷积层。即使我们将具有相同局部区域的相同大小(3×3)的内核应用于跨步卷积的输出,内核也将具有更大的有效感受域:
这是因为跨步层的输出仍然代表相同的图像。与其说是裁剪,不如说是调整大小,唯一的问题是输出中的每一个像素都代表了一个更大的区域(其中的其他像素被丢弃了),该区域与原始输入的大致位置相同。因此,当下一层的s内核对输出进行操作时,它对从更大区域收集的像素进行操作。
如我们在mixed3a层中看到的那样,接受域的这种扩展允许卷积层将低级特征(线,边)组合成更高级别的特征(曲线,纹理)。
随后是一个汇集/跨步层,网络继续为更高级别的功能(部件,模式)创建探测器,正如我们在mixed4a中看到的那样。
与输入224×224相比,通过网络上的第5个块,网络上图像大小的重复减少导致输入大小仅为7×7。此时,每个单个像素表示32×32像素的网格,这是非常大的。
与早期的层相比,激活意味着检测边缘,在这里,微小的7×7网格上的激活是一个高级别的特征,例如鸟类。
整个网络从少量过滤器(GoogLeNet为64)检测低级特征,到大量过滤器(最终卷积为1024),每个过滤器都在寻找极其特定的高级特征。接下来是最终的汇集层,它将每个7×7网格折叠成一个像素,每个通道都是一个特征检测器,其接受域相当于整个图像。
与标准的前馈网络相比,这里的输出简直令人惊叹。标准前馈网络将从图像中的每个单个像素的组合产生抽象特征向量,这需要训练大量的数据。
带着先验知识,CNN从学习非常低层次的特征检测器开始,随着其接受域的扩展,跨层学习如何将这些低层次的特征组合成逐步提高的层次特征;不是每个像素的抽象组合,而是概念的强大视觉层次结构。
通过检测低层特征,并使用它们在视觉层次上检测高层特征,它最终能够检测整个视觉概念,如人脸、鸟类、树木等,这使得它们在处理图像数据时如此强大而高效。
关于对抗性攻击的一点提示
在CNN构建的视觉层次结构中,假设他们的视觉系统与人类相似是非常合理的。它们在处理真实世界的图像方面非常出色,但它们也有一些缺陷,这强烈表明它们的视觉系统并不完全像人类。最主要的问题:对抗性的例子,这些例子被特别修改以愚弄模型。
对于人类而言,两幅图像显然都是大熊猫。对模型而言则不是
如果被篡改的那些是人类会注意到的,那么对抗性的例子是没什么问题的。但这些模型很容易受到样本的攻击,某些样本只是被轻微篡改过,这使模型可能会悄然失效,而这对于从自动驾驶汽车到医疗保健等应用来说非常危险。
对抗攻击的强大功能目前是一个非常活跃的研究领域,解决方案会改善CNN架构,使其变得更安全,更可靠。
结论
CNN是允许计算机视觉从简单应用扩展到复杂产品和服务的模型,它们可能是未来计算机视觉的关键方法,或者引发一些新的突破。无论如何,有一件事是肯定的:它们是令人惊叹的,是许多当今创新应用的核心,非常值得人们去深刻理解。