云梯加速

云梯加速跨境连接资料站

同一份数据重新运行,结果为什么仍可能不同:版本、参数、随机性与复算记录

同一数据重跑出现差异,不等于数据造假,也不一定只是软件故障。版本、依赖、默认参数、随机状态、并行顺序和数值环境都可能进入结果。本文用NIST术语与Software Heritage的版本识别方法建立可复算记录。

研究者半年后重新打开分析项目,把“同一份数据”放进“同一款软件”,得到的显著位点和排序却与报告略有不同。若手边只剩最终表格,差异很难定位。问题可能发生在读取文件之前,也可能出现在预处理、默认参数、随机状态、依赖库或并行计算之中。

重跑不一致不等于数据造假,也不必然说明软件失效。首先要定义哪些条件真的相同,哪些已经改变,再判断差异属于错误、预期波动还是不影响结论的数值尾差。

“同一份数据”要先变成可核对对象

文件名相同,不表示字节相同。下载来源可能更新内容,解压工具可能改变换行,表格软件可能重写日期或编码。重跑前应为原始文件计算校验值,并保存大小、取得时间和来源。

实际进入程序的往往不是原始文件。研究者会筛掉缺失值、合并样本、转换单位、调整标签或重新排序。每一步都会形成新的数据对象,也应计算校验值并记录转换规则。

若只保存处理后的表格,仍要说明它从哪些原始对象产生。若只保存原始数据,却没有预处理脚本,后人也无法知道哪一列被排除。输入证据链必须把两端连接起来。

压缩包内部文件的顺序、字符编码、地区设置和缺失值符号都可能影响读取。一个系统把NA识别为缺失,另一个系统可能把它当普通字符串。程序在第一步得到不同矩阵,后续结果自然不同。

因此,“同一数据”应写成具体校验值,而不是文件名。校验值支持字节身份,却不证明数据收集正确。两个分析都可以使用同一份错误输入,并得到完全一致的错误结果。

重复性和复现性回答不同问题

NIST把重复性定义为同一被测对象在相同测量条件下连续结果的一致程度。列出的条件包括相同程序、观察者、仪器、地点和较短时间间隔。映射到计算分析,就是相同输入、代码、依赖、参数、环境和运行条件。

复现性则关注改变条件后的结果一致程度。NIST强调,有效的复现性陈述必须说明哪些条件改变,例如方法、仪器、地点、使用条件或时间。换电脑、换操作系统、换软件版本,都不是一句“重跑”可以省略的细节。

这一区分决定比较标准。相同容器、相同种子、相同线程数的重复运行,可以要求更严格的一致;不同硬件或不同实现的复现,可能用预先定义的数值容差和结论一致性判断。

“结果一样”也要说明一样到什么程度。字节一致、所有数值一致、误差范围内一致、排序一致和科学结论一致,是五种强度。报告若没有预先选择标准,就容易在看到结果后移动门槛。

软件名称和版本号仍不足够

写下程序名称是起点,不是完整版本证据。同一个版本号可能在不同平台产生不同构建,也可能由发行方重新打包。开发分支上的代码更会随着提交变化。

Software Heritage的研究强调,标识软件对象应能够指向具体源代码版本,并可细分到仓库、发布版、目录或单个文件。项目主页或当前仓库地址会变化,不能唯一代表过去运行的对象。

可复算记录应保存发布包校验值、提交标识或内容型持久标识。若使用自行修改的代码,要保存修改后的完整对象和差异,而不是只写“调整过”。

同一份数据重新运行,结果为什么仍可能不同:版本、参数、随机性与复算记录 配图 1
同一份数据重新运行,结果为什么仍可能不同:版本、参数、随机性与复算记录 配图 1

源代码身份也不等于执行文件身份。编译器版本、编译选项和链接库可能改变二进制结果。若分析依赖已编译扩展,应保存构建产物校验值以及构建日志。

持久标识解决的是“当时用了哪份代码”,不证明方法正确。错误算法同样可以被精确保存。对象可追溯与科学有效性是两项独立检查。

依赖库会在主程序之外改变行为

软件很少完全自包含,实际使用还可能依赖外部库和运行环境。Software Heritage论文特别指出,编译或运行可能需要软件库、运行环境、数据和其他外部资源。

主程序版本没变,依赖解析器却可能安装更新版本。新库修正错误、改变默认值或采用不同数值实现,都会进入结果。只保存顶层包列表无法说明解析出的完整依赖树。

应保存锁定文件或环境清单,包含直接与间接依赖、来源和校验值。若依赖来自系统包管理器,也要记录仓库快照与平台架构。

容器可以把许多依赖封装在一起,但“用了容器”仍不充分。标签可能被覆盖,应保存不可变镜像摘要。容器还共享主机内核,并可能调用不同CPU指令或加速器驱动。

虚拟环境也不是时间机器。环境目录可能被手动更新,远端包可能撤下。能够重新创建环境的配置、下载对象与校验值,比一张环境截图更可靠。

默认参数也是参数

图形界面没有显示的选项,命令行没有明确写出的选项,并不代表它们不存在。软件会根据版本、输入大小或平台选择默认算法。默认值变更常让旧流程在新版本产生不同结果。

运行记录应导出最终生效参数,而不只保存用户输入项。若程序支持配置转储,应保存解析后的完整配置。若不支持,至少保存命令、配置文件和对应版本文档。

预处理参数尤其容易被遗漏。过滤阈值、缺失值处理、标准化、序列修剪和多重检验方法,都可能比主模型名称更影响输出。

参数还可能互相作用。改变线程数可能切换算法路径,改变容差可能影响迭代停止,改变批次大小可能影响随机抽样。可先按原始配置复算,再把候选原因分开验证。

界面操作也要转成记录。点击顺序、勾选框和导入设置若无法导出,应保存步骤、截图与生成的配置,但截图不能替代机器可读参数。

随机种子只锁住一部分随机性

抽样、初始化、置换检验和随机优化会使用伪随机数。保存种子能让同一随机算法从同一状态开始,是重要步骤,但不是全部。

不同软件版本可能更换随机算法或改变调用顺序。即使种子相同,只要前面多调用一次随机数,后续序列就会错位。并行任务分配也可能改变每个线程消耗随机数的顺序。

应记录随机算法名称、种子、子流分配方式和线程数。若框架有多个随机来源,例如主语言、数值库和加速器各自维护状态,需要分别固定。

NIST对随机误差的说明提醒,现实只能通过有限次数估计随机波动。对随机算法,单次重跑相同并不足以描述稳定性;更适合按预设种子重复多次,报告分布、区间和结论改变频率。

固定种子有助于调试,却可能隐藏方法对初始化敏感。正式分析可以同时保存一个可复查运行,并用多种种子评估稳健性。两种目的不应混为一谈。

并行与浮点运算会产生末位差异

浮点加法不满足数学上的任意结合律。相同一组数以不同顺序累加,末位可能不同。并行任务完成顺序变化,就可能改变归约顺序。

CPU与加速器使用的指令、数学库和精度策略也可能不同。一个平台采用融合乘加,另一个拆成两步;结果都可合理,却不一定逐位相同。

迭代算法会放大微小差异。若停止条件接近阈值,末位变化可能让一个运行多迭代一次。聚类或优化存在多个近似解时,微小起点差异还可能走向另一条路径。

所以不能把任何末位差异都判成错误。应根据任务设定绝对或相对容差,并另外比较排名、分类、显著性和中心结论。容差必须在查看新结果前确定。

但“浮点误差”也不能成为万能解释。若差异远超容差、只出现在特定样本或改变主要结论,就要继续追查输入、算法路径和错误日志。

排序和并列处理会改变表格外观

许多结果差异来自排序,而不是核心数值。若多个项目分数相同,软件可能按输入顺序、哈希顺序或名称作为次级键。输入重排后,表格顺序就会变化。

比较时应先按稳定主键对齐记录,再比较对应字段。直接逐行比较两张排序不同的表,会制造大量假差异。

并列排名规则也需保存。有的方法使用最小名次,有的方法使用平均名次。两张表的分数可以完全相同,名次列却不同。

文本导出还会四舍五入。页面显示0.05,内部值可能分别为0.0496和0.0504。应比较未截断原始值,并把显示精度与计算精度分开记录。

日期、地区小数点和字符排序规则同样会进入结果。环境语言不是装饰,它可能改变解析和排序,应纳入运行环境。

用分层重跑定位差异

第一层只验证对象。比较原始输入、处理后输入、代码、构建产物和环境镜像的校验值。任何一项不一致,先记录差异,不急着运行完整模型。

第二层验证配置。导出完整参数、默认值、随机状态、线程数和环境变量。把敏感凭据排除,但保留会影响计算的设置。

第三层验证中间产物。为清洗后矩阵、特征表、模型输入和关键检查点计算校验值。最终表不同不代表要从最后一步猜起,最早出现差异的检查点更有定位价值。

第四层验证日志。保存开始与结束时间、退出码、警告、库加载版本、硬件和资源限制。被忽略的警告常能说明样本被丢弃或算法回退。

第五层才比较结果。先按稳定键对齐,再依预设容差比较数值,最后判断排序、分类和中心结论是否改变。每层都输出机器可读差异报告。

若最早差异出现在输入,修正输入链;若输入相同而中间产物不同,检查代码、依赖和随机性;若只有导出格式不同,就标成格式差异。

一致结果也需要反向检查

两个结果表完全一致,仍不能证明过程正确。两次运行可能共同读取错误列、遗漏相同样本或使用错误单位。可复算性保证过程能够重现,不保证问题设定有效。

因此还要保存独立校验。检查样本数、字段范围、单位、缺失比例和预期对照。对生物信息分析,应验证序列数量、长度分布、标识映射和过滤前后变化。

结果一致也可能来自缓存。程序没有真正重跑,而是读取旧中间文件。日志应说明缓存命中,测试复算时可在干净目录运行,并确认新产物时间与校验值。

相反,两个结果不完全一致也不必推翻研究。若差异在预设容差内、重复分布相近、主要分类与结论稳定,可以报告为跨环境复现。关键是条件和标准事先明确。

复算报告应同时保留已核实内容与未知项。没有取得旧编译器,就写明无法证明二进制身份;不要用“版本相同”填补证据缺口。

建立最小可复算证据包

第一部分是对象清单。列出原始输入、处理后输入、代码、配置、依赖锁定和容器镜像,给每个对象保存校验值或不可变标识。

第二部分是运行说明。写出操作系统、架构、处理器或加速器、驱动、语言运行时、线程数、地区设置和关键环境变量。

第三部分是随机记录。保存随机算法、所有种子、子流策略和重复次数。若算法声明确定性,也要用重复运行验证,而不是只相信名称。

第四部分是过程证据。保存完整命令、解析后参数、日志、警告、退出码和中间检查点。命令应引用证据包内的相对路径,减少目录变化影响。

第五部分是比较规则。预先定义字节一致、数值容差、排序或分类一致,以及什么变化会影响中心结论。把比较程序与结果一起保存。

第六部分是边界说明。记录仍依赖哪些外部服务、专有软件或无法保存的硬件。证据包不能封装的条件要明确列出,不能假装不存在。

来源核对记录:美国国家标准与技术研究院《技术说明1297附录D1》,重复性、复现性与随机误差术语。Software Heritage《软件源代码保存中的数字对象标识》,2018。

同一份数据重新运行,只有在输入对象、代码、依赖、参数、随机状态与数值环境都被说明后,才知道“同一”到什么程度。结果表完全一致仍不能证明输入正确,末位不同也不自动推翻结论。把条件变化和比较标准写在运行之前,重跑差异才会从争议变成可定位的证据。

资料来源

  • National Institute of Standards and Technology:《NIST Technical Note 1297, Appendix D1: Terminology》,发布或更新于 1994-10-01
  • Software Heritage:《Identifiers for Digital Objects: the Case of Software Source Code Preservation》,发布或更新于 2018-09-24