深度玄学:你的网络不work的37种原因
2018/4/10 18:15:47 中国科学院自动化研究所

如何利用这篇guide
深度学习的程序可能出错的地方有很多,这其中有一些错误发生频率比其他更高。通常我会从如下一些方面先行入手:
◆从简单并且得到广泛应用的网络开始,如VGG,如果可以的话使用标准的损失函数。
◆暂时去掉所有的trick,如数据增强(Data Augmentation)和正则化(regularization)。
◆如果是微调(finetuning)模型,再次检查数据的预处理,保证其和原始网络训练时一致。
◆检查输入数据是正确的。
◆从很少量的数据开始(2-20样本),使其过拟合,然后逐渐增加样本。
◆逐渐增加trick,数据增强,正则化,新的损失函数,更复杂的网络等等。
如果上面的仍然不work的话,请按照下面的逐条实验。
1.数据集问题

1)检查输入数据
检查输入给网络的数据是不是有意义的。比如,我不止一次将高度和宽度混淆(输入的图像是转置的)。有时因为数据预处理的错误输入的是全0图像。或者将同一batch的图像反复送入网络。所以,先打印出几个batch的输入保证正确性。
2)尝试随机输入
尝试输入随机数量的样本检查是否出现相同的错误。如果仍然出现同样的错误,说明网络本身有问题。这时尝试逐层调试。
3)检查Data loader
不同的框架有不同的data loader,如tensorflow的tfrecords,keras的imagegenerator等。数据本身可能没什么问题,但data loader可能有出错地方。先打印第一层的输入进行检查。
4)确保网络输入和输出是一致的
检查输入和预定的输出(label)是不是一致的,比如是否同时进行相同的shuffle。
5)输入和输出的关系是否太过随机?
可能输入和输出的关系随机的成分更大,关系成分更小,如股票预测。这种情况下输入和输出不存在有效的关系。没有通用的方法检查这种情况,因为这决定于数据。
6)数据集标签噪音是否过大?
这种情况多发于自己从网上爬数据或者某些小型比赛。比如我从食物网站爬数据时经常有很多标签是不正确的。先手动检查一部分数据的标签是不是有很大噪声。
7)打乱(shuffle)数据
如果你的数据没有打乱而是有一定顺序的,这可能会给网络学习带来很负面的影响。确保你的数据经过了shuffle。
8)减小数据不平衡
数据的不平衡指的是不同类别样本数量相差很大,如医疗数据就经常出现这种情况。数据的不平衡会导致损失函数的不平衡。由于篇幅限制,本文不再讨论如何平衡数据,可以参考https://machinelearningmastery.com/tactics-to-combat-imbalanced-classes-in-your-machine-learning-dataset/。(可能需要科学上网哦)
9)训练样本是否足够
如果网络是从头开始训练而不是fine-tuning,那么可能需要大量的数据。对于分类任务来说,通常一个类需要1000样本甚至更多。
10)确保一个batch中样本不是都属于同一类
这种情况可能发生于样本是有序的情况下,不过通过shuffle可以很容易解决这个问题。
11)减小batch size
论文《On Large-Batch Training for Deep Learning: Generalization Gap and Sharp Minima》指出非常大的batch可能会减弱网络的泛化性能。
Additional:使用标准数据集
当测试新的网络时首先使用标准的数据集如mnist而不是自己的数据,因为标准数据集标签噪声很小。如果网络在标准数据集上能够很好工作那么网络本身可能没有问题。
2.数据增强和归一化

12)归一化数据
检查是否将输入归一化为0均值标准方差。
13)数据增强是否太过?
数据增强有正则化的效果,但是太多的数据增强和其他形式的正则化如dorpout, l2 regularization一起可能会导致欠拟合。
14)查看预训练网络的预处理方式
如果你使用的是预训练的网络,确保你用了相同的预处理方式。如图像像素范围在[0,1],[-1,1]还是[0,255]。
15)检查对于训练集、验证集、测试集的预处理
斯坦福CS231课程对于数据预处理有详细论述,参考http://cs231n.github.io/neural-networks-2/#datapre
数据预处理必须只在训练集上计算,然后将参数用于验证集和测试集的处理。
3.实现过程问题

16)尝试解决问题的简化版本
这将帮助找到问题的来源。如当需要解决的问题是找到物体的具体位置和类别,可以先尝试暂时忽略定位任务,只完成分类任务
17)寻找正确的损失“at chance”
参考自CS231n,
http://cs231n.github.io/neural-networks-3/#sanitycheck。
"at chance"的意思是如果有10类样本,"at chance"会得到10%的正确率,这时Softmax的损失应该为-ln(0.1)=2.302。可以对比自己网络的损失检查。
18)检查损失函数
如果损失函数是自己实现的不是标准损失函数,检查是否有错,可以进行单独的输入测试。
19)检查损失函数的输入
如果损失函数来自于深度学习框架如tensorflow自带,确保你的输入和规定的一致。如在pytorch中NLLLoss和CrossEntropyLoss的输入容易被混淆,前者需要输入softmax形式的输入,而后者不需要。
20)调整损失权重
如果你的损失函数是有几个小的损失函数组成,检查他们的权重是否合理。不同组合的权重可能会导致结果差异很大。
21)监控其他度量(metrics)
有时损失并不是最合适的预测,如果可以的话,监测其他度量如准确率。
22)检查自己写的layer(custom layer)
如果自己写了框架中没有的层,一定要再三确保所写的layer正常工作。
23)检查layer或变量是否“forzen”
检查是否不小心将需要学习的layer或者变量”frozen”了。
24)增加网络深度/宽度
可能你的网络出现了欠拟合的问题,尝试增大网络。如增加卷积层或增加全连接层神经元的数目。
25)检查隐层数据维度是否有误
如果输入是(64,64,64)这样的维度形式,很容易出现维度错误,如通道维度和宽度互换。这种情况下使用特殊的数字进行检查,如不同的维度使用不同的数字。
26)检查梯度
如果有些层是自己手动写的梯度传播公式,检查是否实现有误。(有些框架中自己实现的layer是要自己写梯度)。参考CS231n的梯度检查说明http://cs231n.github.io/neural-networks-3/#gradcheck
4.训练问题

27)在非常小的数据集上训练
当数据集比较小时非常容易过拟合。这种情况下需要数据增强,过采样,或者使用外部数据等手段增加数据量。
28)检查权重初始化方式
如果不确定哪一种初始化方式对自己网络最有效时,推荐使用Xavier和He初始化。不合适的初始化可能会导致网络进入坏的局部最小值点,所以尝试不同的初始化方式。
29)改变超参数
超参数对网络影响很大,如果不确定哪种设置更好,可以采用grid search。参考http://scikit-learn.org/stable/modules/grid_search.html
30)减弱正则化
太多的正则可能导致网络能力不足,在适当情况下减弱如dropout, batch norm, weight l2 regularzation等。参考Jeremy的课程http://course.fast.ai/
31)Give it time
可能你的网络需要更多的时间去训练才能产出有意义的预测。如果loss在稳定的下降,请给网络更多的时间训练再做决定。
32)从训练模式转换为测试模式
Batch Norm,Dropout等层在测试和训练时操作不同,注意在网络设置时这些层参数是否根据训练和测试的不同有所改变。如tensorflow中tf.contrib.layers中的batch norm需要手动传入是否在训练的参数。
33)训练可视化
利用tensorboard和crayon等工具对weights/bias/activations等进行可视化,确保他们的值正常。比如weights更新的强度应该在大约1e-3左右。参考https://deeplearning4j.org/visualization#usingui
34)尝试不同的优化器
即使不同的优化器也不应该使网络不work除非选用了特别差的参数。即使如此,不同的优化器也会带来不同的效果,选择合适的优化器不仅能带来好的输出,还能节约大量时间。在不清楚用何种优化器时推荐使用Adam或SGD with momentum。
参考Sebastian的文章
http://ruder.io/optimizing-gradient-descent/
35)梯度消失/爆炸
检查梯度是否出现了很大或很小的情况。检查layer的激活值,Deeplearning4j上有一个很好的指导:a good standard deviation for the activations is on the order of 0.5 to 2.0. Significantly outside of this range may indicate vanishing or exploding activations
36)增加/减少学习率
小的学习率会让网络收敛很慢。大的学习率可能会在训练末尾难以找到一个好的解。在你当前的学习率进行10/0.1倍调整。
37)克服NaNs
出现Nan是训练网络尤其是RNN时一个非常大的问题。一些可能的帮助手段如下:
◆减小学习率,尤其是在前100 iteration就出现Nan
◆Nan可能发生在除0或者log0的情况下,检查是否有这些问题
◆检查网络每一层,看Nan在哪里先出现的
5.总结
现有的经验总结大抵如此,调试网络时候经常像是在搞玄学,但这些经验也能给一些指导,希望对你的工作有所帮助。

更多精彩内容,欢迎关注
中科院自动化所官方网站:
http://www.ia.ac.cn
欢迎后台留言、推荐您感兴趣的话题、内容或资讯,小编恭候您的意见和建议!如需转载或投稿,请后台私信。
整理:张志鹏
编辑:鲁宁、欧梨成
中科院自动化研究所
微信:casia1956
欢迎搭乘自动化所AI旗舰号!
http://weixin.100md.com
返回 中国科学院自动化研究所 返回首页 返回百拇医药