
注:这篇文章自从发布出来,就受到读者的好评和关注, 因此 ,我编写了一个机器学习测试库 ,请点击链接查看!
在过去的一年里,我花了很多时间来研究深度学习,并且也犯过很多错误,这些错误不仅帮助我对机器学习有了更加深入的理解,也让我学会了如何正确合理的设计这些系统。在Google Brain 工作期间,我学到了很多设计原则,其中之一就是单元测试可以制定或 打破 原有的算法,并且能够节省数周的调试和训练时间。
然而,到目前为止,似乎还没有为神经网络代码编码测试单元的比较可靠的教程。即使是在OpenAI 上,也只是通过一行行的盯着代码来发现bug,然后再思考导致这一bug的原因到底是什么 。显然,大部分人都不愿意这么耗费时间,因此,我希望看完这个教程,你就可以开始着手测试你的系统!
我们从一个简单的例子开始:试试在这段代码中找到bug 。
有找到bug 吗 ?实际上,这个神经网络并没有进行堆叠。我在编写代码的时候,只是对slim.conv2d ( ... )代码行做了简单的复制粘贴,然后对内核大小进行修改, 而并 没有实际的输入。
略微尴的来说,这其实是我上周编写的代码…… 这 也 是个很重要的教训!但是由于某些原因,这些bug 很难被发现:
1. 这段代码永远不会崩溃,或者引发错误,又或者是运行速度变慢。
2. 这个神经网络仍在训练,并且损失函数会越来越小。
3. 几个小时后,会收敛到某一数值,结果非常糟糕,但是,你又不知道应该修改哪里。
当唯一的反馈只有最终那个错误验证时,那么,你只有一个办法—— 就是搜索整个网络架构。不用再多说了,你需要的是一个更好的网络系统。
在我们 对数据 进行了一整天的训练以后,该如何发现这一bug 呢? 我们发现,最容易注意到的是,层的值实际上从未到达函数外的任何其他张量。因此,假设我们有某种类型的损失函数和优化器,这些张量永远都不会得到优化,它们将始终保持为默认值。
通过简单的训练,我们来比较训练之前和训练之后的结果:
在这不到15 行的代码中,我们基本上验证了训练过的所有的变量。
这个测试非常简单、实用。现在,假设我们已经修复了上一个问题,现在,添加一些批量优化,看看是否能发现这一bug 。
看到了没?这个非常微妙。在tensorflow 中, batch_norm 实际上将 is_training 默认为 False ,所以添加这行代码并不能在训练期间将输入规范化!值得庆幸的是,我们编写的最后一个单元测试将会立刻找到这个问题!
我们来 看 看另外一个例子,来自于reddit的一个帖子 :该作者想创建一个分组器,其输出范围为(0,1 ), 你是否能够 找出其中的bug ?
这个bug 很难发现,并且稍不注意就会导致特别混乱的结果。基本上,这个预测只有一个输出,当你使用softmax交叉熵 时,总会导致损失函数为0 。
测试这段代码最简单的方法就是—— 确保损失函数永远不为 0 。
这个测试类似于我们的第一个测试,唯一不同的就是回退。在这个测试中,你可以确保只训练你想要训练的变量。拿生成对抗网络来(GAN )说,常常出现的 bug 就是忘记在优化期间训练了哪些变量,类似这种的 bug 经常会发生。
这其中最大的问题就是:优化器有一个默认设置来优化所有的变量。对于类似于对抗生成网络的架构来说,这是对所有训练时间判了一个死刑。在这里,使用下面的测试代码,你就可以轻松检测到这些bug :
同样,我们也可以为鉴别器或其它强化学习算法编写类似的测试代码。很多演员-评论模型都有自己相对独立的网络,需要通过不同的损失进行优化。
为了你在阅读完本文后,能够更好的进行测试,我认为以下几个建议很重要:
1. 保证测试的确定性。如果你真的想要随机输入数据,那么,请确保输入的随机性,以便于轻松的完成测试。
2. 保证测试的简短性。一定要有能够训练收敛并检查验证集的单元测试,否则你就是在浪费时间。
3. 确保在每次测试前重置图表。
总之,还会有很多测试方法 可以 测试这些算法。花一个小时的时间来编写一个测试代码,不仅可以帮你节省重新训练的时间,还能够大大改善你的研究成果!
以上为译文。
本文由北邮@爱可可-爱生活 老师推荐, 阿里云云栖社区 组织翻译。
文章原标题《How to unit test machine learning code 》,译者: Mags,审校:袁虎。
文章为简译,更为详细的内容,请查看原文。