科学编程中的可重复性

18

除了产生错误结果外,科学编程中最糟糕的恐惧之一是无法重现所生成的结果。哪些最佳实践有助于确保您的分析是可重复的?


徒劳无功...大多数人被随机性愚弄了。此外,三分之二的人在不知道其含义的情况下使用“科学”一词。同样,两个博士中就有一个犯有相同的错误。聚合愚蠢= 1/0。 - Hamish Grubijan
1
@Hamish:未捕获的DivideByZeroException异常。另外,这并不是无药可救的情况。 - ine
@amdfan:Hamish可能是在提到这句话:“只有两件事是无限的:宇宙和人类的愚蠢……” - Andrew Grimm
2
@Hamish ...而且四个统计数字中有三个是虚构的 :-) - Stephen C
2
我目前在这个页面上只看到了一次“原始数据”的提及。一个非常常见的错误是不记录原始数据并无限期地保存它。在保存数据之前进行少量处理非常诱人,但不要这样做。这样做可以节省大量重复实验和重新采集数据的时间。 - Davorak
8个回答

13
  • 将原始数据在线发布并免费提供下载。
  • 使代码库开源并可在网上下载。
  • 如果在优化中使用随机化,则应多次重复优化,选择产生最佳值的结果或使用固定的随机种子,以便重复相同的结果。
  • 在执行分析之前,您应将数据拆分为“训练/分析”数据集和“测试/验证”数据集。对“训练”数据集进行分析,并确保获得的结果仍然适用于“验证”数据集,以确保您的分析实际上是具有普遍性的,而不仅仅是记忆特定数据集的细节。

前两点非常重要,因为使数据集可用允许其他人对相同的数据执行自己的分析,从而提高对自己分析的有效性的信心水平。此外,将数据集在线提供--尤其是如果使用链接数据格式--使网络爬虫能够将您的数据集与其他数据集聚合在一起,从而使大型数据集的分析成为可能 ... 在许多类型的研究中,样本大小有时太小,无法对结果产生真正的信心...但共享您的数据集可以构建非常大的数据集。或者,有人可以使用您的数据集来验证他们对其他数据集执行的分析。

此外,使您的代码开源使同行可以审查代码和过程。通常这种审查会发现缺陷或其他优化和改进的可能性。最重要的是,它允许其他研究人员在不必从头开始实施您已经完成的所有工作的情况下改进您的方法。当研究人员可以专注于改进而不是重新发明轮子时,研究的速度大大加快。

关于随机化...许多算法依赖于随机化来实现它们的结果。随机和蒙特卡罗方法非常常见,尽管已经证明在某些情况下会收敛,但仍有可能得到不同的结果。确保获得相同的结果的方法是,在您的代码中循环调用计算一定次数,并选择最佳结果。如果使用足够的重复次数,您可以期望找到全局或接近全局最优解,而不是陷入局部最优解。另一个可能性是使用预定的种子,尽管这不是我认为最好的方法,因为您可能会选择导致您陷入局部最优解的种子。此外,没有保证不同平台上的随机数生成器将针对该种子值生成相同的结果。


1
我真的希望所有的研究人员都能分享您的理念。 - Anycorn
1
随机化 - 您应该为种子设置一个标志,以便您可以选择是否要复制相同的结果。 - wisty
@wisty:标志位是否也应该被存储? - Andrew Grimm
当然,你可以在代码中设置一个默认标志,只使用其他标志进行探索/测试。这取决于你想要多么严格。请注意,在Python中,numpy.random和random都需要单独的标志。 - wisty

10

我是一名软件工程师,嵌入在一个地球物理研究团队中,我们一直在努力提高在需求时重现结果的能力。以下是我们从经验中获得的一些要点:

  1. 将所有内容放在版本控制下:源代码、输入数据集、makefiles等
  2. 在构建可执行文件时:我们将编译器指令嵌入到可执行文件本身中,使用UUID标记构建日志并使用相同的UUID标记可执行文件,为可执行文件计算校验和,自动构建所有内容并自动更新数据库(实际上只是一个平面文件)以记录构建详细信息,等等。
  3. 我们使用Subversion的关键字在每个源代码中包含修订号(等),这些被写入生成的任何输出文件中。
  4. 我们进行大量(半)自动化的回归测试,以确保新版本的代码或新的构建变体会产生相同的(或足够相似的)结果,并且我正在开发一堆程序来量化发生的变化。
  5. 我的地球物理学同事们分析了程序对输入变化的敏感性,而我则分析它们(程序,而不是地质探测)对编译器设置、平台等的敏感性。

我们目前正在开发一个工作流系统,将记录每个作业运行的细节:使用的输入数据集(包括版本)、输出数据集、程序(包括版本和变体)、参数等,也就是所谓的溯源。一旦这个系统投入使用,唯一发布结果的方式就是使用工作流系统。任何输出数据集都将包含其自身的溯源详情,但我们还没有对此进行详细设计。

我们对于重现数字结果的最低有效数字相当宽松(也许有点太宽松了)。我们工作的基础科学以及基本数据集测量误差不支持超过2或3个有效数字的任何数字结果的有效性。

我们肯定不会为同行评审发布代码或数据,我们在石油业务中。


9

已经有很多好的建议了。我会加上一些(都是从痛苦的经验中得出的——在发布之前,谢天谢地!)

1)检查结果是否稳定:

  • 尝试几种不同的数据子集
  • 重新对输入进行分组
  • 重新对输出进行分组
  • 调整网格间距
  • 尝试几个随机种子(如果适用)

如果不稳定,那么工作还没有结束。

发表上述测试的结果(或者至少保留证据并提到你已经进行过测试)。

2)抽查中间结果

是的,你可能会在小样本中开发方法,然后处理整个混乱的数据。在这个过程中也要时不时地查看中间结果。更好的方法是,在可能的情况下收集中间步骤的统计数据,并寻找其中的异常迹象。

同样,如果有任何意外,你就必须回头重新做。

再次,保留和/或发表这些信息。


已经提到过的一些我喜欢的东西包括

  • 源代码控制——你自己需要它。
  • 记录构建环境。发布它也很好。
  • 计划公开代码和数据。

还有一个没有人提到的:

3)文档化代码

是的,你正在忙于编写代码,可能在进行设计。但我的意思并不是详细的文档,而是对所有意外情况的解释。你无论如何都需要把这些东西写下来,所以认为这是在论文上先行一步。你可以将文档保存在源代码控制中,以便随时丢弃不再适用的部分,如果需要,可以重新获取。

建立一个小小的README文件,包含构建说明和“如何运行”的简介,这样也不会有坏处。如果你要公开代码,人们会问这些问题...另外,对我来说,回头查看这些信息有助于我保持在正确的轨道上。


你能详细解释一下“所有的惊喜”吗?你是指程序需要以与最初预期不同的方式执行操作,以及为什么它必须执行这些操作吗?另外,为自己编写README文件确实很有用! - Andrew Grimm
1
惊喜意味着:1)任何与您的学科通常做法相反的事情;2)任何您不得不重新实现的东西,因为“显而易见”的方法由于某些根本(而非语言相关)原因无法工作;3)在设置和运行代码时出现的任何“陷阱”;以及4)关于分析的任何其他内容,将必须在最终论文中解释。 - dmckee --- ex-moderator kitten

7

发布程序代码,使其可以被审查。

这并不是针对你的意思,但这是我的抱怨:

如果你从事由纳税人资助的工作,如果你在同行评议的期刊上发表结果,提供源代码,采用开放源代码许可证或公共领域。我已经厌倦了读到关于某个人想出的伟大算法的文章,他们声称该算法能做到x,但没有提供验证/检查源代码的方法。如果我看不到代码,我就无法验证你的结果,因为算法实现可能存在非常大的差异。

在我看来,将由纳税人支付的工作置于同行研究人员之外是不道德的。在推动论文的同时,却没有为公众提供可用工作方面的实际利益,这是违背科学精神的。


6
我认为之前的回答都遗漏了你问题中关于"科学计算"的部分,而是回答了适用于任何科学研究的非常通用的东西(公开数据和方法,专业化到计算机科学)。他们遗漏的是,你需要更加专业化:必须具体说明使用的编译器版本、编译时使用的开关、操作系统版本、所有链接的库的版本、硬件配置、同时在您的机器上运行的其他内容等等。有发表的论文中其中每一个因素对结果产生了非微不足道的影响。
例如(在英特尔硬件上),您可能正在使用使用FPU的80位浮点数的库,进行操作系统升级,现在该库可能仅使用64位双精度浮点数,并且如果问题稍微存在问题,结果可能会发生 drastical 改变。
编译器升级可能会改变默认的舍入行为,或者单个优化可能会翻转2个指令执行的顺序,再次对于不正常的系统,结果不同。
嘿,有些奇怪的故事显示次优算法在实际测试中表现最佳,因为它们在笔记本电脑上测试时自动减速了CPU(这是最优算法所做的)。
这些事情都无法从源代码或数据中看到。

只有在源代码/数据可用的情况下,才能验证/检查此类事情。 - Anycorn
好观点,但+1尤其是关于“最优”算法如何使CPU过热并运行更慢。 - DarenW

2

将代码、数据和结果发布在互联网上,在论文中写下URL。

此外,可以将您的代码提交到“竞赛”中。例如,在音乐信息检索领域,有MIREX


1

以某种方式记录配置参数(例如,如果您可以将某个变量设置为某个值)。这可以在数据输出中或版本控制中完成。

如果您经常更改程序(我是!),请确保记录您正在使用的程序版本。


0
也许这有点偏题,但是为了跟随@Jacques Carette关于科学计算的具体问题,查阅验证和验证("V&V")文献对于一些特定问题可能会有所帮助,尤其是那些模糊可重现性和正确性之间界限的问题。现在云计算正在成为大型仿真问题的选择,随机CPU的可重现性将更加引人注目。此外,我不知道是否可能完全将您的结果的“正确性”与“可重现性”分开,因为您的结果源自您的计算模型。即使您的模型在计算集群A上运行良好,但在集群B上却无法运行,您仍需要遵循一些指南来确保制作此模型的工作流程是合理的。针对可重现性,V&V社区中有一些关于将可重现性误差纳入整体模型不确定性的讨论(我会让读者自行调查)。
例如,对于计算流体力学(CFD)工作,黄金标准是ASME V&V指南。特别是对于应用多物理建模和仿真人员(其一般概念适用于更广泛的科学计算社区),这是一个重要的标准需要内化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接