作者:Cecelia Shao 编译:ronghuaiyang
导读
这篇文章提供了可以采取的切实可行的步骤来识别和修复机器学习模型的训练、泛化和优化问题。
众所周知,调试机器学习代码非常困难。即使对于简单的前馈神经网络也是这样,你经常会在网络体系结构做出一些决定,重初始化和网络优化——所有这些会都导致在你的机器学习代码中出现bug。
正如Chase Roberts在一篇关于“How to unit test machine learning code”的优秀文章中所写的,他遇到的麻烦来自于常见的陷阱:
那么我们该怎么做呢?
本文将提供一个框架来帮助你调试神经网络:
请随意跳转到特定的部分或通读下面的内容!请注意:我们不包括数据预处理或特定的模型算法选择。对于这些主题,网上有很多很好的资源。
一个具有复杂结构和正则化以及学习率调度程序的神经网络将比一个简单的网络更难调试。我们在第一点上有点欺骗性,因为它与调试你已经构建的网络没有什么关系,但是它仍然是一个重要的建议!
从最简单的开始:
首先,构建一个只有一个隐藏层的小型网络,并验证一切正常。然后逐步增加模型的复杂性,同时检查模型结构的每个方面(附加层、参数等),然后再继续。
作为一个快速的完整性检查,你可以使用一两个训练数据点来确认你的模型是否能够过拟合。神经网络应该立即过拟合,训练精度为100%,验证精度与你的模型随机猜测相匹配。如果你的模型不能对这些数据点进行过拟合,那么要么是它太小,要么就是存在bug。
即使你已经验证了模型是有效的,在继续之前也可以尝试训练一个(或几个)epochs。
你的模型的损失是评估你的模型性能的主要方法,也是模型评估的重要参数,所以你要确保:
注意,你最初的损失也很重要。如果模型一开始就随机猜测,检查初始损失是否接近预期损失。在Stanford CS231n coursework中,Andrej Karpathy提出了以下建议:
在随机表现上寻找正确的损失。确保在初始化小参数时得到预期的损失。最好先单独检查数据的loss(将正则化强度设置为零)。例如,对于使用Softmax分类器的CIFAR-10,我们期望初始损失为2.302,因为我们期望每个类的随机概率为0.1(因为有10个类),而Softmax损失是正确类的负对数概率,因此:-ln(0.1) = 2.302。
对于二分类的例子,只需对每个类执行类似的计算。假设数据是20%的0和80%的1。预期的初始损失是- 0.2ln(0.5) - 0.8ln(0.5) = 0.693147。如果你的初始损失比1大得多,这可能表明你的神经网络权重不平衡(即初始化很差)或者你的数据没有标准化。
要调试神经网络,通常了解神经网络内部的动态以及各个中间层所起的作用以及这些中间层之间如何连接是很有用的。你可能会遇到以下错误:
如果梯度值为零,这可能意味着优化器中的学习率可能太小,或者你遇到了上面的错误#1,其中包含梯度更新的不正确的表达式。
除了查看梯度更新的绝对值之外,还要确保监视激活的大小、权重的大小和每个层的更新相匹配。例如,参数更新的大小(权重和偏差)应该是1-e3。
有一种现象叫做“死亡的ReLU”或“梯度消失问题”,ReLU神经元在学习了一个表示权重的大的负偏置项后,会输出一个零。这些神经元再也不会在任何数据点上被激活。
你可以使用梯度检查来检查这些错误,通过使用数值方法来近似梯度。如果它接近计算的梯度,则正确地实现了反向传播。
Faizan Shaikh描述了可视化神经网络的三种主要方法:
有许多有用的工具可以可视化单个层的激活和连接,比如ConX和Tensorboard。
使用ConX生成的动态呈现可视化示例
神经网络有大量的参数相互作用,使得优化变得困难。请注意,这是一个活跃的研究领域,所以下面的建议只是简单的出发点。
在实践中已经观察到,当使用一个较大的batch size时,模型的质量会下降,这可以通过它的泛化能力来衡量。我们研究了在大批量情况下泛化下降的原因,并给出了支持large-batch方法趋向于收敛于训练和测试函数的sharp的极小值这一观点的数值证据——众所周知,sharp的极小值导致较差的泛化。相比之下,小batch size的方法始终收敛于平坦的最小值,我们的实验支持一个普遍的观点,即这是由于梯度估计中的固有噪声造成的。
本文来自Dishank Bansal的”TensorFlow中batch norm的陷阱和训练网络的健康检查“,里面包括了很多使用batch norm的常见错误。
通常情况下,损失函数是数据损失和正则化损失的总和(例如L2对权重的惩罚)。需要注意的一个危险是正则化损失可能会超过数据损失,在这种情况下,梯度将主要来自正则化项(它通常有一个简单得多的梯度表达式)。这可能会掩盖数据损失的梯度的不正确实现。
为了检查这个问题,应该关闭正则化并独立检查数据损失的梯度。
来自Stackoverflow的用户
MiloMinderBinder
:Dropout是为了完全阻断某些神经元的信息,以确保神经元不相互适应。因此,batch norm必须在dropout之后进行,否则你将通过标准化统计之后的数据传递信息。” 来自arXiv:Understanding the Disharmony between Dropout and Batch Normalization by Variance Shift — 从理论上讲,我们发现,当我们将网络状态从训练状态转移到测试状态时,Dropout会改变特定神经单元的方差。但是BN在测试阶段会保持其统计方差,这是在整个学习过程中积累的。当在BN之前的使用Dropout时,该方差的不一致性(我们将此方案命名为“方差漂移”)导致不稳定的推断数值行为,最终导致更多的错误预测。
你很容易忽视记录实验的重要性,直到你忘记你使用的学习率或分类权重。通过更好的跟踪,你可以轻松地回顾和重现以前的实验,以减少重复的工作(也就是说,遇到相同的错误)。
然而,手工记录信息对于多个实验来说是很困难的。工具如 Comet.ml可以帮助自动跟踪数据集、代码更改、实验历史和生产模型(这包括关于模型的关键信息,如超参数、模型性能指标和环境细节)。
你的神经网络对数据、参数甚至版本中的细微变化都非常敏感,这会导致模型性能的下降。跟踪你的工作是开始标准化你的环境和建模工作流的第一步。
我们希望这篇文章为调试神经网络提供了一个坚实的起点。要总结要点,你应该:
—END—
英文原文:https://towardsdatascience.com/checklist-for-debugging-neural-networks-d8b2a9434f21