我最初接触机器学习时,花费了大量时间来阅读论文,并尝试实现。当然,我不是天才。实现它意味着要执行 git clone 并尝试运行论文作者的代码。对于我感兴趣的概念,我可能还手动输入一些代码并进行注释,以便更好地理解论文和项目。
这样的学习方法令人沮丧。尝试复现论文的流程大致如下:
- 一些达到新 SOTA 的论文在新闻媒体中引起关注;
- 读者深入研究或快速浏览论文内容;
- 读者对论文中的实验结果印象深刻,并产生复现的兴趣。
接下来就是疯狂搜索项目代码,并尝试在作者所用的数据集上运行代码。这时,你需要祈祷该项目具备以下要素:运行说明(README.md)、代码、参数、数据集、数据集路径、软件环境、所需依赖项以及硬件条件。了解这些,才能顺利复现论文中的 SOTA 结果。
而在这个过程中,你可能会遇到很多常见问题(参见下文)。遇到问题之前先了解它们是很有帮助的,毕竟,没人喜欢空手而归。
复现机器学习论文时的常见问题
复现过程中的常见问题如下所示:
- README 文件不完整或缺失;
- 未定义依赖项、代码存在 bug、缺少预训练模型;
- 未公开参数;
- 私有数据集或缺少预处理步骤;
- 对 GPU 资源的需求不切实际。
1. README 文件不完整或缺失
如果一篇论文在发表时开源了代码,那么 README 就是你着手开始复现项目的文档之一。好的 README 文件通常具备以下几个组成部分:依赖项列表、训练脚本、评估脚本、预训练模型以及运行脚本得到的结果。
实际上,这些内容已经在 Papers with Code 发布的《机器学习代码完整性自查清单》中列出(该清单已成为 NeurIPS 2020 代码提交流程的一部分)。该清单受到麦吉尔大学副教授、Facebook 蒙特利尔 FAIR 实验室负责人 Joelle Pineau 的启发。
Papers with Code 提供的 README 样例参见:
https://github.com/paperswithcode/releasing-research-code
不完整的 README 文件对运行代码而言是一个坏的开端。
一个需要注意的信号是示例 notebook 或示例代码。notebook 的用途是演示代码的使用。理想情况下,除了点击「Run all」以外,不需要任何其他调整就能够运行 notebook。预填充参数和数据路径的命令行也能够实现同样的效果。
还有一些次要但有用的信息,比如作者的联系方式或展示模型架构或数据转换流程的 gif 图片等,这些都是完备的 README 文件应该包含的。如果代码库托管在 GitHub 上,请检查 Issue 区域的问题是否得到了积极回复,以及 pull request 是否定期被查看。这些事项均能证明库得到精心维护,确保后续复现工作得到有效支持。当然会有例外,但请慎重考虑以上各项出现缺失的情况。
Joelle Pineau 发布的机器学习可复现性检查清单
(图源:https://www.cs.mcgill.ca/~jpineau/ReproducibilityChecklist.pdf)
2. 未定义依赖项、代码存在 bug、缺少预训练模型
当你对示例 notebook 觉得满意后,你或许想尝试用不同的参数在自己的数据集上试用模型。在这一阶段,你或许会调用示例 notebook 中未用到的函数,或者在自己的数据集上尝试预训练模型,这时可能会遇到问题。
例如,你可能注意到 requirements.txt 缺失,或者软件包版本未固定(如 tensorflow==2.2)想象一下当你发现 TensorFlow 版本是 1.15 而不是 2.2,原因只是作者没有指定版本时的爆炸心态吧。
假设你检查过了依赖项,然而现在却发现预训练模型失踪了!这种情况下,你要么 debug 代码,要么提交 bug 报告,要么忽略代码。请谨慎选择第一个选项,因为你可能会在这上面花费好几个小时。当然有的 bug 很容易解决,如果我能修复的话,我会提交 pull request。但并不是每次都那么好运,这些随手可及的果子有时候很难摘。
预训练模型缺失是一个危险信号,但这其实并不罕见。毕竟,论文作者没有义务发布模型。那么,另一个替代方法是使用公开的参数训练模型进行复现。不过参数也不总是公开……
3. 未公开参数
根据模型情况来看,超参数对于实现 SOTA 结果是非常重要的。下图展示了不同参数产生不同的 f1 分数(范围从 0.5 到 1.0)。模型中的参数通常是学习率(learning rate)、嵌入尺寸(embedding size)、层数、dropout 量、批处理大小、训练 epoch 数量等。
因此,如果作者没有提供他们使用的确切参数,你可能必须自己进行所有实验才能复现 SOTA 结果。
顺便说一句,Facebook 的 HiPlot 是一个很好的工具,帮助你在使用不同参数组合时将模型结果可视化。
HiPlot 地址:https://github.com/facebookresearch/hiplot
4. 私有数据集或缺少预处理步骤
从很多方面来说,我们很幸运地拥有世界各地研究者提供的开源数据集。事实就是如此,数据的收集绝非易事,而清理这些数据并将其格式化以供研究使用,就更加麻烦一些。在此需感谢学术机构和 Kaggle 免费托管这些开源数据集,因为带宽和存储成本是很高的。
然而想使用私有数据集,并非易事。数据集可能包含受版权保护的信息,比如 ImageNet。通常你需要填写一份申请表,版权所有者将自行决定是否批准。
某些时候这个过程会很麻烦,如果你所需的数据集不可用,在申请行动之前要先认真考虑一下。或者你可以从其他渠道搜索或者下载数据,比如 Academic Torrents:
https://academictorrents.com/。
5. 对 GPU 资源的需求不切实际
近期出现了一股趋势:模型越大性能越好。一些论文使用了整个数据中心的算力才达到 SOTA 结果,这些论文复现起来当然很难。例如,2019 年 10 月谷歌发表论文《Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer》,尝试通过将参数扩展到 110 亿来探索 Transformer 模型架构的局限性。然而几个月后微软用 170 亿参数创建了 Turning-NLG,不久 OpenAI 放出 1750 亿参数的预训练语言模型 GPT-3……
要想训练数十亿参数的模型,你需要使用分布式训练方法以及某种形式的高性能计算(HPC)或 GPU 集群。具备 110 亿和 170 亿参数的模型分别需要约 44GB 和 68GB 的内存,因此这些模型无法仅使用一块 GPU 完成训练。
简而言之,尽早发现论文所用大模型是否超出你的个人能力。
微软训练 Turning-NLG。
总结
复现论文代码并非易事,不过越来越多的项目尝试标准化 SOTA 模型。我个人最喜欢的是 HuggingFace 的 Transformers,它为研究者和开发者提供了足够低的进入门槛。另外,TensorFlow 的 Model Garden 和 PyTorch 的 Model Zoo 也发展迅速(其中分别是 TensorFlow 和 PyTorch 团队构建的预训练模型)。
这些库旨在标准化预训练模型的使用,并为模型贡献和分发提供合适的条件。它们对代码质量提供了保障,并且具备不错的文档。我希望社区能从这些库中获益,并帮助复现 SOTA 结果,轻松地使用 SOTA 模型。
【本文是51CTO专栏机构“机器之心”的原创译文,微信公众号“机器之心( id: almosthuman2014)”】