神经网络和反向传播算法

来源:互联网 发布:服务器 定时关机 软件 编辑:程序博客网 时间:2024/05/18 13:23

神经元

神经元和感知器本质上是一样的,只不过我们说感知器的时候,它的激活函数是阶跃函数;而当我们说神经元时,激活函数往往选择为sigmoid函数或tanh函数。如下图所示:

计算一个神经元的输出的方法和计算一个感知器的输出是一样的。假设神经元的输入是向量x⃗ ,权重向量是w⃗ (偏置项是w0),激活函数是sigmoid函数,则其输出y

y=sigmoid(w⃗ Tx⃗ )(1)

sigmoid函数的定义如下:

sigmoid(x)=11+ex

将其带入前面的式子,得到

y=11+ew⃗ Tx⃗ 

sigmoid函数是一个非线性函数,值域是(0,1)。函数图像如下图所示

sigmoid函数的导数是:

y=sigmoid(x)y=y(1y)(1)(2)

可以看到,sigmoid函数的导数非常有趣,它可以用sigmoid函数自身来表示。这样,一旦计算出sigmoid函数的值,计算它的导数的值就非常方便。

神经网络是啥

神经网络其实就是按照一定规则连接起来的多个神经元。上图展示了一个全连接(full connected, FC)神经网络,通过观察上面的图,我们可以发现它的规则包括:

  • 神经元按照来布局。最左边的层叫做输入层,负责接收输入数据;最右边的层叫输出层,我们可以从这层获取神经网络输出数据。输入层和输出层之间的层叫做隐藏层,因为它们对于外部来说是不可见的。
  • 同一层的神经元之间没有连接。
  • 第N层的每个神经元和第N-1层的所有神经元相连(这就是full connected的含义),第N-1层神经元的输出就是第N层神经元的输入。
  • 每个连接都有一个权值

上面这些规则定义了全连接神经网络的结构。事实上还存在很多其它结构的神经网络,比如卷积神经网络(CNN)、循环神经网络(RNN),他们都具有不同的连接规则。

计算神经网络的输出

神经网络实际上就是一个输入向量x⃗ 到输出向量y⃗ 的函数,即:

y⃗ =fnetwork(x⃗ )

根据输入计算神经网络的输出,需要首先将输入向量x⃗ 的每个元素xi的值赋给神经网络的输入层的对应神经元,然后根据式1依次向前计算每一层的每个神经元的值,直到最后一层输出层的所有神经元的值计算完毕。最后,将输出层每个神经元的值串在一起就得到了输出向量y⃗ 

接下来举一个例子来说明这个过程,我们先给神经网络的每个单元写上编号。

如上图,输入层有三个节点,我们将其依次编号为1、2、3;隐藏层的4个节点,编号依次为4、5、6、7;最后输出层的两个节点编号为8、9。因为我们这个神经网络是全连接网络,所以可以看到每个节点都和上一层的所有节点有连接。比如,我们可以看到隐藏层的节点4,它和输入层的三个节点1、2、3之间都有连接,其连接上的权重分别为w41,w42,w43。那么,我们怎样计算节点4的输出值a4呢?

为了计算节点4的输出值,我们必须先得到其所有上游节点(也就是节点1、2、3)的输出值。节点1、2、3是输入层的节点,所以,他们的输出值就是输入向量x⃗ 本身。按照上图画出的对应关系,可以看到节点1、2、3的输出值分别是x1,x2,x3。我们要求输入向量的维度和输入层神经元个数相同,而输入向量的某个元素对应到哪个输入节点是可以自由决定的,你偏非要把x1赋值给节点2也是完全没有问题的,但这样除了把自己弄晕之外,并没有什么价值。

一旦我们有了节点1、2、3的输出值,我们就可以根据式1计算节点4的输出值a4

a4=sigmoid(w⃗ Tx⃗ )=sigmoid(w41x1+w42x2+w43x3+w4b)(3)(4)

上式的w4b是节点4的偏置项,图中没有画出来。而w41,w42,w43分别为节点1、2、3到节点4连接的权重,在给权重wji编号时,我们把目标节点的编号j放在前面,把源节点的编号i放在后面。

同样,我们可以继续计算出节点5、6、7的输出值a5,a6,a7。这样,隐藏层的4个节点的输出值就计算完成了,我们就可以接着计算输出层的节点8的输出值y1

y1=sigmoid(w⃗ Tx⃗ )=sigmoid(w84a4+w85a5+w86a6+w87a7+w8b)(5)(6)

同理,我们还可以计算出y2的值。这样输出层所有节点的输出值计算完毕,我们就得到了在输入向量x⃗ =x1x2x3时,神经网络的输出向量y⃗ =[y1y2]。这里我们也看到,输出向量的维度和输出层神经元个数相同

神经网络的矩阵表示

神经网络的计算如果用矩阵来表示会很方便(当然逼格也更高),我们先来看看隐藏层的矩阵表示。

首先我们把隐藏层4个节点的计算依次排列出来:

a4=sigmoid(w41x1+w42x2+w43x3+w4b)a5=sigmoid(w51x1+w52x2+w53x3+w5b)a6=sigmoid(w61x1+w62x2+w63x3+w6b)a7=sigmoid(w71x1+w72x2+w73x3+w7b)

接着,定义网络的输入向量x⃗ 和隐藏层每个节点的权重向量wj。令

x⃗ w⃗ 4w⃗ 5w⃗ 6w⃗ 7f=x1x2x31=[w41,w42,w43,w4b]=[w51,w52,w53,w5b]=[w61,w62,w63,w6b]=[w71,w72,w73,w7b]=sigmoid(7)(8)(9)(10)(11)(12)

代入到前面的一组式子,得到:

a4a5a6a7=f(w4x⃗ )=f(w5x⃗ )=f(w6x⃗ )=f(w7x⃗ )(13)(14)(15)(16)

现在,我们把上述计算a4,a5,a6,a7的四个式子写到一个矩阵里面,每个式子作为矩阵的一行,就可以利用矩阵来表示它们的计算了。令

a⃗ =a4a5a6a7,W=w⃗ 4w⃗ 5w⃗ 6w⃗ 7=w41,w42,w43,w4bw51,w52,w53,w5bw61,w62,w63,w6bw71,w72,w73,w7b,f(x1x2x3...)=f(x1)f(x2)f(x3)...

带入前面的一组式子,得到

a⃗ =f(Wx⃗ )(2)

式2中,f是激活函数,在本例中是sigmoid函数;W是某一层的权重矩阵;x⃗ 是某层的输入向量;a⃗ 是某层的输出向量。式2说明神经网络的每一层的作用实际上就是先将输入向量左乘一个数组进行线性变换,得到一个新的向量,然后再对这个向量逐元素应用一个激活函数。

每一层的算法都是一样的。比如,对于包含一个输入层,一个输出层和三个隐藏层的神经网络,我们假设其权重矩阵分别为W1,W2,W3,W4,每个隐藏层的输出分别是a⃗ 1,a⃗ 2,a⃗ 3,神经网络的输入为x⃗ ,神经网络的输入为y⃗ ,如下图所示:

则每一层的输出向量的计算可以表示为:

a⃗ 1=f(W1x⃗ )a⃗ 2=f(W2a⃗ 1)a⃗ 3=f(W3a⃗ 2)y⃗ =f(W4a⃗ 3)(17)(18)(19)(20)

这就是神经网络输出值的计算方法。

神经网络的训练

现在,我们需要知道一个神经网络的每个连接上的权值是如何得到的。我们可以说神经网络是一个模型,那么这些权值就是模型的参数,也就是模型要学习的东西。然而,一个神经网络的连接方式、网络的层数、每层的节点数这些参数,则不是学习出来的,而是人为事先设置的。对于这些人为设置的参数,我们称之为超参数(Hyper-Parameters)

接下来,我们将要介绍神经网络的训练算法:反向传播算法。

反向传播算法(Back Propagation)

我们首先直观的介绍反向传播算法,最后再来介绍这个算法的推导。当然读者也可以完全跳过推导部分,因为即使不知道如何推导,也不影响你写出来一个神经网络的训练代码。事实上,现在神经网络成熟的开源实现多如牛毛,除了练手之外,你可能都没有机会需要去写一个神经网络。

我们以监督学习为例来解释反向传播算法。在零基础入门深度学习(2) - 线性单元和梯度下降一文中我们介绍了什么是监督学习,如果忘记了可以再看一下。另外,我们设神经元的激活函数fsigmoid函数(不同激活函数的计算公式不同,详情见反向传播算法的推导一节)。

我们假设每个训练样本为(x⃗ ,t⃗ ),其中向量x⃗ 是训练样本的特征,而t⃗ 是样本的目标值。

首先,我们根据上一节介绍的算法,用样本的特征x⃗ ,计算出神经网络中每个隐藏层节点的输出ai,以及输出层每个节点的输出yi

然后,我们按照下面的方法计算出每个节点的误差项δi

  • 对于输出层节点i

δi=yi(1yi)(tiyi)(3)

其中,δi是节点i的误差项,yi是节点i输出值ti是样本对应于节点i目标值。举个例子,根据上图,对于输出层节点8来说,它的输出值是y1,而样本的目标值是t1,带入上面的公式得到节点8的误差项δ8应该是:

δ8=y1(1y1)(t1y1)

  • 对于隐藏层节点,

δi=ai(1ai)koutputswkiδk(4)

其中,ai是节点i的输出值,wki是节点i到它的下一层节点k的连接的权重,δk是节点i的下一层节点k的误差项。例如,对于隐藏层节点4来说,计算方法如下:

δ4=a4(1a4)(w84δ8+w94δ9)

最后,更新每个连接上的权值:

wjiwji+ηδjxji(5)

其中,wji是节点i到节点j的权重,η是一个成为学习速率的常数,δj是节点j的误差项,xji是节点i传递给节点j的输入。例如,权重w84的更新方法如下:

w84w84+ηδ8a4

类似的,权重w41的更新方法如下:

w41w41+ηδ4x1

偏置项的输入值永远为1。例如,节点4的偏置项w4b应该按照下面的方法计算:

w4bw4b+ηδ4

我们已经介绍了神经网络每个节点误差项的计算和权重更新方法。显然,计算一个节点的误差项,需要先计算每个与其相连的下一层节点的误差项。这就要求误差项的计算顺序必须是从输出层开始,然后反向依次计算每个隐藏层的误差项,直到与输入层相连的那个隐藏层。这就是反向传播算法的名字的含义。当所有节点的误差项计算完毕后,我们就可以根据式5来更新所有的权重。

以上就是基本的反向传播算法,并不是很复杂,您弄清楚了么?

反向传播算法的推导

反向传播算法其实就是链式求导法则的应用。然而,这个如此简单且显而易见的方法,却是在Roseblatt提出感知器算法将近30年之后才被发明和普及的。对此,Bengio这样回应道:

很多看似显而易见的想法只有在事后才变得显而易见。

接下来,我们用链式求导法则来推导反向传播算法,也就是上一小节的式3式4式5

前方高能预警——接下来是数学公式重灾区,读者可以酌情阅读,不必强求。

按照机器学习的通用套路,我们先确定神经网络的目标函数,然后用随机梯度下降优化算法去求目标函数最小值时的参数值。

我们取网络所有输出层节点的误差平方和作为目标函数:

Ed12ioutputs(tiyi)2

其中,Ed表示是样本d的误差。

然后,我们用文章零基础入门深度学习(2) - 线性单元和梯度下降中介绍的随机梯度下降算法对目标函数进行优化:

wjiwjiηEdwji

随机梯度下降算法也就是需要求出误差Ed对于每个权重wji的偏导数(也就是梯度),怎么求呢?

观察上图,我们发现权重wji仅能通过影响节点j的输入值影响网络的其它部分,设netj是节点j加权输入,即

netj=wjxj=iwjixji(21)(22)

Ednetj的函数,而netjwji的函数。根据链式求导法则,可以得到:

Edwji=Ednetjnetjwji=Ednetjiwjixjiwji=Ednetjxji(23)(24)(25)

上式中,xji是节点i传递给节点j的输入值,也就是节点i的输出值。

对于Ednetj的推导,需要区分输出层隐藏层两种情况。

输出层权值训练

对于输出层来说,netj仅能通过节点j的输出值yj来影响网络其它部分,也就是说Edyj的函数,而yjnetj的函数,其中yj=sigmoid(netj)。所以我们可以再次使用链式求导法则:

Ednetj=Edyjyjnetj(26)

考虑上式第一项:

Edyj=yj12ioutputs(tiyi)2=yj12(tjyj)2=(tjyj)(27)(28)(29)

考虑上式第二项:

yjnetj=sigmoid(netj)netj=yj(1yj)(30)(31)

将第一项和第二项带入,得到:

Ednetj=(tjyj)yj(1yj)

如果令δj=Ednetj,也就是一个节点的误差项δ是网络误差对这个节点输入的偏导数的相反数。带入上式,得到:

δj=(tjyj)yj(1yj)

上式就是式3

将上述推导带入随机梯度下降公式,得到:

wjiwjiηEdwji=wji+η(tjyj)yj(1yj)xji=wji+ηδjxji(32)(33)(34)

上式就是式5

隐藏层权值训练

现在我们要推导出隐藏层的Ednetj

首先,我们需要定义节点j的所有直接下游节点的集合Downstream(j)。例如,对于节点4来说,它的直接下游节点是节点8、节点9。可以看到netj只能通过影响Downstream(j)再影响Ed。设netk是节点j的下游节点的输入,则Ednetk的函数,而netknetj的函数。因为netk有多个,我们应用全导数公式,可以做出如下推导:

Ednetj=kDownstream(j)Ednetknetknetj=kDownstream(j)δknetknetj=kDownstream(j)δknetkajajnetj=kDownstream(j)δkwkjajnetj=kDownstream(j)δkwkjaj(1aj)=aj(1aj)kDownstream(j)δkwkj(35)(36)(37)(38)(39)(40)

因为δj=Ednetj,带入上式得到:

δj=aj(1aj)kDownstream(j)δkwkj

上式就是式4

——数学公式警报解除——

至此,我们已经推导出了反向传播算法。需要注意的是,我们刚刚推导出的训练规则是根据激活函数是sigmoid函数、平方和误差、全连接网络、随机梯度下降优化算法。如果激活函数不同、误差计算方式不同、网络连接结构不同、优化算法不同,则具体的训练规则也会不一样。但是无论怎样,训练规则的推导方式都是一样的,应用链式求导法则进行推导即可。

原创粉丝点击