文章出处: Michael Nielsen的《Neural Network and Deep Learning》,本节译者:朱小虎 、张广宇。
目录
1、使用神经网络识别手写数字
2、反向传播算法是如何工作的
3、改进神经网络的学习方法
- 改进神经网络的学习方式
- 交叉熵损失函数
- 使用交叉熵损失来分类MNIST数字集
- 交叉熵意味着什么?它从哪里来?
- Softmax
- 过拟合和正则化
- 正则化
- 为什么正则化能够降低过拟合?
- 其他正则化技术
- 权重初始化
- 重温手写数字识别:代码
- 如何选择神经网络的超参数
- 其他技术
4、神经网络能够计算任意函数的视觉证明
5、为什么深度神经网络的训练是困难的
6、深度学习
创建了神经网络后,我们需要进行权重和偏置的初始化。到现在,我们一直是根据在第一章中介绍的那样进行初始化。提醒你一下,之前的方式就是根据独立高斯随机变量来选择权重和偏置,其被归一化为均值为 ,标准差 。这个方法工作的还不错,但是非常特别,所以值得去重新探讨它,看看是否能寻找一些更好的方式来设置初始的权重和偏置,这也许能帮助我们的网络学习得更快。
结果表明,我们可以比使用归一化的高斯分布做得更好。为什么?假设我们使用一个有大量输入神经元的网络,比如说 个。假设,我们已经使用归一化的高斯分布初始化了连接第一个隐藏层的权重。现在我将注意力集中在这一层的连接权重上,忽略网络其他部分:
为了简化,假设我们使用训练输入 ,其中一半的输入神经元值为 ,另一半为 。以下的论点更普遍适用,但你可以从这种特殊情况得到要点。让我们考虑隐藏神经元输入的带权和 。其中 个项消去了,因为对应的输入 为 。所以 是遍历总共 个归一化的高斯随机变量的和,包含 个权重项和额外的 个偏置项。因此 本身是一个均值为 标准差为 的高斯分布。 其实有一个非常宽的高斯分布,完全不是非常尖的形状:
尤其是,我们可以从这幅图中看出 会变得非常的大,即 或者 。如果是这样,隐藏神经元的输出 就会接近 或者 。也就表示我们的隐藏神经元会饱和。所以当出现这样的情况时,在权重中进行微小的调整仅仅会给隐藏神经元的激活值带来极其微弱的改变。而这种微弱的改变也会影响网络中剩下的神经元,然后会带来相应的代价函数的改变。结果就是,这些权重在我们进行梯度下降算法时会学习得非常缓慢[1]。
这其实和我们在本章前面讨论的问题差不多,前面的情况是输出神经元在错误的值上饱和导致学习的下降。我们之前通过代价函数的选择解决了前面的问题。不幸的是,尽管那种方式在输出神经元上有效,但对于隐藏神经元的饱和却一点作用都没有。
我已经讨论了第一个隐藏层的权重输入。当然,类似的论证也适用于后面的隐藏层:如果后面隐藏层的权重也是用归一化的高斯分布进行初始化,那么激活值将会非常接近 或者,学习速度也会相当缓慢。
还有可以帮助我们进行更好地初始化,能够避免这种类型的饱和,最终避免学习速度的下降?假设我们有一个有 个输入权重的神经元。我们会使用均值为 标准差为 的高斯随机分布初始化这些权重。也就是说,我们会向下挤压高斯分布,让我们的神经元更不可能饱和。我们会继续使用均值为 标准差为 的高斯分布来对偏置进行初始化,后面会告诉你原因。有了这些设定,带权和 仍然是一个均值为 , 不过有尖锐峰值的高斯分布。假设,我们有 个值为 的输入和 个值为 的输入。那么很容易证明 是服从均值为 标准差为 的高斯分布。这要比以前有更尖锐的峰值,尖锐到为了用下图更直观地比较,我不得不对对纵坐标进行压缩:
这样的一个神经元更不可能饱和,因此也不大可能遇到学习速度下降的问题。
练习
验证 标准差为 。下面两点可能会有帮助:(a)独立随机变量和的方差,是每个独立随机变量方差的和;(b)方差是标准差的平方。
我在上面提到,我们会继续使用之前的方式对偏置进行初始化,就是使用均值为 标准差为 的高斯分布来对偏置进行初始化。这其实是可行的,因为这样并不会让我们的神经网络更容易饱和。实际上,考虑到已经避免了饱和的问题,如何初始化偏置影响不大。有些人将所有的偏置初始化为 ,依赖梯度下降来学习合适的偏置。但是因为差别不是很大,我们后面还会按照前面的方式来进行初始化。
让我们在 MNIST 数字分类任务上比较一下新旧两种权重初始化方式。同样,还是使用 个隐藏元,minibatch 的大小为 ,规范化参数 ,然后是交叉熵代价函数。我们将learningrate从 降到 ,因为这样会让结果在图像中表现得更加明显。我们先使用旧的权重初始化方法训练:
>>> 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.1, lmbda = 5.0,
… evaluation_data=validation_data,
… monitor_evaluation_accuracy=True)
我们也使用新方法来进行权重的初始化。这实际上还要更简单,因为network2 默认方式就是使用新的方法。这意味着我们可以丢掉上面的net.large_weight_initializer() 调用:
>>> net = network2.Network([784, 30, 10], cost=network2.CrossEntropyCost)
>>> net.SGD(training_data, 30, 10, 0.1, lmbda = 5.0,
… evaluation_data=validation_data,
… monitor_evaluation_accuracy=True)
将结果用图展示出来[2],我们得到:
两种情形下,我们最终都获得了超过 96% 的准确率。最终的分类准确率几乎完全一样。但是新的初始化技术带来了速度的提升。在经过一轮迭代后,第一种初始化方式的分类准确率在 87% 以下,而新的方法已经几乎达到了 93%。看起来的情况就是我们新的关于权重初始化的方式将训练带到了一个新的境界,让我们能够更加快速地得到好的结果。同样的情况在 个神经元的设定中也出现了:
在这个情况下,两个曲线并没有重合。然而,我做的实验发现在一些额外的迭代次数之后准确率也是几乎相同的。所以,基于这些实验,看起来提升的权重初始化仅仅会加快训练,不会改变网络的最终性能。然而,在第四章,我们会看到一些例子里面使用 权重初始化的长期运行的结果要显著更优。因此,不仅仅能够带来训练速度的加快,有时候在最终性能上也有很大的提升。
的权重初始化方法帮助我们提升了神经网络学习的方式。其他的权重初始化技术同样也被提出,很多都是基于这个基本的思想。我不会在这里回顾其他的方法,因为 已经可以工作得很好了。如果你感兴趣的话,我推荐你看看在2012 年的 Yoshua Bengio 的论文[3]的 14 和 15 页,以及相关的参考文献。
问题
将规范化和改进的权重初始化方法结合使用 L2 规范化有时候会自动给我们一些类似于新的初始化方法的东西。假设我们使用旧的初始化权重的方法。考虑一个启发式的观点:(1)假设 不太小,训练的第一轮迭代将会几乎被权重衰减统治;(2)如果 ,权重会在每轮迭代中按照因子 衰减;(3)假设 不太大,权重衰减会在权重降到 的时候保持住,其中 是网络中权重的个数。论证这些条件都已经在本节给出图示的例子中满足。
[1]我们在第二章详细讨论过这个问题,其中我们用反向传播的方程来显示输入到饱和神经元的权重学习得缓慢。
[2]用来生成这幅以及下一幅图形的程序是https://github.com/mnielsen/neural-networks-and-deep-learning/blob/master/fig/weight_initialization.py。
[3]http://arxiv.org/pdf/1206.5533v2.pdf Practical Recommendations for Gradient-Based Training of Deep Architectures,作者为Yoshua Bengio (2012)。
本文来源于哈工大SCIR