目录
深度前馈网络
实例:学习xor
基于梯度的学习
代价函数
用最大似然学习条件分布
学习条件统计量
输出单元
用于高斯输出分布的线性单元
用于Bernoulli 输出分布的sigmoid 单元
用于Multinoulli 输出分布的softmax 单元
其他的输出类型
隐藏单元
整流线性单元及其扩展
logistic sigmoid与双曲正切函数
其他隐藏单元
结构设计
BP和其他的微分算法
深度前馈网络(deep feedforward network),也叫作前馈神经网络(feedforward neural network) 或者多层感知机(multilayer perceptron, MLP),是典型的深度学习模型。前馈网络的目标是近似某个函数f*。例如,对于分类器,将输入x 映射到一个类别y。前馈网络定义了一个映射,并且学习参数的值,使它能够得到最佳的函数近似。
这种模型被称为前向(feedforward) 的,是因为信息流过x 的函数,流经用于定义f 的中间计算过程,最终到达输出y。在模型的输出和模型本身之间没有反馈(feedback) 连接。当前馈神经网络被扩展成包含反馈连接时,它们被称为循环神经网络。
前馈网络对于机器学习的从业者是极其重要的。它们是许多重要商业应用的基础。例如,用于对照片中的对象进行识别的卷积神经网络就是一种专门的前馈网络。前馈网络是向循环网络前进中的概念莫基石,后者在自然语言的许多应用中发挥着巨大作用。
前馈神经网络被称作网络( network)是因为它们通常用许多不同函数复合在一起来表示。该模型与ー个有向无环图相关联,而图描述了函数是如何复合在一起的。例如,我们有三个函数f(1),f(2)和f(3)连接在一个链上以形成f(x)=f3(f2(f1(x)))。这些链式结构是神经网络中最常用的结构。在这种情况下,f1被称为网络的第一层( first layer),f2被称为第二层( second layer),以此类推。链的全长称为模型的深度( depth)。正是因为这个术语オ出现了“深度学习”这个名字。前馈网络的最后一层被称为输出层( output layer)。在神经网络训练的过程中,我们让f(x)去匹配的值。训练数据为我们提供了在不同训练点上取值的、含有噪声的的近似实例。每个样例x都伴随着一个标签。训练样例直接指明了输出层在每一点x上必须做什么;它必须产生一个接近y的值。
但是训练数据并没有直接指明其他层应该怎么做。学习算法必须决定如何使用这些层来产生想要的输出,但是训练数据并没有说每个单独的层应该做什么。相反,学习算法必须决定如何使用这些层来最好地实现的近似。因为训练数据并没有给出这些层中的每一层所需的输出,所以这些层被称为隐藏层(hidden layer)。
最后,这些网络被称为神经网络是因为它们或多或少地受到神经科学的启发。网络中的每个隐藏层通常都是向量值的。这些隐藏层的维数决定了模型的宽度(width)。向量的每个元素都可以被视为起到类似一个神经元的作用。除了将层想象成向量到向量的单个函数,我们也可以把层想象成由许多并行操作的单元(unit) 组成,每个单元表示一个向量到标量的函数。每个单元在某种意义上类似一个神经元,它接收的输入来源于许多其他的单元,并且计算它自己的激活值。使用多层向量值表示的想法来源于神经科学。用于计算这些表示的函数的选择,也或多或少地受到神经科学观测的指引,这些观测是关于生物神经元计算功能的。然而,现代的神经网络研究受到更多的是来自许多数学和工程学科的指引,并且神经网络的目标并不是完美地给大脑建模。我们最好将前馈神经网络想成是为了实现统计泛化而设计出的函数近似机器,它偶尔从我们了解的大脑中提取灵感但是并不是大脑功能的模型。
一种理解前馈网络的方式是从线性模型开始,并考虑如何克服它的局限性。线性模型,例如逻辑回归和线性回归,是非常吸引人的,因为无论是封闭形式还是使用凸优化,它们都能高效而可靠地拟合。线性模型也有明显的缺陷,那就是该模型的能力被局限在线性函数里,所以它无法理解任何两个输入变量间的相互作用。
为了扩展线性模型来表示x的非线性函数,我们可以把线性模型不用在x本身,而是用在一个变换后的输入ϕ(x) 上,这里ϕ是一个非线性变换。等价地,我们可以使用5.7.2节中描述的核技巧,来得到一个基于隐含地使用ϕ映射的非线性学习算法。我们可以认为ϕ提供了一组描述x的特征,或者认为它提供了x的一个新的表示。剩下的问题就是如何选择映射ϕ。
这种通过学习特征来改善模型的一般化原则不止适用于本章描述的前馈神经网络。它是深度学习中反复出现的主题,适用于全书描述的所有种类的模型。前馈神经网络是这个原则的应用,它学习从x到y的确定性映射并且没有反馈连接。后面出现的其他模型会把这些原则应用到学习随机映射、学习带有反馈的函数以及学习单个向量的概率分布。
本章我们先从前馈网络的一个简单例子说起。接着,我们讨论部署一个前馈网络所需的每个设计决策。首先,训练一个前馈网络至少需要做和线性模型同样多的设计决策:选择一个优化模型,代价函数以及输出单元的形式。我们先回顾这些基于梯度学习的基本知识,然后去面对那些只出现在前馈网络中的设计决策。前馈网络已经引入了隐藏层的概念,这需要我们去选择用于计算隐藏层值的激活函数(activation function)。我们还必须设计网络的结构,包括网络应该包含多少层、这些层应该如何连接,以及每一层包含多少单元。在深度神经网络的学习中需要计算复杂函数的梯度。我们给出反向传播(back propagation) 算法和它的现代推广,它们可以用来高效地计算这些梯度。最后,我们以某些历史观点来结束这一章。
为了使前馈网络的想法更加具体,我们首先从前馈网络充分发挥作用的一个简单例子说起:学习XOR 函数。
XOR函数(‘‘异或’’ 逻辑)是两个二进制值x1 和x2 的运算。当这些二进制值中恰好有一个为1 时,XOR 函数返回值为1。其余情况下返回值为0。XOR函数提供了我们想要学习的目标函数。我们的模型给出了一个函数并且我们的学习算法会不断调整参数来使得尽可能接近。
在这个简单的例子中,我们不会关心统计泛化。我们希望网络在这四个点上表现正确。我们会用全部这四个点来训练我们的网络,唯一的挑战是拟合训练集。我们可以把这个问题当作是回归问题,并使用均方误差损失函数。我们选择这个损失函数是为了尽可能简化本例中用到的数学。在应用领域,对于二进制数据建模时,MSE通常并不是一个合适的损失函数。更加合适的方法将在6.2.2.2节中讨论。
为了对在整个训练集上的表现进行评估,MSE损失函数为
我们现在必须要选择我们模型的形式。假设我们选择一个线性模型,包含w和b,那么我们的模型被定义成
我们可以用正规方程对w和b最小化,来得到一个封闭形式的解。
解正规方程以后,我们得到w=0以及b=1/2。线性模型仅仅是在任意一点都输出0.5。为什么会发生这种事?图6.1演示了线性模型为什么不能用来表示XOR函数。解决这个问题的其中一种方法是使用一个模型来学习ー个不同的特征空间,在这个空间上线性模型能够表示这个解。
具体来说,我们这里引入一个非常简单的前馈神经网络,它有一层隐藏层并且隐藏层中包含两个单元。参见图6.2中对该模型的解释。
这个前馈网络有一个通过函数计算得到的隐藏单元的向量h。这些隐藏单元的值随后被用作第二层的输入。第二层就是这个网络的输出层。输出层仍然只是一个线性回归模型,只不过现在它作用于h而不是x。网络现在包含链接在一起的两个函数和,完整的模型是。
应该是哪种函数?线性模型到目前为止都表现不错,让也是线性的似乎很有诱惑力。不幸的是,如果是线性的,那么前馈网络作为一个整体对于输入仍然是线性的。暂时忽略截距项,假设并且,那么。我们可以将这个函数重新表示成其中
显然,我们必须用非线性函数来描述这些特征。大多数神经网络通过仿射变换之后紧跟着一个被称为激活函数的固定非线性函数来实现这个目标,其中仿射变换由学得的参数控制。我们这里使用这种策略,定义,其中W是线性变换的权重矩阵,c是偏置。先前,为了描述线性回归模型,我们使用权重向量和一个标量的偏置参数来描述从输入向量到输出标量的仿射变换。现在,因为我们描述的是向量x到向量h的仿射变换,所以我们需要一整个向量的偏置参数。激活函数g通常选择对每个元素分别起作用的函数,有。在现代神经网络中,默认的推荐是使用由激活函数定义的整流线性单元( rectified inear unit)或者称为ReLU( Jarrett et al,2009b; Inair and Hinton2010a; Glorot et al.,2011a),如图6.3所示。
我们现在可以指明我们的整个网络是
我们现在可以给出XOR 问题的一个解。令
以及b = 0。
我们现在可以了解这个模型如何处理一批输入。令X表示设计矩阵,它包含二进制输入空间中全部的四个点,每个样例占一行,那么矩阵表示为:
神经网络的第一层是将输入矩阵乘以第一层的权重矩阵:
然后,加上偏置向量c,得到
在这个空间中,所有的样例都处在一条斜率为1 的直线上。当我们沿着这条直线移动时,输出需要从0 升到1,然后再降回0。线性模型不能实现这样一种函数。为了用h对每个样例求值,我们使用整流线性变换:
这个变换改变了样例间的关系。它们不再处于同一条直线上了。如图6.3所示,它们现在处在一个可以用线性模型解决的空间上。
我们最后乘以一个权重向量w:
神经网络对这一批次中的每个样例都给出了正确的结果。
在这个例子中,我们简单地指明了答案,然后说明它得到的误差为零。在实际情况中,可能会有数十亿的模型参数以及数十亿的训练样本,所以不能像我们这里做的那样进行简单地猜解。与之相对的,基于梯度的优化算法可以找到一些参数使得产生的误差非常小。我们这里给出的XOR问题的解处在损失函数的全局最小点,所以梯度下降算法可以收敛到这一点。梯度下降算法还可以找到XOR问题一些其
他的等价解。梯度下降算法的收敛点取决于参数的初始值。在实践中,梯度下降通常不会找到像我们这里给出的那种干净的、容易理解的、整数值的解。
设计和训练神经网络与使用梯度下降训练其他任何机器学习模型并没有太大不同。在5.10节中,我们描述了如何通过指明一个优化过程、代价函数和一个模型族来构建一个机器学习算法。
我们到目前为止看到的线性模型和神经网络的最大区别,在于神经网络的非线性导致大多数我们感兴趣的损失函数都成为了非凸的。这意味着神经网络的训练通常使用的迭代的、基于梯度的优化,仅仅使得代价函数达到一个非常小的值;而不是像用于训练线性回归模型的线性方程求解器,或者用于训练逻辑回归或SVM的凸优化算法那样具有全局的收敛保证。凸优化从任何一种初始参数出发都会收敛(理论上如此——在实践中也很鲁棒但可能会遇到数值问题)。用于非凸损失函数的随机梯度下降没有这种收敛性保证,并且对参数的初始值很敏感。对于前馈神经网络,将所有的权重值初始化为小随机数是很重要的。偏置可以初始化为零或者小的正值。这种用于训练前馈神经网络以及几乎所有深度模型的迭代的基于梯度的优化算法会在第八章详细介绍,参数初始化会在8.4节中具体说明。就目前而言,只需要懂得,训练算法几乎总是基于使用梯度来使得代价函数下降的各种方法即可。一些特别的算法是对梯度下降思想的改进和提纯,在4.3节中介绍,还有一些更特别的,大多数是对随机梯度下降算法的改进,在5.9节中介绍。
我们当然也可以用梯度下降来训练诸如线性回归和支持向量机之类的模型,并且事实上当训练集相当大时这是很常用的。从这点来看,训练神经网络和训练其他任何模型并没有太大区别。计算梯度对于神经网络会略微复杂一些,但仍然可以很高效而精确地实现。6.5节将会介绍如何用反向传播算法以及它的现代扩展算法来求得梯度。
和其他的机器学习模型一样,为了使用基于梯度的学习方法我们必须选择一个代价函数,并且我们必须选择如何表示模型的输出。现在,我们重温这些设计上的考虑,并且特别强调神经网络的情景。
深度神经网络设计中的一个重要方面是代价函数的选择。幸运的是,神经网络的代价函数或多或少是和其他的参数模型例如线性模型的代价函数相同的。
在大多数情况下,我们的参数模型定义了一个分布并且我们简单地使用最大似然原理。这意味着我们使用训练数据和模型预测间的交叉熵作为代价函数。
有时我们使用一个更简单的方法,不是预测y的完整概率分布,而是仅仅预测在给定x的条件下y的某种统计量。某些专门的损失函数允许我们来训练这些估计量的预测器。
用于训练神经网络的完整的代价函数,通常在我们这里描述的基本代价函数的基础上结合一个正则项。我们已经在5.2.2节中看到正则化应用到线性模型中的一些简单的例子。用于线性模型的权值衰减方法也直接适用于深度神经网络,而且是最流行的正则化策略之一。用于神经网络的更高级的正则化策略会在第七章中讨论。
大多数现代的神经网络使用最大似然来训练。这意味着代价函数就是负的对数似然,它与训练数据和模型分布间的交叉熵等价。这个代价函数表示为
代价函数的具体形式随着模型而改变,取决于的具体形式。上述方程的展开形式通常会有一些项不依赖于模型的参数,我们可以舍去。例如,正如我们在5.1.1节中看到的,如果,那么我们恢复均方误
差代价,
至少系数1/2和常数项不依赖于。舍弃的常数是基于高斯分布的方差,在这种情况下我们选择不把它参数化。先前,我们看到了对输出分布的最大似然估计和对线性模型均方误差的最小化之间的等价性,但事实上,这种等价性并不要求用于预测高斯分布的均值。
使用最大似然来导出代价函数的方法的一个优势是,它减轻了为每个模型设计代价函数的负担。明确一个模型则自动地确定了一个代价函数。
贯穿神经网络设计的一个反复出现的主题是代价函数的梯度必须足够的大和具有足够的预测性,来为学习算法提供一个好的指引。饱和(变得非常平)的函数破坏了这一目标,因为它们把梯度变得非常小。这在很多情况下都会发生,因为用于产生隐藏单元或者输出单元的输出的激活函数会饱和。负的对数似然帮助我们在很多模型中避免这个问题。很多输出单元都会包含一个指数函数,这在它的变量取绝
对值非常大的负值时会造成饱和。负对数似然代价函数中的对数函数消除了某些输出单元中的指数效果。我们将会在6.2.2节中讨论代价函数和输出单元的选择间的交互关系。
用于实现最大似然估计的交叉熵代价函数有一个不同寻常的特性,那就是当它被应用于实践中经常遇到的模型时,它通常没有最小值。对于离散型输出变量,大多数模型以一种特殊的形式来参数化,即它们不能表示概率零和一,但是可以无限接近。逻辑回归是其中一个例子。对于实值的输出变量,如果模型可以控制输出分布的密度(例如,通过学习高斯输出分布的方差参数),那么它可能对正确的训练集输出赋予极其高的密度,这将导致交叉熵趋向负无穷。第七章中描述的正则化技术提供了一些不同的方法来修正学习问题,所以模型不会通过这种方式来获得无限制的收益。
有时我们并不是想学习一个完整的概率分布,而仅仅是想学习在给定x时y的某个条件统计量。
例如,我们可能有一个预测器,我们想用它来预测y的均值。如果我们使用一个足够强大的神经网络,我们可以认为这个神经网络能够表示一大类函数中的任何一个函数,这个类仅仅被一些特征所限制,例如连续性和有界,而不是具有特殊的参数形式。从这个角度来看,我们可以把代价函数看作是一个泛函(functional) 而不仅仅是一个函数。泛函是函数到实数的映射。我们因此可以将学习看作是选择一个函数而不仅仅是选择一组参数。我们可以设计代价泛函在我们想要的某些特殊函数处取得最小值。例如,我们可以设计一个代价泛函,使它的最小值处于一个特殊的函数上,这个函数将x映射到给定x时y的期望值。对函数求解优化问题需要用到变分法(calculus of variations) 这个数学工具,我们将在19.4.2节中讨论。理解变分法对于理解本章的内容不是必要的。目前,只需要知道变分法可以被用来导出下面的两个结果。
我们使用变分法导出的第一个结果是解优化问题
得到
要求这个函数处在我们要优化的类里。换句话说,如果我们能够用无穷多的、来源于真实的数据生成分布的样例进行训练,最小化均方误差代价函数将得到一个函数,它可以用来对每个x的值预测出y的均值。
不同的代价函数给出不同的统计量。第二个使用变分法得到的结果是
将得到一个函数可以对每个x预测y取值的中位数,只要这个函数在我们要优化的函数族里。这个代价函数通常被称为平均绝对误差( mean absolute error )
不幸的是,均方误差和平均绝对误差在使用基于梯度的优化方法时往往会导致糟糕的结果。一些饱和的输出单元当结合这些代价函数时会产生非常小的梯度。这就是为什么交叉熵代价函数比均方误差或者平均绝对误差更受欢迎的原因之一了,即使是在没必要估计整个分布时。
代价函数的选择与输出单元的选择紧密相关。大多数时候,我们简单地使用数据分布和模型分布间的交叉熵。选择怎样表示输出决定了交叉熵函数的形式。
任何种类的可以被用作输出的神经网络单元,也可以被用作隐藏单元。这里,我们关注把这些单元用作模型的输出,但是原则上它们也可以在内部使用。我们将在6.3节中重温这些单元并且给出当它们被用作隐藏单元时一些额外的细节。
在本节中,我们假设前馈网络提供了一组定义为的隐藏特征。输出层的作用是随后对这些特征进行一些额外的变换来完成整个网络必须完成的任务。
一种简单的输出单元是基于仿射变换的输出单元,仿射变换不带有非线性。这些单元往往被直接称为线性单元。
给定特征h,线性输出单元层产生一个向量。
线性输出层经常被用来产生条件高斯分布的均值:
最大化对数似然此时等价于最小化均方误差。
最大化似然的框架使它也可以很直观的来学习高斯分布的协方差矩阵,或者使得高斯分布的协方差是输入的函数。然而,对于所有输入,协方差矩阵都必须被限制成一个正定的矩阵。用线性输出层来满足这种限制是困难的,所以通常使用其他的输出单元来对协方差参数化。对协方差建模的方法在6.2.2.4节中简要介绍。
因为线性模型不会饱和,所以它们对基于梯度的优化算法没有任何困难并且可以被用在相当广泛的优化算法中。
许多任务需要预测二值型变量y的值。具有两个类的分类问题可以归结为这种形式。
此时最大似然的方法是定义y在x条件下的Bernoulli 分布。
Bernoulli 分布仅需单个参数来定义。神经网络只需要预测即可。为了使这个数是有效的概率,它必须处在区间[0,1] 中。
满足这个限制需要一些细致的设计工作。假设我们打算使用线性单元,并且通过阈值来限制它成为一个有效的概率:
这的确定义了一个有效的条件概率分布,但我们并不能使用梯度下降来高效地训练它。任何时候当处于单位区间外时,模型的输出对它的参数的梯度都将为0。梯度为0 通常是有问题的,因为学习算法对于如何提高相应的参数没有了指导。
与之相对的,最好是使用一种不同的方法来保证无论何时模型给出了错误的答案时总能有一个很强的梯度。这种方法是基于用sigmoid输出单元结合最大似然来实现的。
sigmoid输出单元定义为
这里是第3.10节中介绍的logistic sigmoid函数。
我们可以认为 sigmoid输出单元具有两个部分。首先,它使用一个线性层来计算。接着,它使用 sigmoid激活函数将z转化成概率。
我们暂时忽略对于x的依赖性,只讨论如何用z的值来定义y的概率分布。sigmoid可以通过构造一个非归一化(和不为1)的概率分布来得到。我们可以随后除以一个合适的常数来得到有效的概率分布。如果我们假定非归一化的对数概率对y和z是线性的,可以对它取指数来得到非归一化的概率。我们然后对它归一化,可以发现这服从Bernoulli 分布,它受z 的sigmoid变换控制:
(没看懂
基于指数和归一化的概率分布在统计建模的文献中很常见。用于定义这种二值型变量分布的变量z被称为分对数(logit)。
这种在对数空间里预测概率的方法可以很自然地使用最大似然学习。因为用于最大似然的代价函数是,代价函数中的log 抵消了sigmoid中的exp。如果没有这个效果,sigmoid的饱和性会阻止基于梯度的学习做出好的改进。我们使用最大似然来学习一个由sigmoid参数化的Bernoulli分布,它的损失函数为
这个推导使用了3.10节中的一些性质。通过将损失函数写成softplus函数的形式我们可以看到它仅仅在(1-2y)2取绝对值非常大的负值时才会饱和。因此饱和只会出现在模型已经得到正确答案时——当y=1且z取非常大的正值时,或者y=0且z取非常小的负值时。当z的符号错误时, softplus函数的变量(1-2y)z可以简化为。当变得很大并且z的符号错误时, softplus函数渐进地趋向于它的变量。对z求导则渐进地趋向于,所以,对于极限情况下极度不正确的z,softplus函数完全不会收缩梯度。这个性质很有用,因为它意味着基于梯度的学习可以很快地改正错误的z。
当我们使用其他的损失函数,例如均方误差之类的,损失函数会在任何饱和时饱和。sigmoid激活函数在z取非常小的负值时会饱和到0,当z取非常大的正值时会饱和到1。这种情況一旦发生,梯度会変得非常小以至于不能用来学习,无论此时模型给出的是正确还是错误的答案。因为这个原因,最大似然几乎总是训练 sigmoid输出单元的优选方法。
理论上, sigmoid的对数总是确定和有限的,因为 sigmoid的返回值总是被限制在开区间(0,1)上,而不是使用整个闭区间[0,1]的有效概率。在软件实现时,为了 避免数值问题,最好将负的对数似然写作z的函数,而不是的函数。如果sigmoid函数下溢到零,那么之后对取对数会得到负无穷。
任何时候当我们想要表示一个具有n个可能取值的离散型随机变量的分布时,我们都可以使用softmax函数。它可以看作是sigmoid函数的扩展,sigmoid函数用来表示二值型变量的分布。
softmax函数最常用作分类器的输出,来表示n 个不同类上的概率分布。比较少见的是,softmax函数可以在模型内部使用,例如如果我们想要在某个内部变量的n个不同选项中进行选择。
在二值型变量的情况下,我们希望计算一个单独的数
因为这个数需要处在0 和1 之间,并且我们想要让这个数的对数可以很好地用于对数似然的基于梯度的优化,我们选择去预测另外一个数。对其指数化和归一化,我们就得到了一个由sigmoid函数控制的Bernoulli 分布。
为了推广到具有n 个值的离散型变量的情况,我们现在需要创造一个向量,它的每个元素是。我们不仅要求每个元素介于0 和1 之间,还要使得整个向量的和为1 使得它表示一个有效的概率分布。用于Bernoulli 分布的方法同样可以推广到Multinoulli 分布。首先,线性层预测了非标准化的对数概率:
其中。 softmax函数然后可以对z指数化和归一化来获得需要的。最终, softmax函数的形式为
和 logistic sigmoid一样,当使用最大化对数似然训练 softmax来输出目标值y时,使用指数函数工作地非常好。这种情况下,我们想要最大化。将 soft max定义成指数的形式是很自然的因为对数似然中的log可以抵消 softmax中的exp
公式6.30中的第一项表示输入总是对代价函数有直接的贡献。因为这一项不会饱和,所以即使 对公式6.30的第二项的贡献很小,学习依然可以进行。当最大化对数似然时,第一项鼓励被推高,而第二项则鼓励所有的z 被压低。为了对第二项有一个直观的理解,注意到这一项可以大致近似为。这种近似是基于对任何明显小于 的, 都是不重要的。我们能从这种近似中得到的直觉是,负对数似然代价函数总是强烈地惩罚最活跃的不正确预测。如果正确答案已经具有了softmax 的最大输入,那么 项和项将大致抵消。这个样本对于整体训练代价贡献很小,将由其他未被正确分类的样本支配。
到目前为止我们只讨论了一个例子。总体来说,未正则化的最大似然会驱动模型去学习一些参数,而这些参数会驱动softmax 函数来预测在训练集中观察到的每个结果的比率:
因为最大似然是一致的估计量,所以只要模型族能够表示训练的分布,这就能保证发生。在实践中,有限的模型能力和不完美的优化将意味着模型只能近似这些比率。
除了对数似然之外的许多目标函数对softmax 函数不起作用。具体来说,那些不使用对数来抵消softmax 中的指数的目标函数,当指数函数的变量取非常小的负值时会造成梯度消失,从而无法学习。特别是,平方误差对于softmax 单元来说是一个很差的损失函数,即使模型做出高度可信的不正确预测,也不能训练模型改变其输出(Bridle, 1990)。要理解为什么这些损失函数可能失败,我们需要检查softmax
函数本身。
像sigmoid一样,softmax 激活函数可能会饱和。sigmoid函数具有单个输出,当它的输入极端负或者极端正时会饱和。对于softmax 的情况,它有多个输出值。当输入值之间的差异变得极端时,这些输出值可能饱和。当softmax 饱和时,基于softmax 的许多代价函数也饱和,除非它们能够转化饱和的激活函数。
为了说明softmax函数对于输入之间差异的响应,观察到当对所有的输入都加上一个相同常数时softmax 的输出不变:
使用这个性质,我们可以导出一个数值方法稳定的softmax 函数的变体:
变换后的形式允许我们在对softmax 函数求值时只有很小的数值误差,即使是当z包含极正或者极负的数时。观察softmax 数值稳定的变体,可以看到softmax 函数由它的变量偏离的量来驱动。
当其中一个输入是最大并且 远大于其他的输入时,相应的输出 会饱和到1。当不是最大值并且最大值非常大时,相应的输出 也会饱和到0。这是sigmoid单元饱和方式的一般化,并且如果损失函数不被设计成对其进行补偿,那么也会造成类似的学习困难。
softmax 函数的变量z 可以用两种方式产生。最常见的是简单地使神经网络较早的层输出z 的每个元素,就像先前描述的使用线性层。虽然很直观,但这种方法是对分布的过度参数化。n 个输出总和必须为1 的约束意味着只有n-1 个参数是必要的;第n 个概率值可以通过1 减去前面n-1 个概率来获得。因此,我们可以强制要求z 的一个元素是固定的。例如,我们可以要求。事实上,这正是sigmoid单元所做的。定义等价于用二维的z 以及z1 = 0 来定义。无论是n-1 个变量还是n个变量的方法,都描述了相同的概率分布,但会产生不同的学习机制。在实践中,无论是过度参数化的版本还是限制的版本都很少有差别,并且实现过度参数化的版本更为简单。
从神经科学的角度看,有趣的是认为softmax 是一种在参与其中的单元之间形成竞争的方式:softmax 输出总是和为1,所以一个单元的值增加必然对应着其他单元值的减少。这与被认为存在于皮质中相邻神经元间的侧抑制类似。在极端情况下(当最大的 和其他的在幅度上差异很大时),它变成了赢者通吃(winner-take-all)的形式(其中一个输出接近1,其他的接近0)。
“softmax’’ 的名称可能会让人产生困惑。这个函数更接近于argmax 函数而不是max 函数。“soft’’ 这个术语来源于softmax 函数是连续可微的。“argmax’’ 函数的结果表示为一个one-hot向量(只有一个元素为1,其余元素都为0 的向量),不是连续和可微的。softmax 函数因此提供了argmax 的‘‘软化’’ 版本。max 函数相应的软化版本是。可能最好是把softmax 函数称为“softargmax’’,但当前名称是一个根深蒂固的习惯了。
先前描述的线性、sigmoid和softmax 输出单元是最常见的。神经网络可以推广到我们希望的几乎任何种类的输出层。最大似然原则为如何为几乎任何种类的输出层设计一个好的代价函数提供了指导。
一般的,如果我们定义了一个条件分布,最大似然原则建议我们使用 作为代价函数。
一般来说,我们可以认为神经网络表示函数。这个函数的输出不是对值的直接预测。相反, 提供了分布的参数。我们的损失函数就可以表示成。
例如,我们想要学习在给定x 时y 的条件高斯分布的方差。简单情况下,方差是一个常数,此时有一个闭合的表达式,这是因为方差的最大似然估计量仅仅是观测值y 与它们的期望值的差值的平方平均。一种计算上更加昂贵但是不需要写特殊情况代码的方法是简单地将方差作为分布的其中一个属性,这个分布受控制。负对数似然 将为代价函数提供一个必要的合适项来使我们的优化过程可以逐渐地学到方差。在标准差不依赖于输入的简单情况下,我们可以在网络中创建一个直接复制到中的新参数。这个新参数可以是本身,或者可以是表示的参数,或者可以是表示的参数,取决于我们怎样对分布参数化。我们可能希望模型对不同的x 值预测出y 不同的方差。这被称为异方差(heteroscedastic) 模型。在异方差情况下,我们简单地把方差指定为其中一个输出值。实现它的典型方法是使用精度而不是方差来表示高斯分布,就像公式3.22所描述的。在多维变量的情况下,最常见的是使用一个对角精度矩阵
这个公式适用于梯度下降,因为由参数化的高斯分布的对数似然的公式仅涉及的乘法和的加法。乘法、加法和对数运算的梯度表现良好。相比之下,如果我们用方差来参数化输出、我们需要用到除法。除法函数在零附近会变得任意陡峭。虽然大梯度可以帮助学习,但任意大的梯度通常导致不稳定。如果我们用标准差来参数化输出,对数似然仍然会涉及除法,并且还将涉及平方。通过平方运算的梯度可能在零附近消失,这使得学习被平方的参数变得困难。无论我们使用的是标准差方差还是精度,我们必须确保高斯分布的协方差矩阵是正定的。因为精度矩阵的特征值是协方差矩阵特征值的倒数,所以这等价于确保精度矩阵是正定的。如果我们使用对角矩阵,或者是一个常数乘以单位矩阵,那么我们需要对模型输出强加的唯一条件是它的元素都为正。如果我们假设a是用于确定对角精度的模型的原始激活, 那么可以用softplus 函数来获得正的精度向量:。这种相同的策略对于方差或标准差同样适用,也适用于常数乘以单位阵的情况。
学习一个比对角矩阵具有更丰富结构的协方差或者精度矩阵是很少见的。如果协方差矩阵是满的和有条件的,那么参数化的选择就必须要保证预测的协方差矩阵是正定的。这可以通过写成来实现,这里B是一个无约束的方阵。如果矩阵是满秩的,那么一个实际问题是计算似然是很昂贵的,计算一个的矩阵的行列式或者的逆(或者等价地并且更常用地,对它特征值分解或者B(x) 的特征值分解)需要的计算量。
我们经常想要执行多峰回归(multimodal regression),即预测条件分布的实值,该条件分布对于相同的x 值在y 空间中有多个不同的峰值。在这种情况下,Gaussian 混合是输出的自然表示(Jacobs et al., 1991; Bishop, 1994)。带有将Gaussian 混合作为其输出的神经网络通常被称为混合密度网络(mixture densitynetwork)。具有n 个分量的Gaussian 混合输出由下面的条件分布定义
神经网络必须有三个输出:定义的向量,对所有的i 给出的矩阵,以及对所有的i 给出的张量。这些输出必须满足不同的约束 :
有报道说基于梯度的优化方法对于混合条件Gaussian(作为神经网络的输出)可能是不可靠的,部分是因为涉及到除法(除以方差)可能是数值不稳定的(当某个方差对于特定的实例变得非常小时,会导致非常大的梯度)。一种解决方法是梯度截断(clip gradient)(见10.11.1节),另外一种是启发式梯度放缩(Murray and Larochelle, 2014)。
Gaussian 混合输出在语音生成模型(Schuster, 1999) 和物理运动(Graves, 2013)中特别有效。混合密度策略为网络提供了一种方法来表示多种输出模式,并且控制输出的方差,这对于在这些实数域中获得高质量的结果是至关重要的。混合密度网络的一个实例如图6.4所示。
一般的,我们可能希望继续对包含更多变量的更大的向量y 来建模,并在这些输出变量上施加更多更丰富的结构。例如,我们可能希望神经网络输出字符序列形成一个句子。在这些情况下,我们可以继续使用最大似然原理应用到我们的模型上,但我们用来描述y 的模型会变得非常复杂,超出了本章的范畴。第十章描述了如何用循环神经网络来定义这种序列上的模型,第三部分描述了对任意概率分布进行建模的高级技术。
到目前为止我们集中讨论了神经网络的设计选择,这对于使用基于梯度的优化方法来训练的大多数参数化机器学习模型都是通用的。现在我们转向一个前馈神经网络独有的问题:该如何选择隐藏单元的类型,这些隐藏单元用在模型的隐藏层中。
隐藏单元的设计是一个非常活跃的研究领域,并且还没有许多明确的指导性理论原则。
整流线性单元是隐藏单元极好的默认选择。许多其他类型的隐藏单元也是可用的。决定何时使用哪种类型的隐藏单元是困难的事(尽管整流线性单元通常是一个可接受的选择)。我们这里描述对于每种隐藏单元的一些基本直觉。这些直觉可以用来建议我们何时来尝试一些单元。通常不可能预先预测出哪种隐藏单元工作得最好。设计过程充满了试验和错误,先直觉认为某种隐藏单元可能表现良好,然后用它组成神经网络进行训练,最后用校验集来评估它的性能。
这里列出的一些隐藏单元可能并不是在所有的输入点上都是可微的。例如,整流线性单元在z = 0 处不可微。这似乎使得g 对于基于梯度的学习算法无效。在实践中,梯度下降对这些机器学习模型仍然表现得足够好。部分原因是神经网络训练算法通常不会达到代价函数的局部最小值,而是仅仅显著地减小它的值,如图4.3所示。这些想法会在第八章中进一步描述。因为我们不再期望训练能够实际到达梯度为0 的点,所以代价函数的最小值对应于梯度未定义的点是可以接受的。不可微的隐藏单元通常只在少数点上不可微。一般来说,函数g(z) 具有左导数和右导数,左导数定义为紧邻在z 左边的函数的斜率,右导数定义为紧邻在z 右边的函数的斜率。只有当函数在z 处的左导数和右导数都有定义并且相等时,函数在z 点处才是可微的。神经网络中用到的函数通常对左导数和右导数都有定义。在
的情况下,在z = 0 处的左导数是0,右导数是1。神经网络训练的软件实现通常返回左导数或右导数的其中一个,而不是报告导数未定义或产生一个错误。这可以通过观察到在数字计算机上基于梯度的优化总是会受到数值误差的影响来启发式地给出理由。当一个函数被要求计算g(0) 时,底层值真正为0 是不太可能的。相对的,它可能是被舍入为0 的一个小量ϵ。在某些情况下,理论上更好的
理由可以使用,但这些通常对神经网络训练并不适用。重要的是,在实践中,我们可以放心地忽略下面描述的隐藏单元激活函数的不可微性。
除非另有说明,大多数的隐藏单元都可以描述为接受输入向量x,计算仿射变换,然后使用一个作用于每个元素的非线性函数g(z)。大多数隐藏单元的区别仅仅在于激活函数g(z) 的形式。
整流线性单元使用激活函数。
整流线性单元易于优化,因为它们和线性单元非常类似。线性单元和整流线性单元的唯一区别在于整流线性单元在其一半的定义域上输出为零。这使得只要整流线性单元处于激活状态它的导数都能保持较大。它的梯度不仅大而且一致。整流操作的二阶导数几乎处处为0,并且在整流线性单元处于激活状态时它的一阶导数处处为1。这意味着它的梯度方向对于学习来说更加有用,相比于引入二阶效应的激活
函数。
整流线性单元通常用于仿射变换上:
当初始化仿射变换的参数时,可以将b的所有元素设置成一个小的正值,例如0.1。这使得整流线性单元很可能初始时就对训练集中的大多数输入呈现激活状态,并且允许导数通过。
有很多整流线性单元的扩展存在。大多数这些扩展的表现比得上整流线性单元,并且偶尔表现得更好。
整流线性单元的一个缺陷是它们不能通过基于梯度的方法学习那些使它们激活为零的样例。整流线性单元的各种扩展保证了它们能在各个位置都接收到梯度。
整流线性单元的三个扩展基于当时使用一个非零的斜率 : 。绝对值整流( absolute value rectification)固定来得到。它用于图像中的对象识别( J arnett et al,2009a),其中寻找在输入照明极性反转下不变的特征是有意义的。整流线性单元的其他扩展更广泛地适用。渗漏整流线性单元( Leaky Relu)( Maas et a,2013)将固定成一个类似0.01 的小值,参数化整流线性单元(parametric ReLU) 或者PReLU将作为学习的参数(He et al., 2015)。
maxout 单元(maxout unit)(Goodfellow et al., 2013a) 进一步扩展了整流线性单元。并不是使用作用于每个元素的函数g(z),maxout 单元将z 划分为具有k 个值的组。每个maxout 单元然后输出其中一组的最大元素:
这里是组i 的输入指标集{(i-1)k +1;... ; ik}。这提供了一种方法来学习对输入x 空间中多个方向响应的分段线性函数。
maxout 单元可以学习具有多达k 段的分段线性的凸函数。maxout 单元因此可以视为学习激活函数本身而不仅仅是单元之间的关系。使用足够大的k,maxout 单元可以以任意的逼真度来近似任何凸函数。特别地,具有每组两块的maxout 层可以学习实现和传统层相同的输入x 的函数,包括整流线性激活函数、绝对值整流、渗漏整流线性单元或参数化整流线性单元、或者可以学习实现与这些都不同的函数。
maxout 层的参数化当然也将与这些层不同,所以即使是maxout 学习去实现和其他种类的层相同的x 的函数这种情况下,学习的机理也是不一样的。
每个maxout 单元现在由k 个权重向量来参数化,而不仅仅是一个,所以maxout单元通常比整流线性单元需要更多的正则化。如果训练集很大并且每个单元分得的块数保持很低的话,它们可以在没有正则化的情况下正常工作(Cai et al., 2013)。maxout 单元还有一些其他的优点。在某些情况下,需要更少的参数可以获得一些统计和计算上的优点。具体来说,如果由n 个不同的线性过滤器描述的特征可以在不损失信息的情况下,用每一组k 个特征的最大值来概括的话,那么下一层可以获得k 倍更少的权重数。
因为每个单元由多个过滤器驱动,maxout 单元具有一些冗余来帮助它们抵抗一种被称为灾难遗忘(catastrophic forgetting) 的现象,这个现象是说神经网络忘记了如何执行它们过去训练的任务(Goodfellow et al., 2014a)。
整流线性单元和它们的这些扩展都是基于一个原则,那就是如果它们的行为更接近线性,那么模型更容易优化。使用线性行为更容易优化的一般性原则同样也适用在除了深度线性网络以外的内容。循环网络可以从序列中学习并产生状态和输出的序列。当训练它们时,需要通过一些时间步长来传播信息,当其中包含一些线性计算(具有大小接近1 的某些方向导数)时,这会更容易。作为性能最好的循环网络结构之一,LSTM 通过求和来在时间上传播信息,这是一种特别直观的线性激活。它将在10.10节中进一步讨论。
在引入整流线性单元之前,大多数神经网络使用logistic sigmoid激活函数
或者是双曲正切激活函数
这些激活函数紧密相关,因为。
我们已经看过sigmoid单元作为输出单元用来预测二值型变量取值为1 的概率。与分段线性单元不同,sigmoid单元在其大部分定义域内都饱和——当z 取绝对值很大的正值时,它们饱和到一个高值,当z 取绝对值很大的负值时,它们饱和到一个低值,并且仅仅当z 接近0 时它们才对输入强烈敏感。sigmoid单元的广泛饱和性会使得基于梯度的学习变得非常困难。因为这个原因,现在不鼓励将它们用作前馈网络中的隐藏单元。它们作为输出单元可以与基于梯度的学习相兼容,如果使用了一个合适的代价函数来抵消sigmoid的饱和性的话。
当必须要使用sigmoid激活函数时,双曲正切激活函数通常要比logistic sigmoid函数表现更好。在 而的意义上,它更像是单位函数。因为tanh在0 附近与单位函数类似,训练深层神经网络类似于训练一个线性模型,只要网络的激活能够被保持地很小。这使得训练tanh 网络更加容易。
sigmoid激活函数在除了前馈网络以外的配置中更为常见。循环网络、许多概率模型以及一些自编码器有一些额外的要求使得它们不能使用分段线性激活函数,并且使得sigmoid单元更具有吸引力,尽管它存在饱和性的问题。
也存在许多其他种类的隐藏单元,但它们并不常用。
一般来说,很多种类的可微函数都表现得很好。许多未发布的激活函数与流行的激活函数表现得一样好。为了提供一个具体的例子,作者在MNIST 数据集上使用测试了一个前馈网络,并获得了小于1% 的误差率,这可以与更为传统的激活函数获得的结果相媲美。在新技术的研究和开发期间,通常会测试许多不同的激活函数,并且会发现许多标准方法的变体表现非常好。这意味着,通
常新的隐藏单元类型只有在被明确证明能够提供显著改进时才会被发布。新的隐藏单元类型如果与已有的隐藏单元表现大致相当的话,那么它们是非常常见的,不会引起别人的兴趣。
想要列出文献中出现的所有隐藏单元类型是不切实际的。我们只对一些特别有用和独特的类型进行强调。
其中一种是完全没有激活函数g(z)。也可以认为这是使用单位函数作为激活函数。我们已经看过线性单元可以用作神经网络的输出。它也可以用作隐藏单元。如果神经网络的每一层都仅由线性变换组成,那么网络作为一个整体也将是线性的。然而,神经网络的一些层是纯线性也是可以接受的。考虑具有n 个输入和p 个输出的神经网络层。我们可以用两层来代替它,一层使用权重矩阵U,另一层使用权重矩阵V 。如果第一层没有激活函数,那么我们对基于W 的原始层的权重矩阵进行因式分解。分解方法是计算。如果U 产生了q 个输出,那么U 和V 一起仅包含(n+p)q 个参数,而W 包含np 个参数。如果q 很小,这可以在很大程度上节省参数。这是以将线性变换约束为低秩的代价来实现的,但这些低秩关系往往是足够的。线性隐藏单元因此提供了一种减少网络中参数数量的有效方法。
softmax 单元是另外一种经常用作输出的单元(如第6.2.2.3节中所描述的),但有时也可以用作隐藏单元。softmax 单元很自然地表示具有k 个可能值的离散型随机变量的概率分布,所以它们可以用作一种开关。这些类型的隐藏单元通常仅用于明确地学习操作内存的高级结构中,将在10.12节中描述。
其他一些常见的隐藏单元类型包括:
隐藏单元的设计仍是一个很活跃的研究领域,许多有用的隐藏单元类型仍有待发现。
神经网络设计的另一个关键点是确定它的结构。结构( architecture)一词是指网络的整体结构:它应该具有多少单元,以及这些单元应该如何连接。
大多数神经网络被组织成称为层的单元组。大多数神经网络结构将这些层布置成链式结构,其中每一层都是前一层的函数。在这种结构中,第一层由下式给出:
第二层由
给出,以此类推。
在这些链式结构中,主要的结构考虑是选择网络的深度和每一层的宽度。我们将会看到,即使只有一个隐藏层的网络也足够适应训练集。更深层的网络通常能够对每一层使用更少的单元数和更少的参数,并且经常推广到测试集,但是通常也更难以优化。对于一个具体的任务,理想的网络结构必须通过实验,观測在验证集上的错误来找到。
线性模型,通过矩阵乘法将特征映射到输出,顾名思义,仅能表示线性函数。它具有易于训练的优点,因为当使用线性模型时,许多损失函数会导出凸优化问题。不幸的是,我们经常想要学习非线性函数。
乍一看,我们可能认为学习非线性函数需要为我们想要学习的那种非线性专门设计一类模型族。幸运的是,具有隐藏层的前馈网络提供了一种通用近似框架。具体来说,通用近似定理(universal approximation theorem)(Hornik et al., 1989;Cybenko, 1989) 表明,一个前馈神经网络如果具有线性输出层和至少一层具有任何一种‘‘挤压’’ 性质的激活函数(例如logistic sigmoid激活函数)的隐藏层,只要给予网络足够数量的隐藏单元,它可以以任意的精度来近似任何从一个有限维空间到另一个有限维空间的Borel 可测函数。前馈网络的导数也可以任意好地来近似函数的导数(Hornik et al., 1990)。Borel 可测的概念超出了本书的范畴;对于我们想要实现的目标,只需要知道定义在的有界闭集上的任意连续函数是Borel 可测的,因此可以用神经网络来近似。神经网络也可以近似从任何有限维离散空间映射到另一个的任意函数。虽然原始定理最初以具有特殊激活函数的单元的形式来描述,这个激活函数当变量取绝对值非常大的正值和负值时都会饱和,通用近似定理也已经被证明对于更广泛类别的激活函数也是适用的,其中就包括现在常用的整流线性单元(Leshno et al., 1993)。
通用近似定理意味着无论我们试图学习什么函数,我们知道一个大的MLP 一定能够表示这个函数。然而,我们不能保证训练算法能够学得这个函数。即使MLP能够表示该函数,学习也可能因两个不同的原因而失败。首先,用于训练的优化算法可能找不到用于期望函数的参数值。其次,训练算法可能由于过拟合选择了错误的函数。回忆5.2.1节中的‘‘没有免费的午餐’’ 定理说明了没有普遍优越的机器学习算法。前馈网络提供了表示函数的通用系统,在这种意义上,给定一个函数,存在一个前馈网络能够近似该函数。不存在通用的过程既能够验证训练集上的特殊样例,又能够选择一个函数来扩展到训练集上没有的点。
通用近似定理说明了存在一个足够大的网络能够达到我们所希望的任意精度,但是定理并没有说这个网络有多大。Barron (1993) 提供了单层网络近似一大类函数所需大小的一些界。不幸的是,在最坏情况下,可能需要指数数量的隐藏单元(可能一个隐藏单元对应着一个需要区分的输入配置)。这在二进制情况下很容易看到:向量上的可能的二进制函数的数量是 并且选择一个这样的函数需要位,这通常需要的自由度。
总之,具有单层的前馈网络足以表示任何函数,但是网络层可能不可实现得大并且可能无法正确地学习和泛化。在很多情况下,使用更深的模型能够减少表示期望函数所需的单元的数量,并且可以减少泛化误差。存在一些函数族能够在网络的深度大于某个值d 时被高效地近似,而当深度被限制到小于或等于d 时需要一个远远大于之前的模型。在很多情况下,浅层模型所需的隐藏单元的数量是n 的指数级。这个结果最初被证明是在那些不与连续可微的神经网络类似的机器学习模型中出现,但现在已经扩展到了这些模型。第一个结果是关于逻辑门电路的(Håstad, 1986)。后来的工作将这些结果扩展到了具有非负权重的线性阈值单元(Håstad and Goldmann, 1991; Hajnal et al., 1993),然后扩展到了具有连续值激活的网络(Maass, 1992; Maass et al., 1994)。许多现代神经网络使用整流线性单元。Leshno et al. (1993) 证明带有一大类非多项式激活函数族的浅层网络,包括整流线性单元,具有通用的近似性质,但是这些结果并没有强调深度或效率的问题——它们仅指出足够宽的整流网络能够表示任意函数。Montufar et al.(2014) 指出一些用深度整流网络表示的函数可能需要浅层网络(一个隐藏层)指数级的隐藏单元才能表示。更确切的说,他们说明分段线性网络(可以通过整流非线性或maxout 单元获得)可以表示区域的数量是网络深度的指数级的函数。图6.5解释了带有绝对值整流的网络是如何创建函数的镜像图像的,这些函数在某些隐藏单元的顶部计算,作用于隐藏单元的输入。
每个隐藏单元指定在哪里折叠输入空间,来创造镜像响应(在绝对值非线性的两侧)。通过组合这些折叠操作,我们获得指数级
的分段线性区域,他们可以概括所有种类的规则模式(例如,重复)。
更确切的说,Montufar et al. (2014) 的主要定理指出,具有d 个输入,深度为l,每个隐藏层有n 个单元的深度整流网络可以描述的线性区域的数量是
这意味着,是深度l 的指数级。在每个单元具有k 个过滤器的maxout 网络中,线性区域的数量是
当然,我们不能保证在机器学习(特别是AI)的应用中我们想要学得的函数类型享有这样的属性。
我们还可能出于统计原因来选择深度模型。任何时候,当我们选择一个特定的机器学习算法时,我们隐含地陈述了一些先验,这些先验是关于算法应该学得什么样的函数的。选择深度模型默许了一个非常普遍的信念,那就是我们想要学得的函数应该涉及几个更加简单的函数的组合。这可以从表示学习的观点来解释,我们相信学习的问题包含发现一组潜在的变化因素,它们可以根据其他更简单的潜在的变化因素来描述。或者,我们可以将深度结构的使用解释为另一种信念,那就是我们想要学得的函数是包含多个步骤的计算机程序,其中每个步骤使用前一步骤的输出。这些中间输出不一定是变化的因素,而是可以类似于网络用来组织其内部处理的计数器或指针。根据经验,更深的模型似乎确实会更适用于广泛的任务(Bengio et al., 2007b;Erhan et al., 2009; Bengio, 2009; Mesnil et al., 2011; Ciresan et al., 2012; Krizhevsky et al., 2012a; Sermanet et al., 2013; Farabet et al., 2013; Couprie et al., 2013; Kahou et al., 2013; Goodfellow et al., 2014d; Szegedy et al., 2014a)。图6.6和图6.7展示了一些实验结果的例子。这表明使用深层结构确实在模型学习的函数空间上表示了一个有用的先验。
到目前为止,我们都将神经网络描述成简单的层的链式结构,主要的考虑因素是网络的深度和每层的宽度。在实践中,神经网络显示出相当的多样性。许多神经网络结构已经被开发用于特定的任务。用于计算机视觉的卷积神经网络的特殊结构将在第九章中介绍。前馈网络也可以推广到用于序列处理的循环神经网络,但有它们自己的结构考虑,将在第十章中介绍。
一般的,层不需要连接在链中,尽管这是最常见的做法。许多结构构建了一个主链,但随后又添加了额外的结构属性,例如从层i 到层i + 2 或者更高层的跳动连接。这些跳动连接使得梯度更容易从输出层流向更接近输入的层。结构设计考虑的另外一个关键点是如何将层与层之间连接起来。默认的神经网络层采用矩阵W 描述的线性变换,每个输入单元连接到每个输出单元。在之后章节中的许多专用网络具有较少的连接,使得输入层中的每个单元仅连接到输出层单元的一个小子集。这些用于减少连接数量的策略减少了参数的数量以及用于评估网络的计算量,但通常高度依赖于问题。例如,第九章描述的卷积神经网络使用对于计算机视觉问题非常有效的稀疏连接的专用模式。在这一章中,很难对通用神经网络的结构给出更多具体的建议。随后的章节研发了一些特殊的结构策略,可以在不同的领域工作良好。
当我们使用前馈神经网络接收输入x 并产生输出时,信息通过网络向前流动。输入x 提供初始信息,然后传播到每一层的隐藏单元,最终产生输出。这称之为前向传播(forward propagation)。在训练过程中,前向传播可以持续向前直到它产生一个标量代价函数。反向传播(back propagation) 算法(Rumelhart et al.,1986c),经常简称为backprop,允许来自代价函数的信息通过网络向后流动,以便计算梯度。
计算梯度的解析表达式是很直观的,但是数值化地求解这样的表达式在计算上可能是昂贵的。反向传播算法使用简单和廉价的程序来实现这个目标。
反向传播这个术语经常被误解为用于多层神经网络的整个学习算法。实际上,反向传播仅指用于计算梯度的方法,而另一种算法,例如随机梯度下降,使用该梯度来进行学习。此外,反向传播经常被误解为仅适用于多层神经网络,但是原则上它可以计算任何函数的导数(对于一些函数,正确的响应是报告函数的导数是未定义的)。特别地,我们会描述如何计算一个任意函数f 的梯度,其中x 是一组变量,我们需要它们的导数,而y 是另外一组函数的输入变量,但我们并不需要它们的导数。在学习算法中,我们最常需要的梯度是成本函数关于参数的梯度,即。许多机器学习任务涉及计算其他导数,作为学习过程的一部分,或者用来分析学习的模型。反向传播算法也适用于这些任务,并且不限于计算成本函数关于参数的梯度。通过网络传播信息来计算导数的想法是非常通用的,并且可以用于计算诸如具有多个输出的函数f 的Jacobi 矩阵的值。我们这里描述的是最常用的情况,f 只有单个输出。
到目前为止我们已经用相对非正式的图形语言讨论了神经网络。为了更精确地描述反向传播算法,使用更精确的计算图(computational graph) 语言是很有帮助的。
将计算形式化为图形的方法有很多。
这里,我们使用图中的每一个节点来表示一个变量。变量可以是标量、向量、矩阵、张量、或者甚至是另一类型的变量。为了形式化我们的图形,我们还需要引入操作(operation)。操作是一个或多个变量的简单函数。我们的图形语言伴随着一组被允许的操作。可以通过将多个操作组合在一起来描述比该组中的操作更复杂的函数。
不失一般性,我们定义一个操作仅返回单个输出变量。这并没有失去一般性,因为输出变量可以有多个条目,例如向量。反向传播的软件实现通常支持具有多个输出的操作,但是我们在描述中避免这种情况,因为它引入了对概念理解不重要的许多额外细节。
如果变量y 是变量x 通过一个操作计算得到的,那么我们画一条从x 到y 的有向边。我们有时用操作的名称来注释输出的节点,当上下文很明确时有时也会省略这个标注。计算图的实例可以参见图6.8。
使用链式规则、可以直接写出某个标量对于计算图中任何产生该标量的节点的梯度的代数表达式。然而,实际在计算机中计算该表达式时会引入一些额外的考虑体来说,
许多子表达式可能在梯度的整个表达式中重复若干次。任何计算梯度的程序都需要选择是存储这些子表达式还是重新计算它们几次。图6.9给出了一个例子来说明这些重复的子表达式是如何出现的。
在某些情况下,计算两次相同的子表达式纯粹是浪费。在复杂图中,可能存在指数多的这种计算上的浪费.使得简单的链式法则不可实现。在其他情況下,计算两次相同的子表达式可能是以较高的运行时间为代价来减少内存开销的有效手段。我们首先给出一个版本的反向传播算法,它指明了梯度的直接计算方式(算法62以及相关的正向计算的算法6.1),按照它实际完成的顺序并且递归地使用链式法则。可以直接执行这些计算或者将算法的描述视为用于计算反向传播的计算图的符号表示。然而,这些公式并没有明确地操作和构造用于计算梯度的符号图。这些公式在后面的6.5.6节和算法6.5中给出,其中我们还推广到了包含任意张量的节点。
首先考虑描述如何计算单个标量(例如训练样例上的损失函数)的计算图。我们想要计算这个标量对个输入节点 到 的梯度。换句话说,我们希望对所有的计算。在用反向传播计算梯度来实现参数的梯度下降时,将对应单个或者小批量实例的代价函数,而到则对应于模型的参数。
我们将假设图的节点已经以一种特殊的方式被排序,使得我们可以一个接一个地计算他们的输出,从 开始,一直上升到。如算法6.1中所定义的,每个节点 与操作 相关联,并且通过对该函数求值来得到
其中是所有双亲节点的集合。
该算法详细说明了前向传播的计算,我们可以将其放入图中。为了执行反向传播,我们可以构造一个依赖于并添加额外一组节点的计算图。这形成了一个子图,它的每个节点都是的节点。中的计算和中的计算顺序完全相反,而且中的每个节点计算导数与前向图中的节点相关联。这通过对标量输出使用链式法则来完成
在算法6.2中详细说明。子图 恰好包含每一条对应着 中从节点 到节点的边。从 到 的边对应着计算。另外,对于每个节点都要执行一个内积,内积的一个因子是对于 孩子节点 的已经计算的梯度,另一个因子是对于相同
孩子节点 的偏导数组成的向量。总而言之,执行反向传播所需的计算量与 中的边的数量成比例,其中每条边的计算包括计算偏导数(节点关于它的一个双亲节点的偏导数)以及执行一次乘法和一次加法。下面,我们将此分析推广到张量值节点,这只是在同一节点中对多个标量值进行分组并能够更有效的实现。
反向传播算法被设计为减少公共子表达式的数量而不考虑存储的开销。具体来说,它执行了图中每个节点一个Jacobi 乘积的数量的计算。这可以从算法6.2中看出,反向传播算法访问了图中的节点 到节点 的每条边一次,以获得相关的偏导数 。反向传播因此避免了重复子表达式的指数爆炸。然而,其他算法可能通过对计算图进行简化来避免更多的子表达式,或者也可能通过重新计算而不是存储这些子表达式来节省内存。