《神经网络和深度学习》系列文章二十一:用交叉熵解决手写数字识别问题

文章出处: Michael Nielsen的《Neural Network and Deep Learning》,本节译者:哈工大SCIR本科生 赵怀鹏 (https://github.com/zhaohuaipeng)。


目录

1、使用神经网络识别手写数字

2、反向传播算法是如何工作的

3、改进神经网络的学习方法

  • 改进神经网络的学习方式
  • 交叉熵损失函数
  • 用交叉熵解决手写数字识别问题

  • 交叉熵意味着什么?它从哪里来?
  • Softmax
  • 过拟合和正则化
  • 正则化
  • 为什么正则化能够降低过拟合?
  • 其他正则化技术
  • 参数初始化
  • 重温手写数字识别:代码
  • 如何选择神经网络的超参数
  • 其他技术

4、神经网络能够计算任意函数的视觉证明

5、为什么深度神经网络的训练是困难的

6、深度学习


我们可以很容易在程序中将交叉熵应用于梯度下降法(gradient descent)和反向传播算法(backpropagation)。在本章的后面我会改进之前的手写数字识别程序network.py。新的程序取名network2.py,它不仅仅用到了交叉熵,还用到了本章将要介绍的其他技术1。但现在我们先看一下新程序解决手写数字问题的效果如何。和第一章的例子一样,我们的网络将用30个隐层神经元,mini-batch的大小选为10。设定学习速率为η=0.52,迭代次数选为30。network2.py的接口和network.py稍有不同,但是仍然能够很清楚看到整个过程。


>>> 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个百分点。这比我们第一章的结果96.59有了提升。你可能觉得只是提升了一点,但是考虑到误差率从3.41个百分点降低到3.18个百分点。这也就是说,我们缩减了十四分之一的原始误差。这的确是个不错的提升。


这对交叉熵来说是个好消息,因为和使用均方误差相比,它能得到相似或者更好的结果。原因是我花了一些时间去寻找一些比较好的超参数,比如学习速率,mini-batch的大小等等。这些改进也鼓舞我们要做一个彻底的工作去优化超参数。这些实验结果也验证了我们选择使用交叉熵的理论优势。


顺便说一句,这也是我们在这章或者在这本书中采用的模式。我们采用了一些新的技术,然后做实验验证它,然后我们「改进了」结果。我们当然乐意看到结果得到了改进。但是带来改进的原因通常是令人困扰的。只有我们花费大量时间去优化所有的超参数才能得到令人信服的结果。这样做的工作量非常大,通常我们不会做那么详尽的研究。相反,我们会做一些类似于上面的非正式的测试。不过你仍要记得这种测试的证据并不充分,要对参数失效的迹象要保持警觉。


到目前为止,我们花费了大量篇幅去讨论交叉熵。它只对我们手写数字识别有一点提升,为何要那么大费周章地去介绍它呢?在这章的后面我们会看到其他技术——尤其是正则化,能够大大改进我们的结果。那么为什么要如此关注交叉熵呢?一部分原因是交叉熵是广泛使用的代价函数,因此它值得我们深入了解。但是更重要的理由是神经元饱和在神经元网络中是一个重要的问题,它会贯穿整本书。我花费那么长篇幅讨论交叉熵是因为它是一个很好的实验,能让我们对神经元饱和有了初步的认知。


1 代码托管在Github:https://github.com/mnielsen/neural-networks-and-deep-learning/blob/master/src/network2.py


2 在第一章中,我们使用了平方代价函数和的学习率。正如之前所讨论的,当代价函数改变后,我们不能精确地定义什么是「相同的」学习率。对于对比的两种代价函数,在其它超参数相同的情况下,我尝试了进行实验找到能够产生相似表现的学习率。有一种非常粗浅的想法找到交叉熵代价函数和平方代价函数两者的学习率的联系。正如我们之前所看到的,平方代价函数的梯度表达式中多一项。如果我们对算一下均值,我们得到。我们可以(大致上)得到,当学习率相同时,平方代价函数的速度会平均上慢6倍。这表明一个可行的方法是将平方代价函数的学习率除以6。当然,这远远不是一个严谨的推断,别太当真了。但是你也可以将其视为一种有用的初始化方法。


本文来源于哈工大SCIR

原文链接点击即可跳转


哈尔滨工业大学社会计算与信息检索研究中心

入门理论Michael Nielsen神经网络深度学习哈工大交叉熵数字识别