第三章:优化神经网络的学习
第三章:优化神经网络的学习
我们面对错误的时候会感到不安,但是犯错误时我们可以学习得更快!
理想状态下,我们希望神经网络可以从网络偏差中快速学习,怎么实现呢?为了回答这个问题,我们看下面的这个简单的例子:一个神经元,只有一个输入:

我们训练一个简单的问题:输入1,输出0,虽然很容易手工确定权重和偏差,但是我们采用梯度下降法学习。损失函数定义为第一章中的二次函数,初始权重和偏差分别为:0.6和0.9,,学习速率0.15,训练过程如下:

可以看出神经元可以快速的学习调整权重和阀值,使损失函数值下降,最终输出为0.09,很接近0.而我们还是采用相同的方法,取初始权重和偏移为2,2,学习速率仍0.15,训练过程如下:

可以看出训练开始阶段学习速度很慢,在前150个训练步中权重和偏移没有改变多少,然后学习开始生效,损失函数值如前面一样迅速下降。
这种现象与人类学习行为不相符合,前面说过,当犯大错误的时候,人类学习速度会更快,但是从上图看出人工神经网络在偏差很大的时候并没有比偏差小时学习得更快。实际上,不仅仅在这个简单模型中有这种现状,在通常的神经网络中也会出现这种情况,为什么会学习这么慢?我们能找到什么方法来避免训练速度变慢吗?
为了更好的理解,这里假如学习速率由损失函数的偏导数决定:∂C/∂w ∂C/∂w ∂C/∂b。因此,“学习慢”也可以说是偏导数很小,回忆前面定义的价值函数:

其中a是当训练输入x=1时神经元的输出,对应期望输出y=0.定义:a=σ(z), where z=wx+b
利用链式规则求偏导:

这里我假设的是x=1,y=0.为了理解这些表达式的含义,更好的理解σ′(z),请看下面的sigmoid 函数图像

这下明白了吧,一切在图中!当函数值接近1的时候,其图像非常平缓,即导数就会很小,式(55)、(56)就会很小,这就是学习慢的根本原因。
Introducing the cross-entropy cost function交叉熵损失函数
:问题找到了,咱们该如何解决呢?事实证明,我们可以用一个另外的损失函数取代二次损失函数,这就是有名的交叉熵。为了理解交叉熵,我们假设下面的神经元,多个输入,x1,x2,…,对应权重w1,w2,。。。一个偏差,b:

我们为这个神经元定义交叉熵损失函数:

其中n是训练输入个数,对所有输入x进行求和,y为对应期望输出。
表达式(57)能解决学习速度慢的问题吗?完全看不出来!不知道有什么意义?在说明它能解决学习速度慢的问题之前,咱们先看下为什么这个交叉熵函数能够作为损失函数:
以下两个性质可以解释为什么交叉熵作为损失函数是合理的:
第一,非负性,即C>0。注意:式(57)求和中的每个表达式都为负,因为两个函数的自变量取值范围都为0-1;求和之前有一个负号。
第二,当输入训练x,神经元实际输出与期望接近时,交叉熵接近于0.举例说,假设y=0.a≈0,(输入x),可以计算式(57)≈0,同样可取y=1,a≈1。
综上所述:首先,交叉熵为非负数,其次,当实际输出接近期望时,其值趋近于0.这两个性质,是我们所期望的损失函数所应具有的。二次函数也满足这两个性质。但是交叉熵函数可以避免学习变慢。咱们接着往下看:为了搞明白,我们来计算交叉熵对权重和偏移的偏导数,假设a=σ(z),带入式(57),应用两次链式规则,可以得到

通分得到:

定义sigmoid函数,
σ(z)=1/(1+e−z)σ(z)=1/(1+e−z),
对其求导得到:
σ′(z)=σ(z)(1−σ(z))
带入式(60),可以得到:

这个表达式非常漂亮!它告诉我们权重的学习速率由σ(z)−y决定,即输出偏差决定学习速率,偏差越大学习速度越快,这个表达式巧妙的避开了导数的影响。
同理可得:

练习:自己证明一下:

我们回到第一个单输入单输出的例子:
采用交叉熵损失函数来训练网络:当权重、偏移分别取0.6、0.9时,训练过程如下:

这与取二次函数的训练过程相差不大,当权重、偏移都取2时,训练过程如下:

成功!!!看到了吧,相比二次损失函数,学习速率提高了不少!尤其在初始阶段!交叉熵学习速率η=0.005,这是试验得到的较好的学习速率。你也许会说学习速率都变了,不能说明问题,我们关心的是怎么提高的学习速度,会选择一个学习速率来实现这个目的,这里的学习速率是相对的,不要偏离重点,不解释,事实如此!
前面我们讨论的是一个神经元的情况,但是这可以很容易的推广到多层多神经元的情况,实际中,假设y=y1,y2….是期望输出,a1L,a2L。。。为实际输出,定义交叉熵:

表达式与式(57)类似,只是多了一个∑j,表示对所有输出进行求和。
我们什么时候选择交叉熵?什么时候选择二次函数呢?实际上,选择交叉熵几乎总会比二次函数好!这里假设激活函数取sigmiod,当我们随机初始化权重和偏移时,二次函数可能会出现学习慢的情况,而交叉熵可以避免。
前面提到如果σ(z)≈yσ(z)≈y,是基于y等于0或1的,在分类问题中确实这样,但是对于其他问题(比如递归),y可以取0-1之间的任何值,说明在σ(z)=y时,交叉熵依然取得最小值,这种情况下,交叉熵的值为:

等式−[ylny+(1−y)ln(1−y)]就是著名的二进制熵(binary entropy)
问题
在上一章中介绍的二次损失函数输出层对权重的偏导数:

导数导致学习变慢,交叉熵的偏差定义为:

从而得到输出层各权重的偏导数:

这里的导数已经被去掉,从而避免因为导数学习变慢,对于偏移的学习是一样的道理。
当输出层是线性神经元时,采用二次损失函数:
假设一个多层多神经元的网络,输出层全是线性函数,简单的例子取aiL=ziL,定义偏差:

可以求导得到:

可以看出使用二次函数不会导致学习速率变慢,实际上,在这种情况下,选择二次函数是最合适的。
Using the cross-entropy to classify MNIST digits
交叉熵可以很容易在利用梯度下降和后向传播的学习程序,改进我们第一章用于MNIST手写数字识别的程序network.py,新的程序命名为network2.py,这里不仅仅合并交叉熵,还有一些本章中介绍的其他技术。现在,我们来看一下怎么利用新的程序对MNIST数字进行分类,在第一章中,我们采用的mini batch size是10,隐藏层30个神经元,学习速率是0.5,进行30个学习步。network2.py与network.py有些区别,但是需要明白它如何工作的。在Python shell中输入help(network2.Network.SGD)可以得到帮助文档,但是首先得导入network2,即在shell中输入import network2(注意先更改当前目录)
>>> import mnist_loader
>>> training_data, validation_data, test_data = \
... mnist_loader.load_data_wrapper()
>>> import network2
>>> net = network2.Network([784, 30, 10], cost=network2.CrossEntropyCost)
>>> net.large_weight_initializer()
>>> net.SGD(training_data, 30, 10, 0.5, evaluation_data=test_data,
... monitor_evaluation_accuracy=True)
注意,net.large_weight_initializer()是用于初始化权重和偏移的函数,与第一章的方法一样,这里单独调用是因为后面我们会对权重和偏移的初始化方法进行优化。训练结果是网络的精度达到95.49%,与第一章中采用二次函数得到的结果95。42%接近。如果隐藏层神经元为100个,其他不变,训练最后精度达到达到96.82,相比最初的结果,误差降低了约1/14。
到目前为止,我们长篇大论了交叉熵(cross-entropy),但是只有一点点的提高。后面我们介绍了规整化(regularization)后,提高会更多。另外一个原因是因为交叉熵应用十分广泛,更重要的是需要认识到饱和(saturation)是神经网络的一个重要问题。
What does the cross-entropy mean? Where does it come from?
今天先学习这么多了,明天继续!
这是只是个人学习过程中的记录分享,若需仔细阅读请看英文原文,连接:http://www.tensorfly.cn/home/?p=90


浙公网安备 33010602011771号