转载

揪出bug!解析调试神经网络的技巧

来源:CSDN   http://geek.csdn.net/news/detail/68181

原文链接: Introduction to debugging neural networks

译者:刘翔宇 审校:刘帝伟

责编:周建丁

以下建议是针对神经网络初学者的,这些建议都来自于我在行业应用和斯坦福大学里为神经网络初学者提供建议所获得的经验。本质上讲,神经网络要比大多数程序难以调试,因为大多数神经网络bug不会导致类型错误或运行时错误。只会导致不良的收敛。特别是你刚入门,碰到这些问题会非常令人沮丧!但经验丰富的神经网络训练者能够系统地克服这些困难,尽管有许多看似模棱两可的错误信息:

性能错误:你的神经网络没有训练好(Performance Error: your neural net did not train well.)。

对于门外汉来说,这条错误信息令人畏惧。但是对经验丰富的人来说,这是一个巨大的错误。它意味着样板代码不能正常工作,是时候深入代码调试了!

如何处理NaN

到目前为止,我的学生提出的最常见的一个问题就是,“我为什么会得到NaN错误。”有时,这问题有复杂的原因。但多数情况下,NaN错误在前100次迭代中出现,原因很简单:你的学习率过高了。当学习率非常高的时候,就会在前100次迭代的时候出现NaN错误。用因子为3来降低学习率,直到前100次迭代不再出现NaN错误。这么做一旦有效,你就有了一个非常好的学习率作为开端。根据我的经验,最好的学习率是你得到NaN错误的范围的一到十分之一。

如果你在100次迭代之后碰到了NaN错误,又有两种常见原因。

  1. 如果你使用的是RNN,确保你使用了梯度下降,并对梯度使用L2正则化。RNN似乎在训练早期会产生梯度,10%或更少的批次有学习峰值,此时的梯度幅值是相当高的。没有对梯度削减,这些峰值会产生NaN。
  2. 如果写的是自定义的网络层,那么很有可能因为除以0而引发NaN。另一个众所周知会产生Nan错误的层是Softmax层。Softmax计算包括分子分母的exp(x)操作,它可以用无穷大除以无穷大,会产生NaN。确保你使用了稳定的Softmax实现。

神经网络学习不到任何东西怎么办

一旦你没有了NaN错误,那么你的神经网络就可以在上千次迭代中平稳运行,而且不会在前几百次迭代后减少训练损失。当你第一次构建代码库的时候,最好别使用2000次迭代。这并不是因为所有的网络可以从低于2000次迭代开始学习。相反,从开头开始编码网络很可能出现bug,在达到高迭代次数之前,你会想要过早进行调试。现在的目的是一次又一次地缩小问题范围,直到你得到了一个在2000次迭代以下训练出来的网络。幸运地是,有两种方式来降低复杂性。

  1. 将训练集大小减小到10个实例。 在几百次的迭代中,在这10个实例上,神经网络通常会出现过度拟合的情况。许多编码错误不会导致过拟合的出现。如果你的网络在10个实例的训练集上没有出现过度拟合,那么确保你使用的数据挂上了正确的标签。将批次大小减小到1来检查批次计算错误。在代码中添加打印语句确保输出与你期望的一致。通常情况下,你可以通过上面介绍的纯粹蛮力来找出错误。一旦网络可以在10个实例上训练,你可以试着让它在100个实例上训练。如果这种方式运行正常,但效果不是很好,你可以试试下面的方法。
  2. 解决你感兴趣的最简单的问题。 如果你想翻译句子,首先可以建立一个针对特定语言的语言模型。如果你完成了,那么试着在给出3个词语的情况下预测翻译出来的第一个词。如果你想检测图像中的物体,那么在训练回归网络之前,你可以对图像中物体数目进行分类。在网络能够解决的棘手问题和使用最少的时间让代码得到合适的数据之间需要权衡。这个时候就要发挥你的创造能力了。

将神经网络运用于其他新场景的技巧是合理使用上面介绍的两个步骤。这是一种协调机制,并且效果不错。首先,你表明这个神经网络至少可以记住几个例子。然后这个神经网络可以泛化到更简单问题的验证集中。你慢慢在取得稳步进展时提升难度。这并没有高手第一次使用的Karpathy风格那么有趣,但至少它起作用。有时候你会碰到棘手的问题,你会发现它在2000次迭代中不会继续学习了。那很棒!但它的迭代次数很少会是这个问题之前复杂度下迭代次数的10倍。如果你发现是这种情况,尝试搜索中等水平的复杂度。

调整超参数

现在你的网络可以学习东西了,你可能会得意忘形。你还可能发现你训练的网络并不能够解决大多数复杂的问题。超参数调整就是解决问题的关键。有些人直接下载一个CNN的包然后在他们的数据集上运行,然后告诉你说使用超参数调整并没有带来什么不同。这是因为它们使用已经存在的架构来解决已经存在的问题。 如果你要解决的问题需要新的架构呢,通过超参数调整来得到良好的设置就是必须的了。 你最好确保针对你要解决的问题阅读了超参数教程,不过我还是会在下面列出一些基本思想。

  • 可视化是关键。不要怕在训练过程中花时间编写自定义可视化工具。如果你的可视化方法效果不行,那么考虑换另一种方法。
  • 权重初始化很重要。一般情况下,较大的初始化权重是个不错的选择,但是太大又会导致NaN。因此权重的初始化需要与学习率一同调整。
  • 确保权重看起来“健康”。要了解这是什么意思,我建议在IPython的notebook中查看现有网络的权重值。花些时间来观察在诸如ImageNet或Penn Tree Bank这些标准的数据集上训练的成熟的网络中成分的权重的直方图应该是什么样的。
  • 神经网络的w.r.t.输入不是不变的,特别是在使用SGD而不是其他方法训练的时候,因为SGD不是尺度不变的方法。花时间用与扩展其他方面的方式来扩展输入数据和输出标签。
  • 在训练过程中降低学习速率几乎总会给你带来提升。最好的衰减策略通常是:在k次迭代后,每n次迭代就用学习率除以1.5,k>n。
  • 使用超参数配置文件,虽然把超参数放到代码中也行,但是如果你想试试不同的值那么会比较麻烦。我把参数放在一个JSON文件中,使用一条命令导入,参见 https://github.com/Russell91/tensorbox ,确切的格式不重要。不要轻易重构代码,因为重新加载超参数比较麻烦!重构会引入bug,它们将会延长训练周期,并且可以在你得到一个你喜欢的网络前避免。
  • 如果你负担得起,随机化你的超参数搜索。随机搜索能生成你意想不到的超参数组合,并且一旦你了解某个超参数会产生的影响,随机搜索减少你许多工作。

结论

调试神经网络比传统的程序更费劲,因为大部分错误发生在整个网络的单一维度上。然而,二分查找仍然是你的朋友。通过 改变问题的难度使用少量的训练样例 的交替,你能快速解决最初的bug。超参数调整和长时间耐心等待可以解决余下的问题。

原文  http://dataunion.org/23641.html
正文到此结束
Loading...