AI中国网 https://www.cnaiplus.com
「敢不敢把你十年前写的代码翻出来看看还能不能运行?」在最近的一篇社论文章中,《Nature》介绍了两位法国科学家发起的一项挑战。这项挑战名为「Ten Years Reproducibility Challenge」,由法国国家数字科学技术研究所的计算机神经科学家 Nicolas Rougier 与法国国家科学研究中心的理论生物物理学家 Konrad Hinsen 共同发起,旨在鼓励各个领域的研究者翻出自己十年前(或更早)的代码,看看这些代码到底还能不能运行,研究能否复现。Rougier 认为,尽管计算在科学研究中占有越来越重要的比重,但研究者很少披露自己的底层代码。即使他们给出了代码,别人也很难去执行,就连作者本人有时也会遇到麻烦。而且,随着编程语言、计算环境的演化,现在还能运行的代码过段时间可能就不行了。因此,「『十年代码复现挑战』的宗旨是找出那些十年之后仍然能够 work 的代码编写和发布技术,」Hinsen 表示。这项比赛共吸引了 35 名参赛者。他们提出要复现 43 篇论文,其中 28 篇形成了可复现报告。这些论文涉及的语言包括 C、R、Mathematica 和 Pascal 等等,还有一位参赛者复现的不是代码,而是一个用 SBML(系统生物学标记语言)编写的分子模型。当然,这条复现之路并没有想象中那么简单,有人代码找不到了,有人找到代码也不知道怎么运行。最后,他们通过这项比赛总结出了一些提高代码可复现性的技巧,可以为现在的工作提供借鉴。要完成这个挑战,首先你得找到自己当年的代码,有人在这一步就被卡住了。Roberto DiCosmo 是法国国家信息与自动化研究所的一位计算机科学家,他在 1998 年的一篇论文中提到了一个名为「OcamlP3l」的并行编程系统。但在找遍自己和合著者的硬盘、备份之后,他也没能找到 OcamlP3l 系统的代码。不过幸运的是,一个名为「Software Heritage」的源代码归档网站为他提供了一份备份。
Software Heritage 会定期抓取 GitHub 等开源代码网站,有点像定期抓取网页的互联网档案馆(Internet Archive)。开发者也可以请求 Software Heritage 抓取自己的库留作存档。起初,DiCosmo 并没有考虑去 Software Heritage 找自己的代码,因为在他开发 OcamlP3l 的时候,Software Heritage 还没出现。他猜测,一定是有人将他的代码传到了 Gitorious 托管平台,而 Software Heritage 又在该平台关停之前抓取了上述代码。当然,找到代码并不代表你还会用。威斯康星大学生物统计学家 Broman 表示,他想复现 2003 年的一份研究,但是由于文档遗失、文件组织形式古怪,他已经不知道要运行哪些代码才能复现研究,所以不得不回去阅读原文。「在一个组织良好的项目里,文档的行数超过代码行数不是什么稀罕事儿,」加州大学伯克利分校的一位计算可复现性倡导者表示,「你要保留尽可能多的信息,对分析的结构有更广泛的描述,比如数据从哪儿来,数据、代码的一些元信息等,这些是复现的关键。」Melanie Stefan 是爱丁堡大学的一位神经科学家,她想复现一个用 SBML 写的计算模型。尽管模型都在,但她却找不到自己当年用的参数值(如分子浓度),也没有很好地记录数据标准化的关键细节。因此,Stefen 无法复现她的部分研究。「即使对于同一个人来说,很多十几年前再明显不过的模型细节现在也不明显了,真是令人始料未及!」她面无表情地说道。作为比赛的组织者,Rougier 也参加了这次挑战。他重现的代码是 Apple II 中的一个图像放大器,这是整个挑战赛中最古老的代码。这段代码写于 32 年前,当时写的时候 Rougier 才 16 岁,还发表在了一本名为《Tremplin Micro》的杂志上(已倒闭)。如今,即使拿着神秘的 AppleSoft BASIC 语言说明,他也不记得代码是怎么运行的了。「真是见了鬼了,这可是我自己写的,」Rougier 惆怅地说道。但是,他可以在网上找到这段代码并使其在一个网页版 Apple II 模拟器上运行。要做到这点并不难,Rougier 表示,最难的部分是让它在一个真正的 Apple II 上运行。
对于 Rougier 来说,硬件不是问题,因为他办公室就有一台 Apple II,是一位同事在清理办公室时抢救出来的。但由于这款 Apple II 的年龄比 USB 线和互联网都大,而且当前的计算机无法与它的老式磁盘驱动相连。因此,在运行代码之前,Rougier 需要某种定制的硬件以及一盒老式磁盘。他在亚马逊上找到了一些带有「New」字样的磁盘,但日期是 1993 年的。在对他的数据进行三次写入以确保比特稳定之后,磁盘开始运行了。活动的发起者 Hinsen 也遇到了硬件方面的麻烦。他把自己 90 年代写的代码有条不紊地存到了磁带里,但现在,他已经没有能读取磁带的工具了。过时的计算环境也是压死参赛者的一根稻草。Sabino Maggi 是意大利的一名计算机物理学家,1996 年,他用 Fortran 语言建模了一个超导装置,并用 Microsoft Visual Basic 来处理结果。二十多年过去了,Fortran 并没有发生太大变化,因此 Maggi 只做了些微的调整就实现了代码的顺利编译。但始料未及的是,Visual Basic 给他出了一个难题。Maggi 在报告中写道,「Visual Basic 是一门死掉的语言,早就被 Visual Basic.NET 取代了。」所以,为了运行二十多年前的 Visual Basic 代码,Maggi 不得不使用从网上找到的安装盘在自己的 Mac 电脑上重建了一个十年前的 Windows 虚拟机。在安装之前,Maggi 遇到了一个问题:他根本不记得自己 96 年用的是哪个版本。这些年,微软发布了该语言的多个版本,而且并不总是向后兼容的。
模拟 1994 年的 Windows 计算机运行 Microsoft Visual Basic 的 Mac。同样受到计算环境问题困扰的还有 Ludovic Courtès,他是法国国家信息与自动化研究所的一名研究工程师。在这次挑战赛中,他复现了 2006 年一篇比较数据压缩策略的论文,代码是用 C 语言写的。由于 API 发生了变化,他的代码无法用现有软件库进行编译。为了解决这一问题,他不得不将 6 个计算组件回滚到很老的版本。如今,研究者们可以用 Docker 和 Conda 虚拟环境来打包计算环境,以备不时之需。但有几位参赛者选择了其他方法,比如 Guix(一个 Linux 包管理器)。它可以保证环境直到最后一位都是可复现的,并且构建环境的代码版本是透明的。「环境和整篇论文都可以检查,可以从源代码构建,」Courtès 表示。Hinsen 认为,Guix 可能是这个比赛「目前最好的可复现研究工具」。违反直觉的是,很多参赛者发现,用一些比较古老的语言写的代码反而是最容易复现的。新语言快速变化的 API 和对第三方库的依赖使得它们很难复现。从这个意义上来说,今年刚刚停止支持的 Python 2.7 倒是一个不错的机会,它既是一门高级编程语言,又不会再进行更新。在经历了复现代码的艰辛之后,相信每位参赛者都意识到了自己当年写代码时埋下的一些「隐患」,比如存储介质、所选语言、备份平台等。那么,如何提高论文代码的可复现性呢?《Nature》文章的作者在文中给出了一个 checklist:1. 代码。基于即点即击(point-and-click)界面的工作流(如 Excel)是不可复现的。你要将计算和数据操作保存在代码中;2. 文件。使用注释、计算笔记本、README 文件等解释你的代码如何运行,定义期望的参数和所需的计算环境;3. 记录。记下关键参数,如用于启动随机数生成器的「seed」值。这样的记录可以帮你重新运行代码、跟踪 bug 以及意外的结果;4. 测试。创建一套测试函数。使用 positive 和 negative 控制数据集来确保你得到预期的结果,并在开发过程中运行这些测试,在 bug 出现时及时清除;5. 保存。GitHub 是一个流行但并不永久的在线存储库。长期来看,Zenodo、Figshare 和 Software Heritage 等归档服务可能更加稳定;6. 跟踪。使用 Git 等版本控制工具来记录你的项目历史,记下产生每个结果所用到的版本;7. 打包。利用容器化工具(Docker、Singularity 等)、网页服务(Code Ocean、Gigantum、Binder)、虚拟环境管理器(Conda)等创建随时可用的计算环境;8. 自动化。使用 Travis CI 等持续集成服务在不同的计算环境中定期自动测试你的代码;9. 简化。避免使用会使后续利用复杂化的小众或难以安装的第三方代码库;10. 检查。通过在一系列计算环境中运行代码来检查代码的可移植性。此外,曼彻斯特大学的计算机科学家 Carole Goble 指出,将自己的代码开源也是一种提高可复现性的方式,这样别人就有机会在你的代码基础上进行修改,以保持其活力。如果你也有十几、二十几年前写的代码,可以拿出来试试还能不能运行。参考链接:https://www.nature.com/articles/d41586-020-02462-7AI中国网 https://www.cnaiplus.com
本文网址: