37 Reasons why your Neural Network is not working
原文链接:https://blog.slavv.com/37-reasons-why-your-neural-network-is-not-working-4020854bd607
网络已经训练了12个小时了。看起来一切都好:梯度稳定,损失在降低。但是当检测的时候就是检测不出来东西。到底哪里出了问题呢?
下面是一些很好的检查策略。
0. 如何使用这份指南
很多地方可以出错,但是一些优先级高的问题需要先处理。
- 首先使用一个对这个类型的数据有用的简单模型(例如,对于图像可以用VGG)。如果可以,使用标准loss。
- 关掉全部附加操作。如:regularization和数据增强
- 如果是finetuning一个模型,再次检查一下预处理(preprocessing),它应该和原始模型训练一样。?
- 检验输入数据是正确的。
- 从非常小的数据集开始(2-20个样本)。在这个数据集上过拟合然后逐渐添加更多的数据。
- 开始逐渐把之前关掉的小功能添加回来:augmentation/regularization, custom loss functions,尝试更复杂的模型。
如果完成了上述步骤还是不行的话,开始从下面的列表一个一个的验证。
I. 数据问题
1. 检查你的输入数据
检查你喂给网络的输入数据是否正确。举个例子,我不止一次的将图像的宽与高搞混。有时候,我错误地将全部都是零的数据喂给模型。或者一遍又一遍地使用同一个batch。所以打印一组batches的输入和目标输出,看看它们是否正确。
2. 尝试随机输入
尝试将随机数字作为输入而不是实际的数据,看看是否表现的一样。如果是,很确定是你的网络再某一些点上将数据变成了垃圾。试着一层一层的debugging,看看哪里出了问题。
3. 检查data loader
你的数据可能没事但将它们传入网络的代码可能错了。在做任何操作之前打印网络第一层的输入,检查一下。
4. 确保输入是连接着输出标签的
检查一些输入样本是否有正确的标签。确保打乱输入样本时输出标签也跟着变化。
5. 输入和输出的关联性太随机了吗?
输入和输出的关联性并不大。
6. 数据集中的脏数据太多?
检查一些输入样本是否有正确的标签。
7. 打乱数据集
如果你的数据集从未被打乱过,而且有特定的顺序(标签顺序),这对学习是个负面影响。打乱数据集避免这个情况。确保同时打乱输入和输出标签。
8. 减少类别失衡
如果有类别失衡的情况,你可能需要平衡你的损失函数。
9. 是否有足够多的训练数据
如果你从头训练一个网络(not finetuning),你可能需要大量的数据。对于图像分类,对每个类别你可能需要1000个图像或者更多。
10. 确认你的batches不会包含单一的标签
可能出现在有序的数据集的情况。打乱数据集避免这个情况。
11. 减小batch大小
非常大的batch会减少模型的generalization能力。
Addition 1. 首先使用标准的数据集
在测试新的网络结构或写新代码时,首先使用标准的数据集而不是你自己的数据集。这是因为这些数据集有相关的问题已经被解决了。而且不会有标签错误,训练测试分布不同等等数据集相关的问题。
II. 数据 Normalization/Augmentation
12. Standardize the features
你的输入是否平均值为0,方差为1。
13. 数据增强做太多了?
过多的数据增强再加上regularization(weight L2,dropout,等)可以导致网络欠拟合。
14. 检查预训练模型的preprocessing
如果你使用预训练的模型。确保在训练的时候使用同样normalization和preprocessing。例如,图像的像素值应该在范围[0, 1], [-1, 1]或[0, 255]。
15. 检查训练/验证/测试集的预处理
在CS231n中指出。所有的预处理统计必须只在训练集上进行计算,然后应用于验证/测试集。例如,在整个数据集上计算平均值并减去它,然后再分成训练/验证/测试集会出现错误。
在每一个样本和batch上检查不同的预处理。
III. 实现错误
16. 尝试解决一个简单版本的问题
这会帮助找到bug在哪。例如,当目标输出是一个目标类别和坐标,试着先只预测类别。
17. 查看正确的损失
来自CS231n:
确保在初始化小参数时得到预期的损失。最好先单独检查data loss (因此将正则化强度设置为零)。例如,对于使用Softmax分类器的CIFAR-10,我们期望初始损失为2.302,因为我们期望每个类的扩散概率为0.1(因为有10个类),而Softmax损失是正确类的负对数概率,因此:-ln(0.1) = 2.302。对于Weston Watkins SVM,我们期望所有期望的边距都被破坏(因为所有的分数都近似为零),因此期望损失9(因为每个错误的类的边距为1)。如果您没有看到这些损失,那么初始化可能会有问题。
在这之后,尝试提高正则化强度应该可以提高损失。
18. 检查你的损失函数
如果你实现的你自己的损失函数,使用单元测试,检查一下有没有bug。有时候,损失函数轻微的错误可以轻微的影响网络的性能。
19. 检验损失输入
如果你使用框架提供的loss函数,请确保传递给它的是它所期望的。例如,在PyTorch中,我将混合NLLLoss和CrossEntropyLoss,因为前者需要一个softmax输入,而后者不需要。
20. 调整损失权重
如果损失由几个较小的损失函数组成,请确保它们相对于每个损失函数的大小是正确的。这可能需要测试不同的权重组合。
21. 监控其他度量
对于你的网络是否训练的正确,有时候损失不是最好的监控器。如果可以,也可以使用其他度量如正确率。
22. 测试每一个自定义层
你在网络中有你自己自定义的层吗?多次确认确保它们工作正常。
23. 检查是否有frozen层或变量
检查一下是否有无意中禁用了一些应该可学习的层/变量的梯度更新。
24. 增加网络大小
也许您的网络的表达能力不足以到达目标函数。尝试在全连接层中添加更多层或更多隐藏单元。
25. 检查隐藏层维度错误
如果你的输入像这样 (k, H, W) = (64, 64, 64),这会很容易错过错误的关联维度。先使用不同的数字作为输入维度的值,然后检查是否正确。
26. 探索梯度检查
如果你手动实现的梯度下降,梯度检查确保向后传播是正确的。
http://ufldl.stanford.edu/tutorial/supervised/DebuggingGradientChecking
http://cs231n.github.io/neural-networks-3/#gradcheck
https://www.coursera.org/lecture/machine-learning/gradient-checking-Y3s6r
IV. 训练错误
27. 从一个很小的数据集开始解决问题
过拟合一个很小的数据集的子集,然后确保训练正常。例如,一个类别只训练一个或两个样本,然后看网络是否可以学到它们的不同。然后每个类别加入更多的样本。
28. 检查权重初始化
如果不确定,就使用 Xavier 或 He 初始化。另外,你的初始化可能会领向一个坏的局部最低值,所以试一下不同的初始化看看是否有帮助。
29. 检查你的超参数
可能你使用的特别坏的超参数设置。如果可以,试一试grid search。
30. 减少regularization
太多的regularization可以造成网络严重的欠拟合。减少regularization像dropout,batch norm,weight/bias L2 regularization等等。在这个教程中,建议要首先避免欠拟合。这意味着你先要充分的过拟合,然后再解决过拟合。
31. 给模型多点时间
在你的网络开始做有意义的预测之前,可能它需要更多的时间去训练。如果你的loss稳定下降,就让它继续训练。
32. 从训练模式转换为测试模式
有一些架构有一些层像Batch Norm,Dropout和其他的在训练和测试表现不同的层。转换为合适的模型对模型正确预测可能会帮助。
33. 训练可视化
-
监视每一层的激活、权重和更新。确保它们的量级匹配。例如,参数更新的量级(权重和偏差)应该是1-e3。
-
考虑一个可视化库,比如Tensorboard和Crayon。在紧要关头,你还可以打印权重/偏差/激活。
-
注意那些平均值远远大于0的层激活。尝试Batch Norm或ELUs。
-
Deeplearning4j指出了在权重和偏见的直方图中应该期望什么:
“对于权重,这些直方图应该在一段时间后具有近似高斯(正态)分布。对于偏差,这些直方图通常从0开始,并且通常以近似高斯分布结束(LSTM是一个例外)。注意那些发散到+/-∞的参数。注意那些非常大的偏见。如果类的分布非常不平衡,这有时会发生在用于分类的输出层。”
-
检查层更新,它们应该有一个高斯分布。
34. 尝试不同的优化器
你选择的优化器不应该阻止你的网络进行训练,除非你选择了特别糟糕的超参数。然而,对任务使用适当优化器有助于在最短的时间内获得最多的训练。你正在使用的论文描述算法的时候应该有指定了优化器。如果没有,我倾向于使用Adam或带动量的普通SGD。
更多关于梯度下降优化器的内容看这篇优秀的博文。
35. 梯度爆炸/消失
- 检查层更新,因为非常大的值可以表明爆炸梯度。梯度裁剪可能会有所帮助。
- 检查层激活。Deeplearning4j提供了一个很好的指导:“激活的良好标准偏差在0.5到2.0之间。明显超出这一范围可能意味着激活消失或爆炸。”
36. 学习率增加/减少
一个很低的学习率会导致你的模型收敛非常慢。
一个很高的学习率可以再开始的时候很快降低损失,但是可能很难找到最好的权重。
通过将当前的学习率乘以0.1或10来测试最佳的学习率。
37. 解决NaNs
据我所知,在训练RNNs时,获得一个NaN(Non-a-Number)是一个很大的问题。一些解决方法:
- 降低学习速度,特别是如果你在前100次迭代中得到了NaNs。
- 除以零或零的自然对数或负数可以导致NaNs。
- Russell Stewart对如何解决NaNs有很好的建议。
- 试着一层一层地评估你的网络,看看NaNs出现在哪里。