码迷,mamicode.com
首页 > 其他好文 > 详细

神经网络那些事儿(二)

时间:2015-12-06 17:44:00      阅读:707      评论:0      收藏:0      [点我收藏+]

标签:

上一篇中,我们看到了神经网络是怎样使用梯度下降算法来学习它们的权值和偏置。然而,我们还有一些没有解释:我们没有讨论怎样计算损失函数的梯度。本篇中将解释著名的BP算法,它是一个快速计算梯度的算法。

 

反向传播算法(Backpropagation algorithm,BP)是在1970s提出的,但是它的重要性直到一篇著名的1986年的论文才被接受。论文是David Rumelhart,Geoffrey Hinton,以及Ronald Williams合写的。这篇论文描述了几种神经网络,其中的反向传播算法工作得更快比早期的学习算法,这使得使用神经网络能够解决之前不能解决的问题。今天,反向传播算法已经是神经网络中最核心的算法。

 

BP算法的核心是网络中的损失函数C分别关于任何权值w(或者偏置b)的偏导数技术分享的表达式。这个表达式告诉我们当我们改变权值和偏置的时候损失函数变化得有多快。BP算法不仅是一个快速学习的算法,它实际上给出了更细节的关于权值和偏置改变网络的全部行为是怎样变化的。

 

 

热身:一个基于矩阵快速计算神经网络输出的方法

 

在讨论反向传播之前,让我们先热身一下,看一下一个快速基于矩阵的计算神经网络输出的算法。我们实际上已经简短地看见了这个算法在上一张快结束的时候。特别地,这是熟悉在反向传播中用到的符号的一种很自然的方法。

我们将使用技术分享来表示第(l-1)层的第k个神经元到第l层的第j个神经元之间连接的权值。例如下图中的技术分享表示第3层的第2个神经元与第2层的第4个神经元之间的连接的权值:

技术分享

那么,对于偏置和激活,我们使用一个相似的符号。显然地,我们使用技术分享表示第l层的第j个神经元。并且,我们使用技术分享来表示第l层的第j个神经元的激活。就像下图一样:

技术分享

 

我们能发现第l层的第j个神经元的激活技术分享和第l-1层的激活有关系,正如下面的式子:

 

技术分享

这里的和表示第l-1层的所有神经元k。为了把表达式写成一个矩阵形式,我们为每层l定义了一个权值矩阵技术分享。权值矩阵技术分享的元素仅仅是和第l层的神经元连接的权值,即,第j行和第j列的元素是技术分享。类似地,对于每一层l,我们定义一个偏置向量技术分享。偏置向量的元素仅仅是值技术分享,第l层的每个神经元的一个元素。最后,我们定义了一个激活向量技术分享,它的组成是激活技术分享。接下来我们要做的是向量化一个函数,例如技术分享。简单地说,如果我们有函数技术分享,那么f的向量化形式有这样的结果:

 

技术分享

所以我们能够把(23)式写成:

技术分享

这样写不仅在符号上简单许多,而且有助于你从总体上理解这个式子:第l层的激活就是等于前一层(l-1)的激活和与l层神经元相连接的权值的积再加上该层的偏置,然后应用sigmoid函数。最关键的是,许多线性代数库计算基于矩阵的形式会非常快。

 

当使用等式(25)来计算技术分享,我们计算了一个中间量技术分享沿着这种方式。这个量表明是足够有用的而值得重新命名:我们把技术分享称作到第l层神经元的权重输入(weighted input)。等式(25)有时候会写成权重输入(weighted input)的形式,正如技术分享。然后需要注意的是:技术分享技术分享这样的组成,即,技术分享只是第l层的神经元j的到激活函数的权重输入。

 

 

关于损失函数我们需要的两个假设

 

BP算法的目标就是计算损失函数C关于任何网络中的权重w或者偏置b的偏导数技术分享技术分享。这里还是以二次损失函数为例子。即:

技术分享

这里的n是训练样本的总数;对所有单个训练样本x取和;y=y(x)是相应的期望输出;L表示层数;技术分享是输入为x的网络的激活向量技术分享

 

第一个假设就是损失函数可以被写成技术分享,单个的训练样本的损失函数为技术分享。我们始终遵循这种假设。

 

我们需要这个假设的理由是因为反向传播实际上让我们做的是计算单个的训练样本的偏导数技术分享技术分享。然后通过平均所有的训练样本来计算技术分享技术分享。实际上,我们可以假设训练样本x已经被固定,然后丢弃x下标,把损失技术分享写成技术分享

 

第2个假设是损失可以被写成一个神经网络的输出的函数:

技术分享

 

例如,二次损失函数满足这个需求,因为单个训练样本x的二次损失可能被写成:

技术分享

 

 

Hadamard积,技术分享

 

反向传播算法是基于普通的线性代数操作-像向量相加,用矩阵乘以一个向量。但是其中有一个操作用的比较少。假设s和t是两个维数一样的向量。那么我们使用技术分享来表示两个元素的按位相乘。因此,技术分享的组成为技术分享。例如:

技术分享

这种按位相乘有时被称为Hadamard 积。好的矩阵库通常提供了Hadamard积的快速的实现,这对于实现反向传播信手拈来。

 

 

反向传播背后的四个等式

 

反向传播是关于理解在一个网络改变损失函数时,权重和偏置是怎样变化的。最终,这个意味着计算偏导数技术分享技术分享。但是为了计算那些,我们首先引进一个中间变量,技术分享,我们把它称为第l层的第j个神经元的error。BP将给出一个计算error 技术分享的过程,然后关联技术分享技术分享技术分享

 

为了理解error是如何定义的,想象我们的神经网络中有一个精灵:

技术分享

这个精灵坐在第l层的第j个神经元上。当神经元的输入进来时,精灵扰乱神经元的操作。它增加了一个小的变化技术分享到神经元的权重输入,所以输出不再是技术分享,而是技术分享。这个变化传播到网络中后面的层,最终导致损失函数改变了一个量技术分享

 

现在,这个精灵是一个好的精灵,并且正在帮助你改进损失函数,也就是他们正尝试找到一个技术分享使得损失函数更小。假设技术分享有一个很大的值(要么是正的要么是负的,指绝对值)。那么,精灵能够通过选择技术分享有和技术分享相反的符号来使损失函数减小得十分多。相反,如果技术分享接近于0,那么精灵就不能通过扰乱权重输入技术分享来改进损失函数。到目前为止,精灵能够告诉我们,神经元已经相当接近最优了。因此,存在一个启发式技术分享是神经元的error的一个度量。于是我们定义层l的的神经元j的error 技术分享为:

技术分享

按照我们的传统,我们使用技术分享来表示和层l关联的error向量。反向传播将告诉我们计算每层的技术分享方法,然后把这些errors关联到我们真实感兴趣的量技术分享技术分享

 

 

你可能想知道为什么精灵正在改变权重输入技术分享。当然,想象精灵正在改变输出激活技术分享,然后使用技术分享来度量我们的error,这样也许会更自然。事实上,如果你这样做了将和下面的讨论的结果是差不多的。但是,它将使陈述BP变得稍微有点代数上更复杂。因此,我们将坚持技术分享作为我们error的度量。

 

 

攻克计划:

BP是基于四个基础的等式。这些等式一起给了我们一个计算error(你可以将其翻译为残差)技术分享和损失函数的梯度的方法。

 

 

输出层残差技术分享的一个等式

技术分享的组成由下面的式子给定:

技术分享

这是一个很自然的式子。右边的第一项,技术分享,仅仅是度量作为第j个输出激活的一个函数,损失函数变化得有多快。例如,如果C不依赖于一个特定输出神经元j很多的话,那么技术分享将是很小的,这也正是我们所期望的。右边的第二项,技术分享是度量激活函数技术分享在点技术分享上改变得有多快。我们能够发现,(BP1)中的所有项都很容易计算。特别是,我们计算技术分享同时也在计算网络的行为,并且计算技术分享也只是一个很小的花费。技术分享的真实形式将取决于损失函数的形式。然而,被提供的损失函数是已知的,会存在一点小麻烦在计算技术分享的时候。例如,如果我们使用二次损失函数,那么技术分享,因此技术分享,它是很容易被计算的。

 

等式(BP1)是一个技术分享分量方式的表达式。它是一个完美的表达式,但是不是我们想要的基于矩阵的BP表达式。然而,把它写成一个矩阵的形式也是简单的:

技术分享

这里,技术分享被定义为偏导数技术分享组成的一个向量。你可以把它想象成表达C关于输出激活的一个变化率。所以,技术分享,最后基于矩阵的形式为:

技术分享

 

用下一层中的残差技术分享表示的残差技术分享的一个等式

:特别地

技术分享

假设我们知道残差技术分享在第技术分享层。当我们应用转置权值矩阵技术分享时,我们可以直观地把这个想成让残差向后穿过网络,从而给了我们某种度量第l层的输出的残差的方法。当使用Hadamard积技术分享时,它通过第l层的激活函数把残差向后移动,给出了到达l层的权重输入的残差技术分享

 

组合BP2和BP1,我们能计算网络中的任何层的残差技术分享。我们首先通过BP1来计算技术分享,然后应用等式BP2来计算技术分享,然后再次使用等式BP2计算技术分享,等等,用这样的方式反向穿过网络。

 

 

 

网络中损失函数关于任何偏置的变化率的一个等式:

特别地:

技术分享

也就是,残差技术分享实际上等于变化率技术分享。这个信息很有用,因为BP1和BP2已经告诉我们怎样计算技术分享。我们能够重写BP3:

技术分享

 

损失函数关于任何权值的变化率的一个等式:

特别地:

技术分享

这告诉我们怎样利用量技术分享技术分享来计算偏导数技术分享,前面两个量我们已经知道怎么计算了。可以重写为下面的形式:

技术分享

其中技术分享是权重为w输入的神经元的激活,技术分享是从权重w的神经元的输出残差。可以简化为下面的图形:

技术分享

等式(32)的一个很好的结果是当激活技术分享很小的时候,技术分享,梯度项技术分享也将趋向于很小。在这种情况下,我们将说权重学习得很慢,意味着在梯度下降过程中改变得很多。换句话说,BP4的一个结果就是从低-激活神经元输出的权重学习得很慢。

 

从BP1-BP4中也可以看到其他的信息。先看看输出层。考虑(BP1)中的技术分享项。回忆上一章中的sigmoid函数的图,当技术分享接近0或1的时候,技术分享函数变得很平坦。当这个发生的时候,我们可以得到技术分享。所以如果输出神经元是低激活(技术分享)或者高激活(技术分享),那么最后一层中的权重将学习得很慢。这种情况下,通常是说输出神经元已经饱和了,并且权重已经停止学习了(或者学习得很慢)。相似的结论对于输出神经元中的偏置也是成立的。

 

对于非输出层我们也能获得一些相似的信息。特别是,注意BP2中的项技术分享。这意味着如果神经元接近饱和,则技术分享可能变小。反过来,这也意味着输入到一个饱和神经元的任何权重也将学习得很慢。

 

可以总结出来,我们已经知道,如果输入神经元是低-激活或者输出神经元已经饱和了,也就是要么是高激活,要么是低激活,那么一个权重将学习得很慢。刚才观测到的这些信息没有太多的让人惊讶。但是,它们依旧帮助提升当一个神经网络学习的时候发生了什么我们的思维模型。

 

 

四个基础等式的证明

 

我们将证明四个基础等式(BP1)-(BP4)。所有四个等式都是多元微积分的链式法则的结果。首先看(BP1)等式吧,它给出的是输出残差,技术分享。为了证明这个等式,回忆定义:

技术分享

应用链式法则,我们可以重写使用关于输出激活的偏导数来表示

上面的偏导数:

技术分享

和表示所有输出层中的神经元k。当然,第k个神经元仅仅取决于当k=j时的第j个神经元的输入权值技术分享的输出激活技术分享。因此当技术分享 时,技术分享项就消失了。所以可以简化前面的等式为:

 

技术分享

因为技术分享,右边的第2项能够被写成技术分享,等式就变成:

技术分享

这便是BP1的形式。接下来BP2和BP3的证明留给读者自己思考。

 

 

反向传播算法

 

BP算法为我们提供了一个计算损失函数梯度的方法。写成一个算法的形式:

  1. 输入 x:为输入层设置相应的激活技术分享
  2. 前向:对于每个l=2,3,…,L计算技术分享以及 技术分享
  3. 输出残差技术分享:计算向量技术分享
  4. 反向传播残差:对于每个l=L-1,L-2,…,2计算技术分享
  5. 输出:损失函数的梯度为技术分享技术分享

 

我们从最后一层开始向后计算残差向量技术分享,这可能看起来我们正在向后穿过网络是奇怪的。但是,如果你思考反向传播的证明,反向移动是由于损失是网络的输出的一个函数的事实所导致的。为了理解损失怎样随着早先的权重和偏置变化的,我们需要重复应用链式法则,层层向后计算来获得可用表达式信息。反向传播算法计算的是单个训练样本的梯度,即技术分享。实践中,通常把反向传播和一个像随机梯度这样的学习算法组合,在随机梯度算法中我们计算许多训练样本的梯度。特别地,给定一个含有m个训练样本的mini-batch,下面的算法应用了一个基于mini-batch的梯度下降学习算法:

  1. 输入一个训练样本的集合
  2. 对于每个训练样本x:设置相应的输入激活技术分享,然后执行下面的步骤:
    1. 前向:对于每个l=2,3,…,L计算技术分享以及 技术分享
    2. 输出残差技术分享:计算向量技术分享
    3. 反向传播残差:对于每个l=L-1,L-2,…,2计算技术分享
  3. 梯度下降:对于每个l=L,L-1,…,2依据规则技术分享更新权重,依据规则技术分享更近偏置。

 

当然,实践中为了实现随机梯度下降,你也需要一个外层循环来产生训练样本的mini-batches,以及一个外层循环单步执行训练的多个epochs。

 

反向传播代码实现:

 

关于代码的分析,请看我的下一篇文章《神经网络代码分析》。

转载 http://www.gumpcs.com/index.php/archives/962

神经网络那些事儿(二)

标签:

原文地址:http://www.cnblogs.com/chenying99/p/5023815.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!