乐读窝

深度学习

乐读窝 > 文学理论 > 深度学习

9.5 基本卷积函数的变体

书籍名:《深度学习》    作者:伊恩.古德费洛



当在神经网络的上下文中讨论卷积时,我们通常不是特指数学文献中使用的那种标准的离散卷积运算。实际应用中的函数略有不同。这里我们详细讨论一下这些差异,并且对神经网络中用到的函数的一些重要性质进行重点说明。

首先,当提到神经网络中的卷积时,我们通常是指由多个并行卷积组成的运算。这是因为具有单个核的卷积只能提取一种类型的特征,尽管它作用在多个空间位置上。我们通常希望网络的每一层能够在多个位置提取多种类型的特征。

另外,输入通常也不仅仅是实值的网格,而是由一系列观测数据的向量构成的网格。例如,一幅彩色图像在每一个像素点都会有红、绿、蓝三种颜色的亮度。在多层的卷积网络中,第二层的输入是第一层的输出,通常在每个位置包含多个不同卷积的输出。当处理图像时,我们通常把卷积的输入输出都看作3维的张量,其中一个索引用于标明不同的通道(例如红、绿、蓝),另外两个索引标明在每个通道上的空间坐标。软件实现通常使用批处理模式,所以实际上会使用4维的张量,第4维索引用于标明批处理中不同的实例,但我们为简明起见这里忽略批处理索引。

因为卷积网络通常使用多通道的卷积,所以即使使用了核翻转,也不一定保证网络的线性运算是可交换的。只有当其中每个运算的输出和输入具有相同的通道数时,这些多通道的运算才是可交换的。

假定我们有一个4维的核张量K,它的每一个元素是Ki,j,k,l,表示输出中处于通道i的一个单元和输入中处于通道j中的一个单元的连接强度,并且在输出单元和输入单元之间有k行l列的偏置。假定我们的输入由观测数据V组成,它的每一个元素是Vi,j,k,表示处在通道i中第j行第k列的值。假定我们的输出Z和输入V具有相同的形式,如果输出Z是通过对K和V进行卷积而不涉及翻转K得到的,那么

这里对所有的l、m和n进行求和是对所有(在求和式中)有效的张量索引的值进行求和。在线性代数中,向量的索引通常从1开始,这就是上述公式中-1的由来。但是像C或Python这类编程语言索引通常从0开始,这使得上述公式可以更加简洁。

我们有时会希望跳过核中的一些位置来降低计算的开销(相应的代价是提取特征没有先前那么好了)。我们可以把这一过程看作对全卷积函数输出的下采样(downsampling)。如果只想在输出的每个方向上每间隔s个像素进行采样,那么我们可以定义一个下采样卷积函数c使得

我们把s称为下采样卷积的步幅(stride)。当然也可以对每个移动方向定义不同的步幅。图9.12演示了一个实例。

图9.12 带有步幅的卷积。在这个例子中,我们的步幅为2。(上)在单个操作中实现的步幅为2的卷积。(下)步幅大于一个像素的卷积在数学上等价于单位步幅的卷积随后降采样。显然,涉及降采样的两步法在计算上是浪费的,因为它计算了许多将被丢弃的值

在任何卷积网络的实现中都有一个重要性质,那就是能够隐含地对输入V用零进行填充(pad)使得它加宽。如果没有这个性质,表示的宽度在每一层就会缩减,缩减的幅度是比核少一个像素这么多。对输入进行零填充允许我们对核的宽度和输出的大小进行独立的控制。如果没有零填充,我们就被迫面临二选一的局面,要么选择网络空间宽度的快速缩减,要么选择一个小型的核——这两种情境都会极大得限制网络的表示能力。图9.13给出了一个例子。

图9.13 零填充对网络大小的影响。考虑一个卷积网络,每层有一个宽度为6的核。在这个例子中,我们不使用任何池化,所以只有卷积操作本身缩小网络的大小。(上)在这个卷积网络中,我们不使用任何隐含的零填充。这使得表示在每层缩小5个像素。从16个像素的输入开始,我们只能有3个卷积层,并且最后一层不能移动核,所以可以说只有两层是真正的卷积层。可以通过使用较小的核来减缓收缩速率,但是较小的核表示能力不足,并且在这种结构中一些收缩是不可避免的。(下)通过向每层添加5个隐含的零,我们防止了表示随深度收缩。这允许我们设计一个任意深的卷积网络

有三种零填充设定的情况值得注意。第一种是无论怎样都不使用零填充的极端情况,并且卷积核只允许访问那些图像中能够完全包含整个核的位置。在MATLAB的术语中,这称为有效(valid)卷积。在这种情况下,输出的所有像素都是输入中相同数量像素的函数,这使得输出像素的表示更加规范。然而,输出的大小在每一层都会缩减。如果输入的图像宽度是m,核的宽度是k,那么输出的宽度就会变成m-k+1。如果卷积核非常大,缩减率会非常显著。因为缩减数大于0,这限制了网络中能够包含的卷积层的层数。当层数增加时,网络的空间维度最终会缩减到1×1,这种情况下增加的层就不可能进行有意义的卷积了。第二种特殊的情况是只进行足够的零填充来保持输出和输入具有相同的大小。在MATLAB的术语中,这称为相同(same)卷积。在这种情况下,只要硬件支持,网络就能包含任意多的卷积层,这是因为卷积运算不改变下一层的结构。然而,输入像素中靠近边界的部分相比于中间部分对于输出像素的影响更小。这可能会导致边界像素存在一定程度的欠表示。这使得第三种极端情况产生了,在MATLAB中称为全(full)卷积。它进行了足够多的零填充,使得每个像素在每个方向上恰好被访问了k次,最终输出图像的宽度为m+k-1。在这种情况下,输出像素中靠近边界的部分相比于中间部分是更少像素的函数。这将导致学得一个在卷积特征映射的所有位置都表现不错的单核更为困难。通常零填充的最优数量(对于测试集的分类正确率)处于“有效卷积”和“相同卷积”之间的某个位置。

在一些情况下,我们并不是真的想使用卷积,而是想用一些局部连接的网络层(LeCun,1986,1989)。在这种情况下,我们的多层感知机对应的邻接矩阵是相同的,但每一个连接都有它自己的权重,用一个6维的张量W来表示。W的索引分别是:输出的通道i,输出的行j和列k,输入的通道l,输入的行偏置m和列偏置n。局部连接层的线性部分可以表示为

这有时也被称为非共享卷积(unshared  convolution),因为它和具有一个小核的离散卷积运算很像,但并不横跨位置来共享参数。图9.14比较了局部连接、卷积和全连接的区别。

图9.14 局部连接,卷积和全连接的比较。(上)每一小片(接受域)有两个像素的局部连接层。每条边用唯一的字母标记,来显示每条边都有自身的权重参数。(中)核宽度为两个像素的卷积层。该模型与局部连接层具有完全相同的连接。区别不在于哪些单元相互交互,而在于如何共享参数。局部连接层没有参数共享。正如用于标记每条边的字母重复出现所指示的,卷积层在整个输入上重复使用相同的两个权重。(下)全连接层类似于局部连接层,它的每条边都有其自身的参数(在该图中用字母明确标记就太多了)。然而,它不具有局部连接层的连接受限的特征

当我们知道每一个特征都是一小块空间的函数并且相同的特征不会出现在所有的空间上时,局部连接层是很有用的。例如,如果想要辨别一张图片是否是人脸图像,我们只需要去寻找嘴是否在图像下半部分即可。

使用那些连接被更进一步限制的卷积或者局部连接层也是有用的,例如,限制每一个输出的通道i仅仅是输入通道l的一部分的函数时。实现这种情况的一种通用方法是使输出的前m个通道仅仅连接到输入的前n个通道,输出的接下来的m个通道仅仅连接到输入的接下来的n个通道,以此类推。图9.15给出了一个例子。对少量通道间的连接进行建模允许网络使用更少的参数,这降低了存储的消耗以及提高了统计效率,并且减少了前向和反向传播所需要的计算量。这些目标的实现并没有减少隐藏单元的数目。

图9.15 卷积网络的前两个输出通道只和前两个输入通道相连,随后的两个输出通道只和随后的两个输入通道相连

平铺卷积(tiled  convolution)(Gregor  and  LeCun,2010a;Le  et  al.,2010)对卷积层和局部连接层进行了折衷。这里并不是对每一个空间位置的权重集合进行学习,我们学习一组核使得当我们在空间移动时它们可以循环利用。这意味着在近邻的位置上拥有不同的过滤器,就像局部连接层一样,但是对于这些参数的存储需求仅仅会增长常数倍,这个常数就是核的集合的大小,而不是整个输出的特征映射的大小。图9.16对局部连接层、平铺卷积和标准卷积进行了比较。

图9.16 局部连接层、平铺卷积和标准卷积的比较。当使用相同大小的核时,这三种方法在单元之间具有相同的连接。此图是对使用两个像素宽的核的说明。这三种方法之间的区别在于它们如何共享参数。(上)局部连接层根本没有共享参数。我们对每个连接使用唯一的字母标记,来表明每个连接都有它自身的权重。(中)平铺卷积有t个不同的核。这里我们说明t=2的情况。其中一个核具有标记为“a”和“b”的边,而另一个具有标记为“c”和“d”的边。每当我们在输出中右移一个像素后,我们使用一个不同的核。这意味着,与局部连接层类似,输出中的相邻单元具有不同的参数。与局部连接层不同的是,在遍历所有可用的t个核之后,我们循环回到了第一个核。如果两个输出单元间隔t个步长的倍数,则它们共享参数。(下)传统卷积等效于t=1的平铺卷积。它只有一个核,并且被应用到各个地方,我们在图中表示为在各处使用具有标记为“a”和“b”的边的核

为了用代数的方法定义平铺卷积,令K是一个6维的张量(3),其中的两维对应着输出映射中的不同位置。K在这里并没有对输出映射中的每一个位置使用单独的索引,输出的位置在每个方向上在t个不同的核组成的集合中进行循环。如果t等于输出的宽度,这就是局部连接层了。

这里百分号是取模运算,它的性质包括t%t=0,(t+1)%t=1等。在每一维上使用不同的t可以很容易对这个方程进行扩展。

局部连接层与平铺卷积层都和最大池化有一些有趣的关联:这些层的探测单元都是由不同的过滤器驱动的。如果这些过滤器能够学会探测相同隐含特征的不同变换形式,那么最大池化的单元对于学得的变换就具有不变性(见图9.9)。卷积层对于平移具有内置的不变性。

实现卷积网络时,通常也需要除卷积以外的其他运算。为了实现学习,必须在给定输出的梯度时能够计算核的梯度。在一些简单情况下,这种运算可以通过卷积来实现,但在很多我们感兴趣的情况下,包括步幅大于1的情况,并不具有这样的性质。

回忆一下,卷积是一种线性运算,所以可以表示成矩阵乘法的形式(如果我们首先把输入张量变形为一个扁平的向量)。其中包含的矩阵是关于卷积核的函数。这个矩阵是稀疏的,并且核的每个元素都复制给矩阵的多个元素。这种观点能够帮助我们导出实现一个卷积网络所需的很多其他运算。

通过卷积定义的矩阵转置的乘法就是这样一种运算。这种运算用于在卷积层反向传播误差的导数,所以它在训练多于一个隐藏层的卷积网络时是必要的。如果我们想要从隐藏层单元重构可视化单元时,同样的运算也是需要的(Simard  et  al.,1992)。重构可视化单元是本书第3部分的模型广泛用到的一种运算,这些模型包括自编码器、RBM和稀疏编码等。构建这些模型的卷积化的版本都要用到转置化卷积。类似核梯度运算,这种输入梯度运算在某些情况下可以用卷积来实现,但在一般情况下需要用到第三种运算来实现。必须非常小心地来使这种转置运算和前向传播过程相协调。转置运算返回的输出的大小取决于三个方面:零填充的策略、前向传播运算的步幅以及前向传播的输出映射的大小。在一些情况下,不同大小的输入通过前向传播过程能够得到相同大小的输出映射,所以必须明确地告知转置运算原始输入的大小。

这三种运算——卷积、从输出到权重的反向传播和从输出到输入的反向传播——对于训练任意深度的前馈卷积网络,以及训练带有(基于卷积的转置的)重构函数的卷积网络,这三种运算都足以计算它们所需的所有梯度。对于完全一般的多维、多样例情况下的公式,完整的推导可以参考Goodfellow(2010)。为了直观说明这些公式是如何起作用的,我们这里给出一个二维单个样例的版本。

假设我们想要训练这样一个卷积网络,它包含步幅为s的步幅卷积,该卷积的核为K,作用于多通道的图像V,定义为c(K,V,s),就像式(9.8)中一样。假设我们想要最小化某个损失函数J(V,K)。在前向传播过程中,我们需要用c本身来输出Z,然后Z传递到网络的其余部分并且被用来计算损失函数J。在反向传播过程中,我们会得到一个张量G满足。

为了训练网络,我们需要对核中的权重求导。为了实现这个目的,我们可以使用一个函数

如果这一层不是网络的底层,我们需要对V求梯度来使得误差进一步反向传播。我们可以使用如下的函数

第14章描述的自编码器网络,是一些被训练成把输入拷贝到输出的前馈网络。一个简单的例子是PCA算法,将输入x拷贝到一个近似的重构值r,通过函数来实现。使用权重矩阵转置的乘法,就像PCA算法这种,在一般的自编码器中是很常见的。为了使这些模型卷积化,我们可以用函数h来实现卷积运算的转置。假定我们有和Z相同形式的隐藏单元H,并且我们定义一种重构运算

为了训练自编码器,我们会得到关于R的梯度,表示为一个张量E。为了训练解码器,我们需要获得对于K的梯度,这通过g(H,E,s)来得到。为了训练编码器,我们需要获得对于H的梯度,这通过c(K,E,s)来得到。通过用c和h对g求微分也是可行的,但这些运算对于任何标准神经网络上的反向传播算法来说都是不需要的。

一般来说,在卷积层从输入到输出的变换中我们不仅仅只用线性运算。我们一般也会在进行非线性运算前,对每个输出加入一些偏置项。这样就产生了如何在偏置项中共享参数的问题。对于局部连接层,很自然地对每个单元都给定它特有的偏置,对于平铺卷积,也很自然地用与核一样的平铺模式来共享参数。对于卷积层来说,通常的做法是在输出的每一个通道上都设置一个偏置,这个偏置在每个卷积映射的所有位置上共享。然而,如果输入是已知的固定大小,也可以在输出映射的每个位置学习一个单独的偏置。分离这些偏置可能会稍稍降低模型的统计效率,但同时也允许模型来校正图像中不同位置的统计差异。例如,当使用隐含的零填充时,图像边缘的探测单元接收到较少的输入,因此需要较大的偏置。