ANN人工神经网络

ANN人工神经网络

神经元模型

神经网络(neural networks)方面的研究很早就已出现,今天"神经网络"己是一个相当大的、多学科交叉的学科领域。各相关学科对神经网络的定义多种多样,本书采用目前使用得最广泛的一种,即"神经网络是由具有适应性的简单单元组成的广泛并行互连的网络,它的组织能够模拟生物神经系统对真实世界物体所作出的交互反应"[Kohonen, 1988]。我们在机器学习中谈论神经网络时指的是"神经网络学习"或者说,是机器学习与神经网络这两个学科领域的交叉部分。

神经网络中最基本的成分是神经元(neuron)模型,即上述定义中的"简单单元"。在生物神经网络中,每个神经元与其他神经元相连,当它"兴奋"时,就会向相连的神经元发送化学物质,从而改变这些神经元内的电位;如果某神经元的电位超过了一个"阈值"(threshold),那么它就会被激活,即 "兴奋 "起来,向其他神经元发送化学物质。

1943年,[McCulloch and Pitts, 1943]将上述情形抽象为下图所示的简单模型,这就是一直沿用至今的 "M-P神经元模型"。在这个模型中,神经元接收到来自n个其他神经元传递过来的输入信号,这些输入信号通过带权重的连接(connection)进行传递,神经元接收到的总输入值将与神经元的阀值进行比较,然后通过"激活函数"(activation function)处理以产生神经元的输出

理想中的激活函数是下图(a)所示的阶跃函数,它将输入值映射为输出值"0" 或”1“,显然"1"对应于神经元兴奋,"0"对应于神经元抑制。然而,阶跃函数具有不连续、不光滑等不太好的性质,因此实际常用Sigmoid函数作为激活函数。典型的Sigmoid 函数如下图(b)所示,它把可能在较大范围内变化的输入值挤压到(0, 1)输出值范围内,因此有时也称为"挤压函数"。

把许多个这样的神经元按-定的层次结构连接起来,就得到了神经网络。

事实上,从计算机科学的角度看,我们可以先不考虑神经网络是否真的模拟了生物神经网络,只需将一个神经网络视为包含了许多参数的数学模型,这个模型是若干个函数, 例如

yj=f(iwixiθj)y_j=f\left( \sum_iw_ix_i-\theta_j \right)

相互(嵌套)代入而得.有效的神经网络学习算法大多以数学证明为支撑。

激活函数

为什么需要激活函数

从数学上看,神经网络是一个多层复合函数。激活函数在很早以前就被引入,其作用是保证神经网络的非线性,因为线性函数无论怎样复合结果还是线性的。假设神经网络的输入是n维向量x,输出是m维向量y,它实现了如下向量到向量的映射:R^n→R^m。我们将这个函数记为:y=h(x)

除输入层之外,标准的前馈型神经网络第I层实现的变换可以分为线性组合、激活函数两步。在某些开源框架中,这两步可能会拆分成不同的层,以利于代码复用和灵活组合。例如Caffe中线性组合由内积层InnerProductLayer类实现,激活函数由神经元层NeuronLayer类实现。神经网络第层的变换写成矩阵和向量形式为:

u(i)=W(i)x(i1)+b(i)x(i)=f(u(i))\begin{aligned} u^{(i)}&=W^{(i)}x^{(i-1)}+b^{(i)}\\ x^{(i)}&=f(u^{(i)}) \end{aligned}

其中W是权重矩阵,b是偏置向量,u是临时结果,x是神经网络每一层的输出。激活函数分别作用于向量u的每一个分量,产生一个向量输出x。在正向传播阶段,反复用上面的公式进行计算,最后得到网络的输出。对于一个3层的网络,整个映射可以写成:

h(x)=f(W(3)f(W(2)f(W(1)x+b(1))+b(2))+b(3))h(x)=f\left( W^{(3)}f\left( W^{(2)}f\left( W^{(1)}x+b^{(1)} \right) +b^{(2)}\right) +b^{(3)}\right)

这是一个3层的复合函数。从这里可以清晰的看到,如果没有激活函数,整个函数将是一个线性函数:

W(3)(W(2)(W(1)x+b(1))+b(2))+b(3)W^{(3)}\left( W^{(2)}\left( W^{(1)}x+b^{(1)} \right) +b^{(2)}\right) +b^{(3)}

因此对激活函数最基本的要求是必须是非线性的。在早期,普遍使用的是sigmoid函数和tanh函数。

sigmoid函数的计算公式为:

f(x)=11+exp(x)f(x)=\frac{1}{1+\text{exp}(-x)}

这个函数的图像为:

tanh函数的计算公式为:

f(x)=1e2x1+e2xf(x)=\frac{1-e^{-2x}}{1+e^{-2x}}

它的图像为:

前者的值域为(0,1),单调递增且有界;后者的值域为(-1,+1),是一个中心对称的奇函数,同样也是单调递增且有界。

什么样的函数可以做激活函数

前面已经说过,为保证非线性,激活函数必须为非线性函数,但仅仅具有非线性是不够的。神经网络在本质上是一个复合函数,这会让我们思考一个问题:这个函数的建模能力有多强?即它能模拟什么样的目标函数?已经证明,只要激活函数选择得当,神经元个数足够多,使用3层即包含一个隐含层的神经网络就可以实现对任何一个从输入向量到输出向量的连续映射函数的逼近,这个结论称为万能逼近(universal approximation)定理。万能逼近定理的表述为:

如果φ(x)是一个非常数,有界,单调递增的连续函数,Im是m维的单位立方体,Im中的连续函数空间为C(Im)。对于任意ε>0以及函数f∈C(Im),存在整数N,实数vi,bi,实向量wi∈R^m,通过它们构造函数F(x)作为函数f的逼近:

F(x)=i1Nviϕ(wiTx+bi)F(x)=\sum_{i-1}^Nv_i\phi(w_i^Tx+b_i)

对任意的X∈Im满足:

F(x)f(x)<ϵ|F(x)-f(x)|<\epsilon

万能逼近定理的直观解释是可以构造出上面这种形式的函数,逼近定义在单位立方体空间中的任何一个连续函数到任意指定的精度。这个定理对激活函数的要求是必须非常数、有界、单调递增,并且连续。

文献《Cybenko, G. Approximation by superpositions of a sigmoid function. Mathematics of Control, Signals, and Systems, 2, 303-314, 1989.》对使用sigmoid激活函数时的情况进行了证明:如果σ是一个连续函数,并且满足下面条件:

limxσ(x)=0limxσ(x)=1\begin{aligned} \mathop{\text{lim}}_{x\rightarrow -\infty}\sigma(x)&=0\\ \mathop{\text{lim}}_{x\rightarrow \infty}\sigma(x)&=1 \end{aligned}

则函数族:

f(x)=αiσ(wiTx+bi)f(x)=\sum\alpha_i\sigma(w_i^Tx+b_i)

在空间n维单位立方体空间C^m[0, 1]中是稠密的,即这样的函数可以逼近定义在单位立方体空间中的任意连续函数到任意指定的精度。显然sigmoid函数就满足对σ的要求。上面这些结论的函数输出值都是一个标量,但我们可以把它推广的向量的情况,神经网络的输出一般是一个向量。

只要网络规模设计得当,使用sigmoid函数和ReLU函数作为激活函数的逼近能力都能够得到保证。ReLU函数定义为:

ReLU(x)=max(0,x)\text{ReLU}(x)=\text{max}(0,x)

它是一个分段线性函数。文献《Montufar, G. Universal approximation depth and errors of narrow belief networks with discrete units. Neural Computation, 26, 2014.》和《Raman Arora, Amitabh Basu, Poorya Mianjy, Anirbit Mukherjee. Understanding Deep Neural Networks with Rectified Linear Units. 2016, Electronic Colloquium on Computational Complexity.》分析了使用ReLU激活函数的神经网络的逼近能力。下图是一个非线性分类问题的例子,说明了神经网络确实能处理这种非线性问题:

在上图中,用图中的圆圈(红色和蓝色)训练样本训练出来的神经网络模型成功的将蓝色和红色两类样本分开了,分界面是两条曲线。

仅仅满足万能逼近定理的要求也是不够的。神经网络的训练一般采用反向传播算法+梯度下降法。反向传播算法从复合函数求导的链式法则导出,因为神经网络是一个多层的复合函数。在反向传播时,误差项的计算公式为:

δ(i)=(W(i+1))Tδ(i+1)of(u(i))\delta^{(i)}=\left( W^{(i+1)} \right)^T\delta^{(i+1)}\text{o}f'\left( u^{(i)} \right)

由于使用梯度下降法需要计算损失函数对参数的梯度值,这个梯度值根据上面的误差项计算,而误差项的计算又涉及到计算激活函数的导数,因此激活函数必须是可导的。实际应用时并不要求它在定义域内处处可导,只要是几乎处处可导即可。“几乎处处可导”看上去是一个比较有文学味道的词,但实际上是数学中一个严格的概念,这涉及到实变函数的知识。它的严格定义是这样的:

定义R为一维欧氏空间,E⊆R是它的一个子集,mE为点集E的Lebesgue测度。如果E为R中的可测集,f(x)为定义在E上的实函数,如果存在N⊆E,满足:mN=0,对于任意的x0∈E/N,函数f(x)在x0处都可导,则称f(x)在E上几乎处处可导。

上面这个定义过于晦涩。我们可以简单的将几乎处处可导理解成不可导点只有有限个,或者无限可列个(即可用自然数对这些点进行编号,某一区间上的实数就是无限不可列的),即不可导点的测度是0。可以将测度理解成一维直线的一些点的集合的长度,或者二维平面上一些点的集合的面积。在概率论中我们知道,连续型随机变量取任何一个点处的值的概率为0,如果将激活函数输入值x看做是随机变量,则它落在这些不可导点处的概率是0。在计算机实现时,浮点数是进行了离散化的,分成尾数和阶码表示,计算机能表示的浮点数是有限个,因此有一定的概率会落在不可导点处,但概率非常小。ReLU函数在0点处就不可导。

如何评价激活函数

反向传播算法计算误差项时每一层都要乘以本层激活函数的导数。如果激活函数导数的绝对值值小于1,多次连乘之后误差项很快会衰减到接近于0,参数的梯度值由误差项计算得到,从而导致前面层的权重梯度接近于0,参数没有得到有效更新,这称为梯度消失问题。与之相反的是梯度爆炸问题,如果激活函数导数的绝对大于1,多次乘积之后权重值会趋向于非常大的数,这称为梯度爆炸。梯度消失问题最早在1991年发现,文献《X. Glorot, Y. Bengio. Understanding the difficulty of training deep feedforward neural networks. AISTATS, 2010.》对深层网络难以训练的问题进行了分析,在很长一段时间内,梯度消失问题是困扰神经网络层次加深的一个重要因素。

上述文献对深层神经网络难以训练的问题进行了理论分析和实验验证。在实验中,作者训练了有1-5个隐藏层的神经网络,每个隐藏层有1000个神经元,输出层使用softmax logistic回归函数。激活函数使用了sigmoid,tanh,以及softsign:

x1+x\frac{x}{1+|x|}

权重初始化公式为:

Wij=U[1n,1n]W_{ij}=U\left[ -\frac{1}{\sqrt{n}}, \frac{1}{\sqrt{n}} \right]

其中,U[a, b]是[a, b]中的均匀分布,n是前一层的尺寸。理论分析和实验结果都证明,随着网络层数的增加,反向传播的作用越来越小,网络更加难以训练和收敛。

文献《Caglar Gulcehre, Marcin Moczulski, Misha Denil, Yoshua Bengio. Noisy Activation Functions. ICML 2016.》中定义了激活函数饱和性的概念,并对各种激活函数进行了分析,给出了改进措施。如果一个激活函数满足:

limxf(x)=0\mathop{\text{lim}}_{x\rightarrow\infty}f'(x)=0

即在正半轴函数的导数趋向于0,则称该函数为右饱和。类似的如果满足:

limxf(x)=0\mathop{\text{lim}}_{x\rightarrow-\infty}f'(x)=0

即在负半轴函数的导数趋向于0,则称该函数左饱和。如果一个激活函数既满足左饱和又满足右饱和,称之为饱和。如果存在常数c,当x>c时有:

f(x)=0f'(x)=0

则称函数右硬饱和;当x<c时有:

f(x)=0f'(x)=0

则称函数左硬饱和。既满足左硬饱和又满足右硬饱和的激活函数为硬饱和函数。饱和性和梯度消失问题密切相关。在反向传播过程中,误差项在每一层都要乘以激活函数导数值,一旦x的值落入饱和区间,多次乘积之后会导致梯度越来越小,从而出现梯度消失问题。

sigmoid函数的输出映射在(0,1)之间,单调连续,求导容易。但是由于其软饱和性,容易产生梯度消失,导致训练出现问题;另外它的输出并不是以0为中心的。

tanh函数的输出值以0为中心,位于(-1,+1)区间,相比sigmoid函数训练时收敛速度更快,但它还是饱和函数,存在梯度消失问题。

ReLU函数其形状为一条折线,当x<0时做截断处理。该函数在0点出不可导,如果忽略这一个点其导数为sgn。函数的导数计算很简单,而且由于在正半轴导数为1,有效的缓解了梯度消失问题。在ReLU的基础上又出现了各种新的激活函数,包括ELU、PReLU等。如果对各种激活函数深入的比较和分析感兴趣,可以阅读文献《Caglar Gulcehre, Marcin Moczulski, Misha Denil, Yoshua Bengio. Noisy Activation Functions. ICML 2016.》。

激活函数的作用

激活函数有两个作用:

  • 加入非线性因素,解决线性模型所不能解决的问题

  • 用来组合训练数据的特征,特征的充分组合

下面分别对激活函数的两个作用进行解释。

加入非线性因素,解决非线性问题

首先我们有这个需求,就是二分类问题,如我要将下面的三角形和圆形点进行正确的分类,如下图:

利用我们单层的感知机, 用它可以划出一条线, 把三角形和圆形样本分割开:

上图直线是由

w1x1+w2x2+b=0w_1x_1+w_2x_2+b=0

得到,那么该感知器实现预测的功能步骤如下,就是我已经训练好了一个感知器模型,后面对于要预测的样本点,带入模型中。

如果y>0,那么就说明是直线的右侧,也就是正类(我们这里是三角形)。

如果y<0,那么就说明是直线的左侧,也就是负类(我们这里是圆形),虽然这和我们的题目关系不大,但是还是提一下~

好吧,很容易能够看出,我给出的样本点根本不是线性可分的,一个感知器无论得到的直线怎么动,都不可能完全正确的将三角形与圆形区分出来,那么我们很容易想到用多个感知器来进行组合,以便获得更大的分类问题,好的,下面我们上图,看是否可行:

好的,我们已经得到了多感知器分类器了,那么它的分类能力是否强大到能将非线性数据点正确分类开呢~我们来分析一下:

我们能够得到

y=w21(w111x1+w121x2+b11)+w22(w112x1+w122x2+b12)+w23(w113x1+w123x2+b13)\begin{aligned} y=\quad&w_{2-1}(w_{1-11}x_1+w_{1-21}x_2+b_{1-1})\\ +&w_{2-2}(w_{1-12}x_1+w_{1-22}x_2+b_{1-2})\\ +&w_{2-3}(w_{1-13}x_1+w_{1-23}x_2+b_{1-3})\\ \end{aligned}

哎呀呀,不得了,这个式子看起来非常复杂,估计应该可以处理我上面的情况了吧,哈哈哈哈~不一定额,我们来给它变个形。上面公式合并同类项后等价于下面公式:

y=x1(w21w111+w22w112+w23w113)+x2(w21w121+w22w122+w23w123)+w21b11+w22b12+w23b13\begin{aligned} y=\quad&x_1(w_{2-1}w_{1-11}+w_{2-2}w_{1-12}+w_{2-3}w_{1-13})\\ +&x_2(w_{2-1}w_{1-21}+w_{2-2}w_{1-22}+w_{2-3}w_{1-23})\\ +&w_{2-1}b_{1-1}+w_{2-2}b_{1-2}+w_{2-3}b_{1-3}\\ \end{aligned}

啧啧,估计大家都看出了,不管它怎么组合,最多就是线性方程的组合,最后得到的分类器本质还是一个线性方程,该处理不了的非线性问题,它还是处理不了。

就好像下图,直线无论在平面上如果旋转,都不可能完全正确的分开三角形和圆形点:

既然是非线性问题,总有线性方程不能正确分类的地方~

那么抛开神经网络中神经元需不需要激活函数这点不说,如果没有激活函数,仅仅是线性函数的组合解决的问题太有限了,碰到非线性问题就束手无策了.那么加入激活函数是否可能能够解决呢?

在上面线性方程的组合过程中,我们其实类似在做三条直线的组合,如下图:

下面我们来讲一下激活函数,我们都知道,每一层叠加完了之后,我们需要加入一个激活函数(激活函数的种类也很多,如sigmod等等~)这里就给出sigmod例子,如下图:

通过这个激活函数映射之后,输出很明显就是一个非线性函数!能不能解决一开始的非线性分类问题不清楚,但是至少说明有可能啊,上面不加入激活函数神经网络压根就不可能解决这个问题~

同理,扩展到多个神经元组合的情况时候,表达能力就会更强~对应的组合图如下:(现在已经升级为三个非线性感知器在组合了)

跟上面线性组合相对应的非线性组合如下:

这看起来厉害多了,是不是~最后再通过最优化损失函数的做法,我们能够学习到不断学习靠近能够正确分类三角形和圆形点的曲线,到底会学到什么曲线,不知道到底具体的样子,也许是下面这个~

那么随着不断训练优化,我们也就能够解决非线性的问题了~

所以到这里为止,我们就解释了这个观点,加入激活函数是用来加入非线性因素的,解决线性模型所不能解决的问题。

组合训练数据的特征,特征的充分组合

首先我们看一个简单的感知机如下:

其中,x1,x2输入均为特征的输入

则x3为

x3=w1x1+w2x2x_3=w_1x_1+w_2x_2

激活函数采取sigmoid函数,公式表达如下:

S(x)=11+exS(x)=\frac{1}{1+e^{-x}}

S(x)=11+ex3S(x)=\frac{1}{1+e^{-x_3}}

此时,我们可能看不出什么不同,但是根据泰勒展开,

ex=1+11!x+12!x2+13!x3+o(x3)e^x=1+\frac{1}{1!}x+\frac{1}{2!}x^2+\frac{1}{3!}x^3+o(x^3)

我们能够看到,将x3代入到激活函数的时候,其实激活函数的e^x泰勒展开后,有平方项,有立方项,有更高的项,这些自动能够把输入特征进行两两组合,进行三三组合或者其它的组合。

比如其中的平方项体现了将特征进行两两组合:

(w1x1+w2x2)2=w1w1x1x1+w2w2x2x2+w1x1w2x2\begin{aligned} (w_1x_1+w_2x_2)^2=&\quad w_1w_1x_1x_1\\ &+w_2w_2x_2x_2\\ &+w_1x_1w_2x_2\\ \end{aligned}

这就把原来需要领域知识的专家对特征进行组合的情况,在激活函数运算后,其实也能够起到类似特征组合的作用。

(只要激活函数中有能够泰勒展开的函数,就可能起到特征组合的作用)

这也许能给我们一些思考。

常用的激活函数

下表列出了Caffe中支持的激活函数和它们的导数:

不同激活函数的区别

卷积网络的激活函数sigmoid和relu有什么区别?

使用sigmod函数会导致将近一半的神经元被激活。不太符合人类脑活动工程学。

而relu函数在这方面神似,自动引入稀疏性,相当于无监督预练习。

AlexNet用ReLU代替了Sigmoid,发现使用ReLU得到的SGD的收敛速度会比sigmoid/tanh 快很多。主要是因为它是linear,而且non-saturating(因为ReLU的导数始终是1),相比于sigmoid/tanh,ReLU只需要一个阈值就可以得到激活值,而不用去算一大堆复杂的运算。

感知机与多层网络

感知机(Perceptron)由两层神经元组成,如下图所示,输入层接收外界输入信号后传递给输出层,输出层是M-P神经元,亦称"阈值逻辑单元"(threshold logic unit)。

感知机能容易地实现逻辑与、或、非运算。注意到

y=f(iwixiθ)y=f\left( \sum_iw_ix_i-\theta \right)

,假定f是激活函数中的阶跃函数,有

  • “与”(x1 && x2):令w1 = w2 = 1,θ = 2,则y = f( 1·x1 + 1·x2 - 2 ),仅在x1 =1且x2 = 1时,y = 1

  • “或”(x1 || x2):令w1 = w2 = 1,θ = 0.5,则y = f( 1·x1 + 1·x2 - 0.5 ),当x1 = 1或x2 = 1时,y = 1

  • “非”(! x1):令w1 = -0.6,w2 = 0,θ = -0.5,则y = f( -0.6·x1 + 0·x2 + 0.5 ),当x1 = 1时,y = 0;当x1 = 0时,y = 1

更一般地,给定训练数据集,权重wi(i = 1, 2, ... , n)以及阈值θ可通过学习得到。阈值θ可看作一个固定输入为-1.0的"哑结点"(dummy node)所对应的连接权重W(n+1),这样,权重和阈值的学习就可统一为权重的学习。感知机学习规则非常简单,对训练样例(x, y),若当前感知机的输出为hat(y),则感知机权重将这样调整:

wiwi+Δwiwi=η(yy^)xi\begin{aligned} &w_i\leftarrow w_i+\Delta w_i\\ &w_i=\eta(y-\hat{y})x_i \end{aligned}

其中η∈(0, 1)称为学习率。从上式可看出,若感知机对训练样例(x, y)预测正确,即hat(y) = y,则感知机不发生变化,否则将根据错误的程度进行权重调整。

需注意的是,感知机只有输出层神经元进行激活函数处理,即只拥有一层功能神经单元,其学习能力非常有限。事实上,上述与、或、非问题都是线性可分的问题。可以证明,若两类模式是线性可分的,即存在一个线性超平面能将它们分开,如下图(a)-(c) 所示,则感知机的学习过程一定会收敛而求得适当的权向量w = (w1, w2, ... , w(n+1));否则感知机学习过程将会发生震荡,w难以稳定下来,不能求得合适解,例如感知机甚至不能解决如下图(d)所示的异或这样简单的非线性可分问题

要解决非线性可分问题,需考虑使用多层功能神经元。例如下图中这个简单的两层感知机就能解决异或问题。在下图(a)中,输出层与输入层之间的一层神经元,被称为隐层或隐藏层(hidden layer),隐含层和输出层神经元都是拥有激活函数的功能神经元。

更一般的,常见的神经网络是形如下图所示的层级结构,每层神经元与下层神经元全互连,神经元之间不存在同层连接, 也不存在跨层连接。这样的神经网络结构通常称为"多层前馈神经网络"(multi-layer feedforward neural networks),其中输入层神经元接收外界输入,隐层与输出层神经元对信号进行加工,最终结果由输出层神经元输出;换言之,输入层神经元仅是接受输入,不进行函数处理,隐层与输出层包含功能神经元。因此,下图(a)通常被称为"两层网络"。为避免歧义,本书称其为"单隐层网络"。只需包含隐层,即可称为多层网络。神经网络的学习过程,就是根据训练数据来调整神经元之间的"连接权值"以及每个功能神经元的阈值;换言之,神经网络"学"到的东西,蕴涵在连接权值与阈值中。

误差逆向传播(BP)算法

多层网络的学习能力比单层感知机强得多。欲训练多层网络,前面的简单感知机学习规则显然不够了,需要更强大的学习算法。误差逆传播(error BackPropagation,简称BP)算法就是其中最杰出的代表。误差逆向传播算法是迄今最成功的神经网络学习算法。现实任务中使用神经网络时,大多是在使用BP算法进行训练。

下面我们来看看 BP 算法究竟是什么样。

给定训练集D = { (x1, y1), (x2, y2), ... , (xm, ym) }, xi∈R^d,yi∈R^l,即输入示例由d个属性描述,输出l维实值向量。

为便于讨论,下图给出了一个拥有d个输入神经元、l个输出神经元、q个隐层神经元的多层前馈网络结构,其中输出层第j个神经元的阈值用θj表示,隐层第h个神经元的阈值用γh表示。输入层第i个神经元与隐层第h个神经元之间的连接权为v(ih),隐层第h个神经元与输出层第j个神经元之间的连接权为w(hj)。

记隐层第h个神经元接收到的输入为

αh=i=1dvihxi\alpha_h=\sum_{i=1}^dv_{ih}x_i

, 输出层第j个神经元接收到的输入为

βj=h=1qwhjbh\beta_j=\sum_{h=1}^qw_{hj}b_h

,其中bh为隐层第h个神经元的输出。假设隐层和输出层神经元都使用Sigmoid激活函数。

对训练例(xk, yk),假定神经网络的输出为

y^k=(y^1k,y^2k,...,y^lk)\hat{y}_k=(\hat{y}_1^k, \hat{y}_2^k, ... , \hat{y}_l^k)

,即

y^jk=f(βjθj)\hat{y}_j^k=f(\beta_j-\theta_j)

则网络在(xk, yk)上的均方误差为

Ek=12j=1l(y^jkyjk)2E_k=\frac{1}{2}\sum_{j=1}^l(\hat{y}_j^k-y_j^k)^2

其中,1/2是为了后续求导的便利。

上图的网络中有(d + l + 1)q + l个参数需确定:输入层到隐层的d x q个权值 、 隐层到输出层的q x l个权值、q个隐层神经元的阈值、l个输出层神经元的阈值。BP是一个迭代学习算法,在迭代的每一轮中采用广义的感知机学习规则对参数进行更新估计,即与前面的感知机更新算法类似,任意参数v的更新估计式为

vv+Δvv\leftarrow v+\Delta v

下面我们以上图中隐层到输出层的连接权w(hj)为例来进行推导。

BP算法基于梯度下降策略,以目标的负梯度方向对参数进行调整。对上上式的均方误差Ek,给定学习率η,有

Δwhj=ηEkwhj\Delta w_{hj}=-\eta\frac{\partial E_k}{\partial w_{hj}}

注意到w(hj)先影响到第j个输出层神经元的输入值βj,再影响到其输出值hat(y)_j^k,再影响到Ek,有

Ekwhj=Eky^jky^jkβjβjwhj\frac{\partial E_k}{\partial w_{hj}}=\frac{\partial E_k}{\partial \hat{y}_j^k}\frac{\partial \hat{y}_j^k}{\partial \beta_j}\frac{\partial \beta_j}{\partial w_{hj}}

根据βj的定义,显然有

βjwhj=bh\frac{\partial \beta_j}{\partial w_{hj}}=b_h

Sigmoid激活函数有一个很好的性质:

f(x)=f(x)(1f(x))f'(x)=f(x)(1-f(x))

于是有输出层灵敏度gj为

gj=Eky^jky^jkβj=(y^jkyjk)f(βjθj)=(y^jkyjk)y^jk(1y^jk)\begin{aligned} g_j&=\frac{\partial E_k}{\partial \hat{y}_j^k}\frac{\partial \hat{y}_j^k}{\partial \beta_j}\\ &=(\hat{y}_j^k-y_j^k)f'(\beta_j-\theta_j)\\ &=(\hat{y}_j^k-y_j^k)\hat{y}_j^k(1-\hat{y}_j^k)\\ \end{aligned}

则BP算法中关于输出层权值w(hj)的更新公式为

Δwhj=ηgjbh\Delta w_{hj}=-\eta g_jb_h

输出层的阈值θj更新公式为(θj为阈值,本身前面带有负号,所以这里负负得正了)

Δθj=ηgj\Delta\theta_j=\eta g_j

类似可得隐层灵敏度eh为

eh=Ekbhbhαh=(j=1lEkβjβjbh)bhαh=(j=1lgjwhj)f(αhγh)=bh(1bh)j=1lgjwhj\begin{aligned} e_h&=\frac{\partial E_k}{\partial b_h}\frac{\partial b_h}{\partial \alpha_h}\\ &=\left( \sum_{j=1}^l \frac{\partial E_k}{\partial \beta_j}\cdot \frac{\partial \beta_j}{\partial b_h} \right) \cdot \frac{\partial b_h}{\partial \alpha_h}\\ &=\left( \sum_{j=1}^l g_j w_{hj}\right)f'(\alpha_h-\gamma_h)\\ &=b_h(1-b_h)\sum_{j=1}^l g_j w_{hj} \end{aligned}

学习率η∈(0, 1)控制着算法每一轮迭代中的更新步长(常设置为η = 0.1),若太大则容易振荡,太小则收敛速度又会过但。有时为了做精细调节,可分别在每层设置不同的学习率。

下图给出了BP算法的工作流程。对每个训练样例,BP算法执行以下操作:先将输入示例提供给输入层神经元,然后逐层将信号前传,直到产生输出层的结果;然后计算输出层的误差(第4-5行),再将误差逆向传播至隐层神经元(第6行),最后根据隐层神经元的误差来对连接权和阈值进行调整(第7行)。该迭代过程循环进行,直到达到某些停止条件为止,例如训练误差己达到一个很小的值(停止条件与缓解BP过拟合的策略有关)。

下图给出了在2个属性、5个样本的西瓜数据上,随着训练轮数的增加,网络参数和分类边界的变化情况。

需注意的是, BP算法的目标是要最小化训练集D上的累积误差

E=1mk=1mEkE=\frac{1}{m}\sum_{k=1}^mE_k

但我们上面介绍的"标准BP算法"每次仅针对一个训练样例更新连接权和阈值,也就是说,上上图所示算法的更新规则是基于单个的Ek推导而得。如果类似地推导出基于累积误差最小化的更新规则,就得到了累积误差逆传播算法。累积BP算法与标准BP算法都很常用。一般来说,标准BP算法每次更新只针对单个样例,参数更新得非常频繁,而且对不同样例进行更新的效果可能出现"抵消"现象。因此,为了达到同样的累积误差极小点,标准BP算法往往需进行更多次数的法代。累积BP算法直接针对累积误差最小化,它在读取整个训练集D一遍后才对参数进行更新,其参数更新的频率低得多。但在很多任务中,累积误差下降到一定程度之后,进一步下降会非常缓慢,这时标准BP往往会更快获得较好的解,尤其是在训练集D非常大时更明显。

[Hornik et al., 1989]证明,只需一个包含足够多神经元的隐层,多层前馈网络就能以任意精度逼近任意复杂度的连续函数。点这里查看为什么:神经网络为什么可以(理论上)拟合任何函数?。然而,如何设置隐层神经元的个数仍是个未决问题,实际应用中通常靠"试错法"调整。

正是由于其强大的表示能力,BP神经网络经常遭遇过拟合,其训练误差持续降低,但测试误差却可能上升。有两种策略常用来缓解BP网络的过拟合。

第一种策略是"早停":将数据分成训练集和验证集,训练、集用来计算梯度、更新连接权和阔值,验证集用来估计误差,若训练集误差降低但验证集误差升高,则停止训练,同时返回具有最小验证集误差的连接权和阈值。

第二种策略是"正则化"[Barron, 1991; Girosi et al., 1995],其非常相似。基本思想是在误差目标函数中增加一个用于描述网络复杂度的部分,例如连接权与阈值的平方和。仍令Ek表示第k个训练样例上的误差,wi表示连接权和 阈值,则误差目标函数改变为

E=λ1mk=1mEk+(1λ)iwi2E=\lambda\frac{1}{m}\sum_{k=1}^mE_k+(1-\lambda)\sum_iw_i^2

其中λ∈(0, 1)用于对经验误差与网络复杂度这两项进行折中,常通过交叉验证法来估计。

增加连接权与阈值平方和这一项后,训练过程将会偏好比较小的连接权和阈值,使网络输出更加"光滑",从而对过拟合有所缓解。

全局最小与局部极小

若用E表示神经网络在训练集上的误差,则它显然是关于连接权w和阈值θ的函数。此时,神经网络的训练过程可看作一个参数寻优过程, 即在参数空间中,寻找一组最优参数使得E最小。

我们常会谈到两种"最优" :"局部极小" 和"全局极小",如下图所示。显然,我们在参数寻优的过程中是希望找到全局最小。

基于梯度的搜索是使用最为广泛的参数寻优方法。如果误差函数具有多个局部极小,则不能保证找到的解是全局最小,我们称参数寻优陷入了局部极小,这显然不是我们所希望的。

在现实任务中,人们常采用以下策略来试图 "跳出"局部极小,从而进一步接近全局最小:

  • 以多组不同参数值初始化多个神经网络,按标准方法训练后,取其中误差最小的解作为最终参数。这相当于从多个不同的初始点开始搜索,这样就可能陷入不同的局部极小从中进行选择有可能获得更接近全局最小的结果

  • 使用 "模拟退火"技术[Aarts and Korst, 1989]。模拟退火在每一步都以一定的概率接受比当前解更差的结果,从而有助于"跳出"局部极小。在每步迭代过程中,接受"次优解"的概率要随着时间的推移而逐渐降低,从而保证算法稳定。但是也会造成"跳出"全局最小。

  • 使用随机梯度下降。与标准梯度下降法精确计算梯度不同,随机梯度下降法在计算梯度时加入了随机因素。于是,即便陷入局部极小点,它计算出的梯度仍可能不为零,这样就有机会跳出局部极小继续搜索

此外,遗传算法[Goldberg, 1989]也常用来训练神经网络,以更好地逼近全局最小。需注意的是,上述用于跳出局部极小的技术大多是启发式,理论上尚缺乏保障。

其他常见神经网络

Elman网络

与前馈神经网络不同,"递归神经网络"(recurrent neural networks)允许网络中出现环形结构,从而可让一些神经元的输出反馈回来作为输入信号。这样的结构与信息反馈过程,使得网络在t时刻的输出状态不仅与t时刻的输入有关,还与t-1时刻的网络状态有关,从而能处理与时间有关的动态变化。

Elman网络[Elman, 1990]是最常用的递归神经网络之一,其结构如下图所示,它的结构与多层前馈网络很相似,但隐层神经元的输出被反馈回来,与下一时刻输入层神经元提供的信号一起,作为隐层神经元在下一时刻的输入。隐层神经元通常采用Sigmoid激活函数,而网络的训练则常通过推广的BP算法进行[Pineda, 1987]。

Boltzmann机

神经网络中有一类模型是为网络状态定义一个"能量" ,能量最小化时网络达到理想状态,而网络的训练就是在最小化这个能量函数.

Boltzmann机[Ackley et al., 1985]就是一种"基于能量的模型",常见结构如下图(a)所示,其神经元分为两层:显层与隐层。显层用于表示数据的输入与输出,隐层则被理解为数据的内在表达。Boltzmann机中的神经元都是布尔型的,即只能取0、1两种状态,状态1表示激活,状态0表示抑制。令向量 s ∈ {0, 1}^n表示n个神经元的状态,w_ij表示神经元i与j之间的连接权,θi表示神经元i的阈值,则状态向量s所对应的Boltzmann机能量定义为

E(s)=i=1n1j=i+1nwijsisji=1nθisiE(s)=-\sum_{i=1}^{n-1}\sum_{j=i+1}^nw_{ij}s_is_j-\sum_{i=1}^n\theta_is_i

若网络中的神经元以任意不依赖于输入值的顺序进行更新,则网络最终将达到Boltzmann分布,此时状态向量s出现的概率将仅由其能量与所有可能状态向量的能量确定(能量越负,出现概率越大):

P(s)=eE(s)teE(t)P(s)=\frac{e^{-E(s)}}{\sum_te^{-E(t)}}

Boltzmann机的训练过程就是将每个训练样本视为一个状态向量,使其出现的概率尽可能大。标准的Boltzmann机是一个全连接图,训练网络的复杂度很高,这使其难以用于解决现实任务。现实中常采用受限Boltzmann机(Restricted Boltzmann Machine,简称RBM)。如下图(b)所示,受限Boltzmann机仅保留显层与隐层之间的连接,从而将Boltzmann机结构由完全图简化为二部图。

受限Boltzmann机常用"对比散度"(Contrastive Dìvergence,简称CD)算法[Hinton, 2010]来进行训练。假定网络中有d个显层神经元和q个隐层神经元,令v和h分别表示显层与隐层的状态向量,则由于同一层内不存在连接,有

P(vh)=i=1dP(vih)P(hv)=j=1qP(hjv)\begin{aligned} &P(v|h)=\prod_{i=1}^dP(v_i|h)\\ &P(h|v)=\prod_{j=1}^qP(h_j|v)\\ \end{aligned}

CD算法对每个训练样本,先根据上式中第二式计算出隐层神经元状态的概率分布,然后根据这个概率分布采样得到h;此后,类似地根据上式中第一式从h产生v',再从v'产生h‘;连接权的更新公式为

Δw=η(vhTvhT)\Delta w=\eta(vh^T-v'{h'}^T)

阈值的更新公式可类似获得。

参考资料

  • 《机器学习》周志华

本文主要参考此资料。

"激活函数"一节参考此资料。

"激活函数的作用"一节参考了此微信文章。

Last updated