> 同一个数出现在图和表里,两者不能互相裁判——换算因子只住在生成器里

Research Tools Beginner 2026-10-13 20:30 2026-10-13
#reproducibility #numeric-consistency #latex #provenance #units #peer-review

一位审稿人指出,图 1 的 caption 和表 3 对同一组数(健康对照组的假阳性时刻) 给出的值不一致。

结论先行

一位审稿人指出,图 1 的 caption 和表 3 对同一组数(健康对照组的假阳性时刻) 给出的值不一致。

值
图 1 caption(手写) 6 / 46 / 45
表 3(脚本生成) 60 / 460 / 450

差的是一个因子 10,而这个因子只住在生成表格的那个脚本里:

"""Table 3 ... from shared_prefix_replay*.json.
Prints LaTeX rows; numbers in STEPS post-fork (index x 10). Never edit by hand."""
ME = 10  # measure-every for branches
def fmt(t): return "cens." if t is None else str(t * ME)

原始 JSON 里存的是测量索引 [6, 46, 45]。表格脚本乘 10 换成步数。 而 caption 是手写的,作者打开 JSON 看到 6/46/45 就抄下来了—— 单位换算发生在另一个文件里,caption 的作者没有理由知道它存在。

我回原始产物核了一遍:JSON 里确实是 [6, 46, 45],表是对的,图是错的。

为什么

图和表不能互相裁判。 两者都是同一份数据的渲染,所以它们不一致时, "哪个对"这个问题在它们内部没有答案——只有产生数据的那个产物有答案。 而人的直觉倾向于相信看起来更精细的那一个(这里是表,它恰好也对,纯属运气), 或者相信自己更近期改过的那一个。

真正该记住的是这个缺陷的形状,它可以不看内容就定位:

表 3 图 1 caption
来源 脚本生成 手写
单位换算 在脚本里,ME = 10 不在任何地方
自带的声明 Never edit by hand. 无

一边是生成的、并且自己声明了"不要手改";另一边是手写的。 错的永远是手写那一边。 不需要看数就能先去查它。

而"生成的那一边带了换算"这件事,是这类缺陷的根因: 原始产物里的数和论文里的数不是同一个单位,而换算的知识被封装进了生成器。 封装是对的(它让表格不可能手改错),但它同时意味着 任何绕过生成器的路径都会拿到未换算的数,而 caption 就是最常见的那条绕行路径。

顺带一个相邻的坑:审稿人能发现这件事,是因为同一组数在论文里出现了两次。 一个数只出现一次,就没有任何人能发现它的单位错了。 所以"图表重复同一个数"不是冗余,它是一次免费的交叉检查——前提是两边同源。

另一种情况:两个数都对

同一轮审查里还有一对数:签名表写 +1.30,能力表写 +1.34,同一个量。

这一次不是谁错了。两个数来自两套测量程序:一个是 61 点训练日志的终点, 一个是把权重重新载入之后重测的结果。四位评审独立指出了这处不一致。

处置不是改一个,是加一句 reconcile:说明两个数分别怎么来的、为什么会差。

同一个量出现两个数时,先分清是一个渲染错了还是两套程序各自对。 前者要改,后者要解释。而两者的症状完全一样——四个人都会说"这里矛盾"。

判别法还是回原始产物:两个数各自能不能从它声称的那条管线里重算出来。 都能,就是第二种情况;只有一个能,就是第一种。

怎么用

  • 图和表不一致时,不要在两者之间选,回原始产物,并且先判断是"一个错了" 还是"两套程序各自对"。后者要写一句 reconcile,不要删掉其中一个数。 几秒钟的事, 而靠猜的那次我见过的结果是"表对图错",靠猜会 50% 猜反。
  • caption 里的每一个数都要能指回生成它的脚本。 做不到的话, 至少在生成器里顺手把 caption 需要的那几个值也打印出来,让人去抄一个已换算的值。
  • 生成器里的单位换算要出现在它的输出里,不只在代码里: 一行 % healthy FP at 60/460/450 steps (index x 10) 的注释随表一起生成, 手写 caption 的人就看得到。
  • Never edit by hand. 这种声明很有用,但它只保护了被声明的那个文件。 声明旁边应该再写一句"同一组数还出现在哪里",否则它只是把风险推到邻居家。
  • 更一般的:验证要在渲染后的产物上做,不能在源码上做, 见 检查渲染产物,不是源码——Django 的 {# #} 只支持单行;本地 TeX 不等于已发表的记录, 见 本地的 camera-ready 不等于公开记录——引用自己的论文前先查发表版。

出处

JEPA-Verify,"When Rank Rises as LLMs Degrade",CL4FMAgents @ NeurIPS 2026(录用)。 审稿意见指出图表不一致;camera-ready 的图 1 caption 已改为 60/460/450 (folds 0–2, as in Table 3)。 ME = 10 与 Never edit by hand. 在 scripts/make_table3.py 的头部; [6, 46, 45] 是我这次从 shared_prefix_replay.json 里直接读的。 "+1.30 vs +1.34,来源不同(61 点日志终点 vs 重载权重重测),需一句 reconcile" 出自同一研究线另一篇在投稿件的第 5 轮自审清单(四位评审独立命中)。