(译)你的神经网络不工作的37个可能原因
神经网络的训练是一个复杂的问题,很多时候会遇见即使拿到了别人的代码也训练不出来,无法复现。 以下是37个训练网络的建议英文原文:
1.最基本的措施
- 从已知适用于此类数据的简单模型开始(例如,VGG用于图像)。如果可能,使用标准损失。
- 关闭训练的小技巧。如正则和数据增强。
- 如果微调一个模型,检查预处理操作,要保证和原始模型训练的预处理操作一样。
- 验证输入数据是否正确。
- 从一个非常小的数据集开始(2-20个样本)。在它上面叠加并逐渐添加更多数据(不要想一口气吃成一个胖子)。
- 开始逐步添加所有省略的部分:增强/正则化,自定义损失函数,尝试更复杂的模型。
2.数据问题
检查你的输入数据
- 检查您输入网络的输入数据是否有意义。例如,我不止一次混合了图像的宽度和高度。有时,我由于失误填充了0。或者我会一遍又一遍地使用同一批次。因此,打印/显示几批输入和目标输出,并确保它们正常。
尝试随机输入
- 尝试传递随机数而不是实际数据,并查看错误的行为是否相同。如果确实如此,那肯定表明您的网络在某个时刻将数据转化为垃圾。尝试通过op /逐层调试,并查看出错的地方。
检查数据加载器
- 您的数据可能没问题,但是将输入传递到网络的代码可能会被破坏。在任何操作之前打印第一层的输入并检查它。
确保输入连接到输出
- 检查一些输入样本是否具有正确的标签。同时确保随机输入样本对输出标签的工作方式相同。
输入和输出之间的关系是否过于随机?
- 也许输入和输出之间关系的非随机部分与随机部分相比太小(人们可能认为股票价格是这样的)。即输入与输出不充分相关。没有一种通用的方法来检测它,因为它取决于数据的性质。
数据集中是否存在太多噪声
- 当我从食物网站上抓取图像数据集时,这种情况发生在我身上。网络无法学习的标签太多了。手动检查一堆输入样本,看看标签是否关闭。
数据集打乱
- 如果您的数据集没有被洗牌并且具有特定的顺序(按标签排序),这可能会对学习产生负面影响。随机打乱数据集以避免这种情况。确保将输入和标签混合在一起。
减少类间不平衡
- 每个B类图像都有1000个A类图像吗?那么你可能需要平衡你的损失函数或尝试其他类间不平衡方法。
您的训练样本足够了吗?
- 如果您从头开始训练网(即不是微调),您可能需要大量数据。对于图像分类,人们说每个级别或更多需要1000张图像。
确保您的Batch不包含单个标签
- 这可能发生在已排序的数据集中(即前10k样本包含相同的类)。通过改组数据集可以轻松修复。
减少Batchsize
- 具有非常大的批次会降低模型的泛化能力。
使用标准数据集
- 在测试新网络架构或编写新代码时,首先使用标准数据集,而不是自己的数据。这是因为这些数据集有很多参考结果,并且它们被证明是“可解决的”。不会出现标签噪音,训练/测试分布差异,数据集难度太大等问题。
3.数据标准化/增强
特征标准化
- 您是否将输入标准化为零均值和单位方差?
你有太多的数据增强吗?
- 增强具有正则化效果。太多的这种与其他形式的正规化(权重L2正则,dropout等)相结合会导致网络欠拟合。
检查预训练模型的预处理
- 如果您使用的是预训练模型,请确保使用与训练时模型相同的标准化和预处理。例如,图像像素应该在[0,1],[-1,1]还是[0,255]范围内?
检查训练集/验证集/测试集的预处理
CS231n指出了一个常见的陷阱:“…任何预处理统计数据(例如数据均值)必须仅在训练数据上计算,然后应用于验证/测试数据。例如。计算平均值并从整个数据集中的每个图像中减去它,然后将数据拆分为train / val / test splits将是一个错误。“
4.实现问题
尝试解决问题的简单版本
- 这有助于找到问题所在。例如,如果目标输出是对象类别和坐标,请尝试仅将预测限制为对象类别。
寻找“偶然”的正确损失
- 再次来自优秀的CS231n:使用小参数初始化,无需正则化。例如,如果我们有10个类,那么偶然意味着我们将在10%的时间内获得正确的类,而Softmax损失是正确类的负对数概率,因此:-ln(0.1)= 2.302。在此之后,尝试增加正规化强度,这应该增加损失。
检查你的损失函数
- 如果您实现了自己的损失函数,请检查它是否有错误并添加单元测试。通常,我的损失会略微不正确,并以微妙的方式损害网络的性能。
验证损失输入
- 如果您正在使用框架提供的损失函数,请确保您按预期传递给它。例如,在PyTorch中,我会混合NLLLoss和CrossEntropyLoss,因为前者需要softmax输入而后者不需要。
调整损失的权重
- 如果您的损失由几个较小的损失函数组成,请确保它们相对于每个损失的大小是正确的。这可能涉及测试损失权重的不同组合。
监控其他指标
- 有时,丢失不是预测您的网络是否正常训练的最佳预测因素。如果可以,请使用其他指标,如准确性。
测试任何自定义网络层
- 你自己实现了网络中的任何层吗?检查并仔细检查以确保它们按预期工作。
检查“冻结”层或变量
- 检查是否无意中禁用了一些应该可以学习的网络层/变量的梯度更新。
提升网络大小
- 也许你的网络的表现力不足以捕获目标功能。尝试增加更多网络层或者在全连接的层中添加更多隐藏单位。
检查隐藏的尺寸错误
- 如果您的输入看起来像(k,H,W)=(64,64,64),则很容易错过与错误尺寸相关的错误。使用奇怪的数字作为输入维度(例如,每个维度的不同素数)并检查它们如何通过网络传播。
探索梯度检查
- 如果您手动实现了梯度下降,则梯度检查可确保您的反向传播能够正常工作。
5.训练问题
解决一个非常小的数据集
- 过度拟合一小部分数据并确保其有效。例如,仅使用1或2个样本进行训练,看看您的网络是否可以学会区分这些。继续增加每一类的样本数。
检查权重初始化
- 如果不确定,请使用Xavier或He初始化。此外,您的初始化可能会导致您的局部最小值不正确,因此请尝试不同的初始化并查看是否有帮助。
更改你的超参数
- 也许你使用了一组特别糟糕的超参数。如果可行,请尝试网格搜索。
减少正则化
- 过多的正规化会导致网络严重欠拟合。减少正规化,如dropout,bn,权重/偏差L2正规化等。在优秀的“Practical Deep Learning for coders” 课程中,杰里米霍华德建议首先摆脱欠拟合。这意味着您要充分地过度训练数据,然后只需要解决过拟合问题。
给网络一点时间
- 也许您的网络需要更多时间进行训练才能开始进行有意义的预测。如果你的损失在稳步下降,那就让它训练久一些。
从训练切换到测试模式
- 一些框架具有Batch Norm,Dropout等层,其他层在训练和测试期间表现不同。切换到适当的模式可能有助于您的网络正确预测。
训练可视化
- 监控每个层的激活,权重和更新。确保它们的大小匹配。例如,参数更新的大小(权重和bias)应为1-e3。
- 考虑像Tensorboard和Crayon这样的可视化库。在紧要关头,您还可以打印重量/bias/激活。
- 请注意层次激活,平均值远大于0.尝试批量标准或ELU。
- Deeplearning4j指出在权重和偏差的直方图中会发生什么.
“对于权重,这些直方图应在一段时间后具有近似高斯(正态)分布。对于偏差,这些直方图通常从0开始,并且通常最终将近似为高斯(对于LSTM这是一个例外)。留意发散到+/-无穷大的参数。留意变得非常大的bias。如果类的分布非常不平衡,有时可能会在输出层中进行分类。“
- 检查网络层更新,它们应该具有高斯分布。
尝试使用其他优化器
- 除非您选择了特别糟糕的超参数,否则您选择的优化器不应该阻止您的网络进行训练。但是,对于一个任务采用适当的优化器可以帮助您在最短的时间内获得最多的训练。您正在使用的算法的论文指定了特定的优化器。如果没有,我倾向于使用Adam或plain SGD with momentum。
爆炸/消失的梯度
- 检查网络层更新,非常大的值可能意味着梯度爆炸。梯度剪裁可能会有所帮助。
- 检查网络层激活。来自Deeplearning4j的一个很好的指导原则是:“激活的良好标准偏差大约为0.5到2.0。显着超出此范围可能表明消失或爆炸激活。“
增加/降低学习率
学习率低会使您的模型收敛得非常慢。
高学习率将在一开始就迅速减少损失,但可能很难找到一个好的解决方案。
通过将其乘以0.1或10来解决当前的学习率。
克服NaNs
训练RNN时遇到NaN是一个更严重等的问题。一些解决方法:
- 降低学习率,特别是如果你在前100次迭代中获得NaNs。
- NaN可以由零除或零或负数的自然对数产生。
- 拉塞尔·斯图尔特(Russell Stewart)对如何应对NaNs提出了很好的建议how to deal with NaNs。
- 尝试逐层评估您的网络,并查看NaN的出现的位置。