Loss一直不下降,要回到原理上先确定一件事:如果样本只有一个,没有任何随机性(如随机数据增强),是否“一定没问题”。
- 只要理论上没问题,就不要怀疑网络不给力,一定是流程中有问题
- debug像塞车,只要按部就班向前推进,一旦走起来了就比走路快多了。左右乱搞就像左右变道,最终不但危险而且还慢,不可能瞎猫碰见死耗子的。所以不要急功近利左右乱搞,甚至放弃开车下车走路。
- 如果开始乱搞了,就是累了,休息,最好是睡个觉再弄,不要着急,一旦车开起来,就快多了
- 如果没法debug,一定是系统或者数据太复杂了,尽可能地简化他们直到一眼能看出来
debug分成两个阶段:
流程代码debug
1. 退化
一步到位回退到数据的最简化情况,仅保留所有流程,即:
- 单个样本:把系统用单个样本训练,单个样本测试
- 去随机:去除任何随机性,包括加噪,数据增强,对于无法去掉的随机部分,固定随机数种子
- 简化神经网络结构到仅剩极简
2. 定位
二分法打印系统各个关键流程的输出,获得模型每个阶段的输出进行比较,打印结果,回溯到最根源的出问题的步骤。
我们上一步没有简化系统流程,但如果这一步的输出仍有问题,就开始简化系统流程,检查输出,直到不能再精简为止
3. 推进
一个步骤被改正后,先不要急着改下一个步骤,做三件事:
- 多次运行,确定此修改是稳定的
- 添加数据样本量从1到2到10,确定数据量上来后仍然稳定
- [可选]如果加噪后的结果可以肉眼观察,添加数据噪声,确定稳定
4. 迭代
流程调好后,回归到1中的最简化的数据情况,逐步打开下一个流程并检查输出
5. 复原
整个系统各个部分输入输出没问题后,回归到1中的最简化的数据情况,用单个样本确定模型能够收敛,随后增加样本量,增加噪声
X. “关键开关”
以上调试的关键,就是要找到“关键开关”的那行代码,只要改变这行代码,就能使得系统在“正常”和“异常”之间切换,随后集中精力攻破这个开关即可
网络部分debug
- 用一个样本作为训练集,同样一个样本作为测试集运行:
- 检查输入输出是否符合预期
- 检查单样本是否收敛
- 检查网络是否有在训练,同时,查看网络的梯度是否存在,通过tensorboard打印各层的分布来观察
- 检查数值稳定问题,比如除以0,log(0)等
- 如果网络会出现NaN或者inf,使用tfdbg进行debug。
- 其实NaN是会被传染的,因为任何一个数值跟NaN做加减乘除都得NaN,所以当一个网络出现一个NaN,很快就会使得一切参数和输出都变NaN。所以如果出现了NaN,就一定是实现上有问题,一定要找到原因,不可以想着规避,哪怕规避了你得到的结果(如准确率)也很有可能是错的。
- 首先把输入数据的NaN排除一下:
data[np.isnan(data)] = 0.0
-
- 然后检查上面所说的数字稳定问题
附:常见工具
- Spyder,运行一次就可以检查所有numpy变量的状态,新版本将支持在变量查看器中查看Pytorch的Tensor
- tfdbg,对于网络中随机出现NaN值的情况,可以自动检测
- tensorboard,采用tf.summary.histogram,用于查看网络任意层的输出分布是否有在变化,用于确定是否在训练,[例子点这里](TensorFlow学习--tf.summary.histogram与直方图仪表板/tensorboard_histograms - akadiao的博客 - CSDN博客)
- print,这个世界上最好用的调试工具,没有Log,就不可能调试
- 冷静的你,这个世界上最好的调试者,按部就班,不要着急,累了便休息。