如何复现代码
每个研究生都会在一定阶段时,听到导师说:你去复现一下代码吧。我的学生经常会告诉我:老师,我这一周都在等这个代码出结果。我相信这一类学生是有水平的,能够快速熟悉服务器环境,把程序跑起来。但这一类学生肯定是偷懒的,因为他们都不知道为什么要复现代码,就把东西往那里一放,等待时间的慢慢流逝。
也有一部分学生主动问到:我们复现代码,到底怎么算成功呢?照GITHUB跑起来就可以了吗?为了这一部分学生,在此列一下我对于论文代码的一些看法。因为本人是做人工智能领域,所以代码理念基于机器学习。
====== 为什么要复现代码 ====== 首先来尝试解答一下,我们为什么要复现论文代码。就我个人而言,复现代码的目的有二:
-
通过代码反向印证论文中的实施细节。好的论文会介绍全部的训练、测试流程,也会通过公式来确保读者能够准确理解细节。但是,论文里有些操作是有技巧的,并非所有人都能够直接的手撸代码。通过运行代码,能够逐行理解模型的所有实现,学习新的解决问题的角度。当然,如果一篇论文我看完之后就知道如何实现的话,这个目的就不存在了。
-
复现一篇论文的代码,可以帮助我定位任务的baseline。在确定有效的方法基础上做改进,更容易获得有着更好效果的模型。如果自己能够好好处理代码的话,还能够收获一套非常棒的算法实现框架。因为有了参考,能够大幅度降低后期的调试难度。
除了上述目标,刚入门科研的同学们能够通过复现代码,真正的理解什么叫做机器学习。在实际使用数据进行训练和测试的过程中,快速熟悉机器学习中的全部概念,包含但不限于:搭建环境、训练、验证、测试、推理、调参、batch、epoch、过拟合、欠拟合等等。熟悉Linux指令集或许也在其中?好多东西嘛,用用就会了。
====== 如何复现代码 ====== 接下来说一说如何复现代码。此处的复现代码并不是说从头实现,而是熟悉理解开源代码。当年自己使用cudnn复现Alexnet时,踩了不知道多少坑。一篇论文真的不是说的那么简单,里面的所有机制都是精心设计过的,包含里面的dropout,relu,learning rate,优化器等,少了一个结果都会差很多,所以现在我们的工作真的都是站在巨人的肩膀上的,有了pytorch框架,有了adam, adagrad这些优化器。还有这么多的开源算法和教程,大幅度降低了入门代价。
-
复现代码第一步是先跑起来。跑起来可以理解为先load预训练的参数,然后给定一个输入,得到对应的测试结果,也就是输出。这个过程能够理解运行环境、理解任务、理解模型、数据、测试指标。
-
第二步是跑一个训练。并不是要训练模型得到论文中的结果,而是只要能够正常运行一个epoch,得到validation的结果即可。这个过程要理解数据组织、训练、梯度计算、参数更新、还有参数保存、训练状态展示等内容。如果模型真的训练得慢,直接假定训练样本只有一个batch就可以了。
-
第三步是尝试对代码做修改和理解。包含几个方面:数据的处理、模型的实现细节、目标函数、测试函数。一切可能的细节。以假定自己需要实现这样的模型为目标,尽可能的去找到自己的不足,并学习代码中的实现方法。
====== 复现代码需要多长时间 ====== 这个因代码而异。我这里说几个特别的情况,供参考。
-
当年有一个算法刚出来的时候大火,也开源了代码。我在理解他们的代码的时候,学习了不少,了解到了有几个Loss的简化实现方案。但是对于他们说的效果,我试了大概15天,没能得到理想的结果。后来听说某原大大调了一个月。
-
近期准备拿一个算法做Baseline,学生跟我说他们跑Recall的方式好像跟我们理解的不太一样。正常情况下,是对每一个用户预测K个样本,计算recall;这篇文章的代码是对每一个样本预测了K个用户。然后这个试了几天的算法就被我们放弃掉了。
-
早期的推荐系统为每个用户随机1000个样本做测试,现在有论文论证这样不太科学。所以那些方法的测试代码全部要替换,重做baseline。