本文是《AI 算法工程师学习地图》“横切:实验方法论”一层的导读。它不属于任何一层,对每一层都适用;放在 L5 之后,是因为它要用到的例子——scaling law 的外推(04 系列第十篇)、评测的置信区间(后训练第八篇)、loss spike 的归因(04 系列第十二篇)——到这里都已经讲过了。

一个算法工程师一年里做的事,绝大部分不是”提出新方法”,而是回答一个个具体的问题:这批数据加进去有没有用?lr 调高一倍是不是更好?这个 attention 变体值不值得付出 KV 的代价?换一个 tokenizer 会不会伤中文?每个问题都要用实验回答,而每个实验都花钱——一次 7B 的 SFT 消融几十 GPU 小时,一次预训练配方的对照几千。算力是有限的,问题是无限的,于是真正区分工程师水平的不是”会不会跑实验”,而是用多少算力、多长时间,得出一个别人可以信、三个月后自己还能复现、放大十倍之后仍然成立的结论

这件事有方法,但很少被系统地教。教科书教统计推断,论文只给结果不给过程,代码库里只有最后那一版配置。本文把”做一个可信的实验”拆成六步——提假设、小规模先行、控制随机性、记录与复现、读论文与复现、看曲线——每一步说明它防的是哪一种错误、要做到什么程度、以及一个可以算出来的数字。读完应该能回答:

一个”A 比 B 好 1.5 个点”的结论,要经过哪几关才算可信?每一关不过会犯什么错?

一、总览:六步与六种错误

1. 一张对照表

实验方法论的每一步都对应一种真实发生过的错误。把它们排在一起,就是本文的结构:

防的错误 典型现场 关键数字
提假设 事后解释:先跑再想,结果怎样都能”说得通” 加了一批数据,某三个 benchmark 涨了、四个跌了,报告只写涨的三个 一个假设 = 改什么 · 哪个指标 · 变多少 · 为什么
小规模先行 结论不随规模外推 125M 上有效的 trick 在 7B 上失效,或反过来 消融跑 3 个规模;外推只信”趋势一致”的结论
控制随机性 把噪声当信号 两个 seed 差 1.2 个点,单 seed 报告”提升 1.5” 多 seed 标准差;差异 > 2σ 才值得看
记录与复现 复现不出自己的结果 三个月后同样的配置差 0.8 个点,原因是数据版本变了 代码 · 配置 · 数据 · 环境四个版本号缺一不可
读论文与复现 相信别人的数字 论文报 +5,复现 +0.5,差别在评测协议 先复现 baseline 再复现方法
看曲线 事后才发现训练早就出问题 loss 正常但梯度范数翻倍,两千步后 spike 四条曲线:loss · grad norm · lr · 评测

这六步不是顺序执行的流程,而是一次实验里同时在做的六件事:假设决定跑什么、规模决定花多少、随机性决定报什么、记录决定以后怎么用、复现决定 baseline 是什么、曲线决定要不要提前停。

2. 学到什么程度

  • 能写:在跑之前写出一份不超过十行的实验假设,包括预期的变化幅度与失败的判据。
  • 能算:给一个 benchmark 的题数和一个差异,算出它是否超过噪声;给一组小模型的结果,判断它能不能外推。
  • 能查:拿到一份三个月前的实验记录,在一天之内复现出它的数字(差异在噪声范围内)。
  • 能读:读一篇方法论文,二十分钟内提取出”改了什么、和谁比、怎么评、有没有可疑之处”。
  • 不需要:统计推断的完整理论、实验设计(DOE)的正交表、贝叶斯优化的数学。它们有用,但不在最小集里。

3. 本文的章节安排

主题 内容
提假设 可证伪的陈述;改什么、看什么、变多少;预注册;一次只改一个变量的原因与例外
小规模先行 消融的设计;什么能外推、什么不能;三个规模的规则;算力的分配
控制随机性 随机性的来源;seed 的方差有多大;多少 seed 够;差异多大算显著;非确定性 kernel
记录与复现 四个版本号;实验跟踪;配置管理;”三个月后能复现”的检验
读论文与复现 三问;先 baseline 再方法;对报告数字的四种怀疑;复现失败时怎么办
看曲线 四条曲线;形状字典;从曲线判断 lr 过大、数据有问题、过拟合开始
一份实验清单 跑之前、跑的时候、跑完之后各问什么
怎么学 材料与顺序
本文小结  

二、提假设:把”我觉得会好”变成一个可以被证伪的陈述

加了一批高质量数据之后七个 benchmark 三涨四跌,这批数据到底有没有用?

1. 为什么需要假设

不带假设跑实验是最常见的浪费。它的表现是:跑完一组配置,看到一堆数字,然后开始找解释——”数学涨了,说明数据里的推理内容起作用了;代码跌了,可能是配比稀释了”。这两句解释在跌涨互换时同样成立。一个对任何结果都能给出解释的实验,没有传递任何信息。

假设的作用是在跑之前锁定三件事:改什么(自变量)、看什么(因变量)、预期变多少(效应量)。有了它,结果只有两种:符合预期,或不符合。不符合的实验不是失败,是信息——它排除了一个想法。没有假设的实验没有”不符合”这一项,也就排除不了任何东西。

2. 一个假设的四个部分

一个能用的实验假设长这样:

部分 内容 例子
改什么 唯一的自变量与它的取值 在 SFT 数据里加入 50K 条数学推理样本(占比从 0 到 8%)
看什么 主指标(一个)与副指标(少数几个) 主:GSM8K 准确率;副:MMLU、HumanEval、IFEval(看有没有伤到别的)
变多少 预期的效应量与失败判据 预期 GSM8K +3 到 +6 个点;若 < +1.5(噪声水平)视为无效;副指标跌超过 1 个点视为有代价
为什么 机制假设 基座在 GSM8K 上的错误 60% 是推理链中断而非知识缺失,推理样本教的正是链的写法

第四部分最容易被省略,但它是唯一能让实验”教你东西”的部分。如果结果符合预期,机制假设得到一次支持;如果不符合,要修的是机制假设——”也许错误主要不是链中断”——而不是换个配比再试。

“变多少”这一项需要先知道噪声水平(第四章)。GSM8K 有 1319 题,一个 60% 准确率的模型,二项分布的标准误约 \(\sqrt{0.6 \times 0.4 / 1319} \approx 1.35\%\);再加上 seed 之间的方差,+1.5 个点以内基本分不出来。一个预期效应量小于噪声的实验,要么不做,要么先扩大评测集。

3. 一次只改一个变量——以及什么时候不这么做

消融(ablation)的基本原则是一次只改一个变量,否则两个变量的效应混在一起分不开。这条原则的代价是实验数量随变量数线性增长:五个变量五组实验,加一个 baseline。

有三种情况可以偏离它:

  • 变量之间有已知的耦合。lr 与 batch size 是最典型的一对:batch 翻倍时最优 lr 也要变(04 系列第十二篇的平方根律),只改 batch 不调 lr 得到的结论是”大 batch 差”,实际是”大 batch 配了错的 lr”。耦合变量要一起扫,或按已知的律联动。
  • 变量太多、只想筛出重要的。十几个数据源的配比不能逐个消融;这时用一次去掉一个(leave-one-out)或随机组合 + 回归(RegMix 的思路,04 系列第十一篇)比逐个加更省。
  • 验证一个”配方”而不是一个”因素”。把一整套改动作为一个整体与 baseline 比,回答”这套配方好不好”;但这时不能声称其中任何一项单独有效。

无论哪种情况,都要在跑之前写下用的是哪种设计。事后把”配方对照”解释成”逐项有效”,是论文里最常见的一类过度声称。

4. 预注册:把假设写在结果出来之前

“预注册”(pre-registration)借自实验科学:在收集数据之前公开实验设计与分析方法,防止事后调整。算法工作里不需要公开,但需要写在结果出来之前、并且不改。做法很轻:一个 Markdown 文件或实验跟踪工具里的一条 note,写下上一节的四部分,附上日期,跑完之后在下面追加结果与结论。

这样做防的是一种非常自然的自我欺骗:跑完看到 GSM8K 只涨了 1 个点,但 MATH 涨了 4 个点,于是报告”在数学上提升显著”——主指标已经悄悄换成了跌涨中好看的那个。有了预注册,MATH 的涨幅是一个新的假设(”这批数据对竞赛题比对应用题更有效”),需要新的实验去验证,而不是当前实验的结论。

5. 假设的粒度

假设太大(”这个结构更好”)无法证伪;太小(”第 3 层的 lr 乘 0.9”)不值得一次实验。合适的粒度是一个决定:这批数据要不要加、这个变体要不要采用、这个超参用哪个值。每个决定背后一个假设、一组实验、一个结论——这也是实验记录的自然单位。

三、小规模先行:什么能外推,什么不能

125M 上跑通的结论,在 7B 上还成立吗?

1. 为什么先小

一次 7B 模型在 100B token 上的预训练配方对照,大约 \(6 \times 7 \times 10^9 \times 10^{11} = 4.2 \times 10^{21}\) FLOPs,在 64 张 H100 上以 40% MFU 跑约 2.5 天。一次 125M 在 2.5B token 上的对照约 \(1.9 \times 10^{18}\) FLOPs,一张卡几小时。相差两千倍。用小模型筛掉大部分想法,把大模型的算力留给少数几个候选,是所有实验室的做法——Chinchilla 用 400 多个 70M–16B 的模型定下了 D/N ≈ 20;DeepSeek-V3 的超参数由小规模的 scaling 实验确定;Llama 3 用 scaling law 从小模型预测 405B 在 benchmark 上的分数。

但小模型的结论并不都能外推。这一章讨论哪些能、哪些不能、怎么判断。

2. 能外推的与不能外推的

经验上,结论按”是否随规模改变方向”分成三类:

典型 外推性 原因
随规模单调、方向稳定 数据去重有用;tokenizer 压缩率高省算力;Pre-Norm 比 Post-Norm 稳;warmup 有用 机制与规模无关
有效但幅度随规模变化 大部分结构 trick(SwiGLU、RoPE、GQA);正则化(dropout 在大模型上从有益到有害);数据配比 中——只信方向,不信幅度 小模型欠拟合、大模型容量富余,同一改动作用点不同
方向随规模翻转 学习率的最优值;batch size 的最优值;weight decay 的最优值;某些 “涌现” 能力(小模型上是零) 低——必须按律联动或在目标规模上验 最优超参本身是规模的函数

第三类是最危险的:小模型上”lr = 3e-3 最好”,7B 上直接用会发散。处理方法有两种:一是用 μP 一类参数化让最优 lr 在宽度上不变(04 系列第十二篇),二是在三个规模上分别找最优值再拟合趋势(DeepSeek 的经验律)。两种都要求在小规模上就按目标规模的方式做——不是拿一个固定的小配方跑所有消融。

第二类的常见错误是把幅度当结论:”SwiGLU 在 125M 上让 loss 降了 0.05,所以 7B 上也降 0.05”。正确的说法是”SwiGLU 在三个规模上都有效、幅度随规模缩小、在 7B 上预期仍有效但幅度更小”。

3. 三个规模的规则

判断一个结论属于哪一类,一个规模不够——一个点定不出趋势。最低要求是三个规模,间距约 3–4 倍(比如 125M / 350M / 1.3B),看效应的方向与幅度随规模的走势:

  • 三个点方向一致、幅度稳定或缓变 → 第一或第二类,可以外推方向。
  • 幅度随规模快速缩小 → 到目标规模可能归零;要么在目标规模验,要么放弃。
  • 方向不一致 → 第三类,结论不成立,需要重新设计(通常是有耦合变量没联动)。

三个规模的总算力约是最大那个的 1.4 倍(\(1 + 1/3.5 + 1/12\)),比只跑最大那个多 40%,换来的是”能不能外推”的判断。这是整个方法论里性价比最高的 40%。

4. 数据量与训练时长的同步缩放

小规模实验的第二个陷阱是只缩模型不缩数据——或者反过来。125M 模型训 100B token 是 800 倍的过训练,它的 loss 早已进入平台期,任何配方改动都显示不出差别;训 100M token 又严重欠训练,结果全是噪声。合理的做法是让小模型也处于与目标相同的 D/N 区间(04 系列第十篇),或者至少在同一条”训练进度”上比较(同样的 token / 参数比)。

学习率调度同理:cosine 调度的最终 loss 依赖总步数,所以两个实验的 lr 曲线要在各自的总长度上对齐,不能一个跑到调度末尾、一个在中途停下比。WSD 调度的一个实践优点正是这里——从同一条稳定段上分叉出多个衰减段,比较时对齐更容易。

5. 算力的分配

给定一笔算力预算 \(C\) 去回答一个问题,怎么分?一个常用的框架:

  1. 筛选阶段(约 10–20% 预算):最小规模,宽泛地扫——十几个候选、每个一次、单 seed。目标是筛掉明显差的,不是精确排序。
  2. 对照阶段(约 30–40%):三个规模、少数几个候选(3–5 个)、多 seed(第四章)。目标是确定效应的方向与外推性。
  3. 验证阶段(约 40–50%):目标规模或最接近的规模,一到两个候选与 baseline。目标是确认。

这个分配的核心是不要把大部分算力花在一个规模上,也不要在筛选阶段就追求精确——筛选阶段的差异多数是噪声,精确到小数点后一位没有意义。

6. 一个例子:一批新数据要不要加

假设:在预训练配比里加入 5% 的合成教科书数据能提高推理 benchmark。

  • 筛选:350M 模型,10B token,四个配比(0 / 2.5 / 5 / 10%),单 seed。看方向:是否单调?10% 有没有伤到别的?
  • 对照:125M / 350M / 1.3B,0% 与 5% 两组,各 3 seed。看效应随规模的趋势与显著性。
  • 验证:7B,0% 与 5%,各一次。同时按第七章看曲线——合成数据常见的副作用是 loss 曲线过于平滑(数据太简单)。

总算力约是一次 7B 对照的 1.5 倍,得到的是一个带趋势、带方差、在目标规模验过的结论。相比”直接在 7B 上加 5% 试一次”,多花 50% 算力,多得到的是能不能信

四、控制随机性:噪声有多大,差异多大才算信号

两个 seed 之间差了 1.2 个点,”提升 1.5 个点”还剩多少?

1. 随机性的来源

一次训练里随机性从五个地方进来:

来源 影响 能否消除
参数初始化 训练轨迹的起点 固定 seed 可消除
数据顺序(shuffle) 每一步看到的 batch 固定 seed 可消除;分布式下要同步各 rank
Dropout 等随机层 每步的前向 固定 seed 可消除
非确定性 kernel 浮点累加顺序(atomicAdd、某些 cuDNN 算法、集合通信的归约顺序) 部分可消除(torch.use_deterministic_algorithms),有性能代价;分布式归约顺序通常不可控
评测时的采样 temperature > 0 的生成 固定 seed 或 greedy;但 greedy 会低估某些能力

前三项固定 seed 就能消除,但消除它们不是目的。固定 seed 得到的是”这一个 seed 下 A 比 B 好”,而问题是”A 是否一般地比 B 好”。要回答后者,seed 恰恰要变——多个 seed 的结果给出效应的分布,才知道差异是不是运气。

第四项值得知道一个事实:即使全部 seed 固定,两次 GPU 训练的 loss 曲线在几百步后也会分开,因为浮点加法不满足结合律,归约顺序的微小差别被训练放大。这是混沌而不是 bug;bitwise 复现在大规模分布式训练里通常不追求,追求的是统计复现——结果落在多 seed 的分布之内。

2. seed 方差有多大

方差的大小取决于模型规模、数据量、评测集大小。几个可以参考的公开数字:

  • 微调阶段:在 GLUE 一类任务上,BERT-base 微调的 seed 间标准差常在 1–2 个点,某些小数据集(RTE、CoLA)超过 3 个点(Dodge 等 2020 系统地测过)。这意味着单 seed 报告的”+1.5”在这些任务上没有信息。
  • 预训练 loss:同一配置多 seed 的最终 loss 差别通常在 0.005–0.02 之间(小模型更大),而很多配方改动声称的收益在同一量级。
  • LLM 的 benchmark:SFT 后模型在 GSM8K / MMLU 上的 seed 间差异约 0.5–1.5 个点;Arena 类的人类偏好评测,同一模型不同时间窗的 Elo 差可达 10–20。

规则:不知道自己任务上的 seed 方差之前,任何差异都不能解释。第一次做某类实验时,先用 baseline 跑 3–5 个 seed,量出方差,以后所有结论都对照它。这几次 baseline 是这类实验里最有价值的算力支出。

3. 多少个 seed

多 seed 的均值有标准误 \(\sigma / \sqrt{n}\)。要把噪声压到效应量 \(\delta\) 的一半以下,需要 \(n \ge (2\sigma/\delta)^2\):

seed 间标准差 σ 要检测的效应 δ 每组需要的 seed 数
1.0 2.0 1(勉强)
1.0 1.0 4
1.0 0.5 16
0.5 1.0 1(勉强)
0.5 0.5 4

现实是预训练规模的实验很少能跑 4 个 seed。折中的办法:

  • 在小规模上多 seed,确定效应量与方差的量级;大规模上单 seed,但只信”大于小规模上 2σ”的差异。
  • 更大的评测集降低评测噪声——它是总方差的一部分,且可以便宜地降低。
  • 多个 checkpoint 近似多 seed:训练末段相邻的几个 checkpoint 之间的评测差异,粗略反映了噪声水平(它低估了初始化的方差,但比什么都没有强)。
  • 报告时如实写”单 seed,差异 X,小规模上同类差异的 σ 约 Y”。

4. 差异多大算显著

有了方差,判断显著与否的最简单规则是差异 > 2σ(双侧 5% 左右)。更规范的做法是配对检验——两个模型在同一批题上比,消掉题目难度的方差(后训练第八篇第四章讲了 McNemar 与配对 bootstrap)。这里补一个常被忽略的点:多重比较

如果扫了 10 个配置、报告其中最好的一个”比 baseline 高 2σ”,这个结论几乎无效——10 个噪声样本里最大的一个超过 2σ 的概率约 40%。处理办法:把”选出最好”与”验证最好”分开——在一组实验里选出候选,用另一组独立的 seed 或数据验证它。这正是第三章里筛选阶段与验证阶段分开的统计理由。

一个简单的自检:把实验结果按效应量排序,如果最好的几个都只有 1–2σ,且没有独立验证,那么它们很可能是噪声的排序。

5. 评测侧的随机性

生成式评测(temperature > 0)的随机性常被忘记。pass@1 用单次采样估计,一个 60% 的模型在 1319 题上单次采样的标准误是 1.35%;用 n 次采样的平均(后训练第八篇的无偏 pass@k 估计)能把它降到 \(1.35\% / \sqrt{n}\) 附近。推理模型上尤其重要——同一题目多次采样的正确率可以从 20% 到 80%,单次采样的 AIME 分数(只有 30 题)标准误超过 8 个点,任何小于 15 个点的差异都需要多次采样才能判断。

greedy 解码消除了这项随机性,但代价是它测的是”最可能的一条路径”,与实际部署时的采样行为不同,且在推理模型上常常表现更差(重复、死循环)。选哪种要在假设里写清楚,且两个模型必须用同一种。

五、记录与复现:三个月后还能复现吗

同样的配置再跑一次差了 0.8 个点,问题在哪?

1. 四个版本号

一次实验的结果由四样东西决定,缺一个就无法复现:

版本 内容 常见的遗漏
代码 git commit hash;未提交的改动(dirty tree)要么禁止、要么把 diff 存下来 本地改了两行没提交,三个月后不记得
配置 全部超参数,包括默认值——不是只存改过的那几个 库升级后默认值变了(比如 trl 某版本改了 loss 的归一化方式)
数据 数据文件的 hash 或不可变的版本标签;处理脚本的版本;shuffle 的 seed 数据”就地”被清洗过一次,路径没变内容变了
环境 框架与依赖的精确版本、CUDA / 驱动版本、硬件型号 换了一批机器,cuDNN 版本不同,某个算子的数值行为变了

开头那个 0.8 个点的问题,最常见的原因依次是:数据被改过、库的默认值变了、评测脚本变了、硬件不同导致的数值差异(这一项通常小于 seed 方差,不会到 0.8)。四个版本号都记了,排查是查表;缺一个,排查是考古。

2. 实验跟踪工具的用法

W&B、MLflow、TensorBoard 这类工具解决的是”记什么、存哪、怎么比”。用它们时几条实用规则:

  • 一个 run 一条假设。run 的名字或 tag 指向第二章写的那份假设;同一假设的多个 seed 用 group 归在一起。
  • 记全部配置,不是改过的那几个。多数工具有自动记录 argparse / Hydra 配置的能力;确认它记的是解析后的完整配置,而不是命令行上的覆盖项。
  • 记环境pip freeze 或 lockfile、CUDA 版本、GPU 型号、git hash 与 dirty 标志。多数工具默认记一部分,缺的用一个启动钩子补上。
  • 记数据版本:数据集的 hash 或版本号作为配置的一项;如果数据来自处理管线,记管线的 commit。
  • 中间产物存位置,不存内容:checkpoint 与评测输出的路径进 run 的元数据,文件本身放对象存储,路径里带 run id。

至于 Hydra / OmegaConf 一类配置管理工具:它们的价值是”配置即代码”——所有实验的差异是配置文件之间的 diff,而不是命令行历史。一个简单的纪律:每个实验对应一个配置文件(或一组覆盖项),进版本控制,命令行只指定配置文件名。

3. 评测输出也要存

存分数不够,要存每道题的输出。原因有三:事后的错误分析(后训练第八篇第八章)需要原始输出;配对检验需要逐题的对错;评测脚本更新后(比如答案抽取的正则改了)可以在旧输出上重算,而不必重跑模型。一次 7B 模型在十个 benchmark 上的全部输出约几十 MB,成本可以忽略。

4. “三个月后能复现”的检验

复现性不是记录了就有,是检验过才有。一个实用的检验:在另一台机器、由另一个人(或未来的自己),只凭实验记录,复现出 baseline。要求是复现的差异落在第四章量出的 seed 方差之内。第一次做这个检验通常会失败,暴露出的每一处缺失(”这个数据文件在谁的 home 目录下”)都是记录规范里要补的一项。

团队规模的实践是把这个检验自动化:每次改动训练代码,CI 跑一个几分钟的微型配置,比对 loss 曲线与固定的参考值(bitwise 或容差内)。它防的不是数值错误,是无意中改变默认行为——PyTorch 与 Hugging Face 生态里的库升级经常带来这类静默变化。

5. 负结果也记

跑了没效果的实验最容易丢。它们的价值在于防止重复——半年后另一个人(或自己)又想到同一个点子。负结果的记录标准与正结果一样(假设、配置、结果、结论),外加一句”为什么认为无效”(是方向不对,还是幅度在噪声内,还是实验设计有缺陷没测出来)。一份维护良好的负结果列表,是团队算力的长期节省。

六、读论文与复现:从”报了 +5”到”实际 +0.5”

论文说这个方法提升 5 个点,怎么判断它对自己的场景值几个点?

1. 三个问题

读一篇方法论文,二十分钟内要回答三个问题:

找什么 在哪找
改了什么 与 baseline 相比,方法本身的改动——去掉所有”顺便”的改动(更大的数据、更长的训练、调过的超参) 方法节 + 实验设置节的 baseline 描述;对照 appendix 里的超参表
和谁比 baseline 是不是调过的、是不是同一规模 / 数据 / 步数;有没有和最强的已知方法比 实验表的每一行来源:是自己跑的还是引用的?引用的数字评测协议是否相同?
用什么评 benchmark 是哪几个、协议是什么(few-shot 数、抽取方式、temperature);有没有报方差;主指标是不是事先定的 实验设置节;表格脚注;appendix

三问里最常出问题的是第二问。一个非常普遍的模式:方法用精心调过的超参,baseline 用默认超参或引用其他论文的数字(不同协议)。这不一定是故意的——调自己的方法总比调别人的方法花心思——但结果是效应被高估。看到 baseline 数字与该 baseline 原论文报的数字不一致时,要问为什么。

2. 先复现 baseline,再复现方法

复现的顺序是固定的:先在自己的环境里跑出论文的 baseline 数字,误差在噪声内,然后才加方法。跳过这一步直接复现方法,得到 +0.5 时无法判断是方法不行、还是自己的 baseline 已经比论文的强(方法的收益被吃掉了)、还是评测协议不同。

复现 baseline 本身常常就要花大半时间——协议的每个细节(后训练第八篇第三章)都会改变分数。复现出来之后,得到的不只是一个数字,而是一个校准过的评测环境:以后所有自己的实验都在它上面比。

3. 对报告数字的四种怀疑

怀疑 表现 检验
协议差异 论文的 baseline 数字与该模型的官方报告不同 在同一协议下重跑两者
挑选 报告了 7 个 benchmark,方法在 5 个上提升;或报告了最好的 seed / checkpoint 看有没有报方差、有没有 held-out 的 benchmark;看 appendix 里有没有更多结果
污染 在某些 benchmark 上涨幅异常大(+15)而在同类任务上不涨 用新题 / 改写题重测(后训练第八篇第七章)
规模 只在一个规模上验证;或只在小模型上验证但声称普适 找第三章的三类判断;自己在两个规模上试

四种怀疑不是对作者的不信任,是对发表偏差的校正:有效的方法比无效的更容易发表,效应量大的比小的更容易发表,因此发表出来的效应量系统性地高于真实值。一个经验性的折扣:论文报告的收益,在自己的场景里通常能兑现三分之一到一半;如果 baseline 本来就比论文的强,兑现的更少。

4. 复现失败时

复现出的效应远小于论文时,按顺序排查:

  1. 评测协议——最常见。逐项对照:few-shot 数、prompt 格式、抽取正则、temperature、最大长度。
  2. baseline 强度——自己的 baseline 是不是已经用了论文里没用的东西(更好的数据、更多步数)。
  3. 规模与数据——论文在 125M 上 +5,自己在 7B 上 +0.5,是第三章的第二类现象,不是复现失败。
  4. 实现细节——论文没写的细节(初始化方式、归一化位置、loss 的归约方式)。看官方代码;没有官方代码时,找第三方复现的 issue 列表,那里通常已经有人踩过。
  5. 联系作者——前四步都排除后。

不需要复现每一篇论文。值得复现的是准备采用的方法——因为采用的成本远高于复现的成本。

5. 读论文的另一个目的:建立”效应量的直觉”

读得多了会形成一种直觉:什么样的改动大概值多少。数据质量的改进通常值几个点到十几个点;结构 trick 通常值零点几到一两个点;超参调优在合理范围内值一两个点;后训练配方的差别在对话评测上可以值十几个点,在知识 benchmark 上几乎为零。有了这种直觉,看到一篇”改了 FFN 激活函数提升 5 个点”的论文时,第一反应应该是去看 baseline 有没有调好。

七、看曲线:训练还没结束时就知道出了问题

loss 曲线看起来正常,为什么两千步后 spike 了?

1. 四条必看的曲线

曲线 看什么 报警形态
训练 loss 下降速度、平滑度、与预期曲线(scaling law 或以前的 run)的偏差 平台过早(lr 太小或数据太简单);锯齿(数据分布在 shard 之间不均);spike;突然下降到接近零(数据泄漏或重复)
梯度范数 量级与趋势 持续上升(lr 太大或数值问题在积累,spike 的前兆);某几步的孤立尖峰(坏 batch);接近零(梯度消失,或 loss 已经饱和)
学习率 确认调度是否按预期执行 warmup 长度不对;衰减终点不对;恢复训练后 lr 没有从断点继续
验证 / 评测指标 与训练 loss 的关系 训练 loss 降、验证 loss 升(过拟合开始);验证 loss 降但 benchmark 不动(loss 的下降来自评测不关心的部分)

四条里最常被忽略的是梯度范数——它比 loss 更早报警。04 系列第十二篇讲过 spike 的三种机制,其中两种(attention logits 增长、embedding 梯度稀疏)在 loss 上显现之前,梯度范数已经持续上升了几百步。

再多看几条会更有把握:参数范数(weight decay 是否在起作用)、attention logits 的最大值(QK-norm 需不需要)、混合精度的 loss scale 或 FP8 的溢出计数(数值问题)、每步的 token 吞吐(数据加载是否成了瓶颈、有没有慢节点)。

2. 形状字典

把常见的曲线形状与原因对上,是一个可以积累的技能。几个高频的:

训练 loss 下降过快、过平滑:数据太简单或有大量重复。检查数据的去重与配比;对照以前同规模 run 的曲线。

loss 每隔固定步数出现周期性起伏:数据 shard 之间分布不均(一个 shard 全是代码,下一个全是网页)。shuffle 的粒度不够——需要跨 shard 的全局 shuffle 或更细的交错。

loss 在某一步之后再也不降、梯度范数接近零:某种饱和。可能是 lr 已经衰减到零(检查调度)、也可能是数值精度问题(bf16 下小梯度被舍掉)。

loss 缓慢上升:lr 太大导致的漂移(区别于 spike 的突然上升),或 weight decay 过大。看梯度范数是否同时上升。

验证 loss 与训练 loss 的间隙逐步拉大:过拟合。在 SFT 多 epoch 时常见——第二个 epoch 结束时间隙开始变大,第三个 epoch 模型开始复述训练集。

训练 loss 正常但下游评测退化:loss 的下降来自评测不关心的部分。常见于加入新数据后——新数据的 loss 降得快,拉低了平均,但原有能力在变差。按数据源分开记 loss是解决办法:每个数据源的 loss 单独一条曲线。

评测指标在训练中大幅震荡:评测集太小(第四章),或评测本身有随机性(temperature 采样、judge 的方差)。先换更大的评测集或多次采样。

恢复训练后曲线不连续:状态没有完整恢复——优化器状态、lr 调度的步数、数据加载器的位置、RNG 状态中有一项没存。

3. 从曲线判断学习率

lr 是最需要用曲线而不是最终指标判断的超参,因为 lr 的影响在训练早期就能看出来:

  • 太大:loss 早期下降快但很快变得不稳定,梯度范数偏高且波动大;极端时几百步内 spike 或发散。
  • 太小:loss 下降慢,曲线过于平滑,梯度范数偏低;到调度末尾 loss 明显高于同规模的参考曲线。
  • 合适:loss 在 warmup 结束后进入稳定的幂律式下降,与 scaling law 的预测曲线接近。

一个实用的方法是 lr 扫描的早期截断:跑五个 lr(间隔 3 倍),各跑总步数的 5–10%,看这一段的 loss 与梯度范数。多数情况下最差的两三个已经能排除,剩下的再跑全程。它不完美——lr 与调度耦合,早期最好的不一定最终最好——但作为筛选足够。

4. 决定什么时候停

看曲线的最后一个用途是提前终止:一个消融实验如果在 20% 的步数上已经落后 baseline 超过噪声水平,且差距在拉大,跑完的意义很小。这是节省算力最直接的办法,但要小心两种例外:有些改动早期慢、后期追上(比如更强的正则化、某些数据配比);以及 lr 调度不同的 run 在中途不可比(第三章第四节)。在假设里写下终止判据(”若 20% 步数时 loss 落后超过 0.03 则终止”)是防止事后随意终止的办法。

八、一份实验清单

把前六章压成一页,跑实验时对照:

跑之前

  1. 假设写下来了吗——改什么、看什么、变多少、为什么?
  2. 主指标是一个吗?副指标是为了看副作用还是为了事后挑好看的?
  3. 这类实验的 seed 方差知道吗?预期效应量比它大吗?
  4. 自变量与其他变量有耦合吗(lr–batch、数据量–步数、调度–总长度)?联动了吗?
  5. 规模定了吗?这个规模上的结论能外推吗?需要几个规模?
  6. baseline 是最强的、调好的、协议相同的吗?
  7. 终止判据写了吗?
  8. 代码提交了吗?配置进版本控制了吗?数据版本记了吗?

跑的时候

  1. 四条曲线在看吗?梯度范数正常吗?
  2. 与预期曲线(scaling law / 以前的 run)偏差多大?
  3. 按数据源分开的 loss 有没有异常?
  4. 到了终止判据吗?

跑完之后

  1. 差异超过 2σ 了吗?如果扫了多个配置,最好的那个用独立的 seed 验了吗?
  2. 结论只说方向还是也说幅度?幅度能外推吗?
  3. 逐题输出存了吗?错误分析做了吗?
  4. 结果与结论追加到假设下面了吗?负结果也记了吗?
  5. 另一个人凭记录能复现吗?

十七个问题不用每次都全过,但每一个都对应一种发生过的错误。

九、怎么学

1. 材料

实验方法论的材料分散,没有一本”LLM 实验方法论”教材。可以拼起来的:

  • 统计基础:任何一本应用统计的前几章(估计、置信区间、假设检验、多重比较)。目标是理解第四章的每个数字从哪来,不需要更多。
  • 深度学习实验的经验总结:Google 的 Deep Learning Tuning Playbook(Godbole 等)——关于超参调优、消融设计与”科学 vs 干扰 vs 固定”参数分类的实用指南,是本文第二、三章的直接参考。Karpathy 的 A Recipe for Training Neural Networks——关于看曲线与逐步增加复杂度。
  • 实验的可复现性:Dodge 等 2020(Fine-Tuning Pretrained Language Models: Weight Initializations, Data Orders, and Early Stopping)量化了 seed 方差;Bouthillier 等 2021(Accounting for Variance in Machine Learning Benchmarks)系统地讨论了随机性的来源与多少 seed 够。
  • scaling 实验的设计04 系列第十篇第五章”用小模型预测大模型”与它引用的 Chinchilla、Porian 等的拟合方法论。
  • 评测的统计后训练第八篇第四章与 Miller 2024(Adding Error Bars to Evals)。
  • 技术报告的实验节:Llama 3、DeepSeek-V3、OLMo 2 的技术报告里关于”怎么决定超参与配比”的部分,是公开的、规模最大的实验方法论案例。OLMo 系列的价值尤其在于它公开了全部中间 checkpoint 与数据,可以真的去复现。

2. 顺序

  1. 先把第四章的方差量出来:在自己最常做的一类实验上,用 baseline 跑 5 个 seed。这一步之前所有结论都没有参照。
  2. 把第五章的四个版本号补进现有的实验流程,做一次”另一台机器复现 baseline”的检验。
  3. 下一次实验开始前,写第二章的假设——四部分,不超过十行。跑完追加结果。
  4. 下一次要采用一个论文方法时,按第六章先复现 baseline。
  5. 看曲线的能力靠积累:每次训练出问题,把曲线形状与最终原因记成一条,形成自己的形状字典。
  6. 第三章的多规模外推,在有算力做预训练规模实验时再练;微调规模的实验通常只在一个规模上做,但”结论能不能外推到更大的基座”的问题同样存在。

十、本文小结

规则 数字
提假设 改什么 · 看什么 · 变多少 · 为什么;写在结果之前;一次一个决定 预期效应量必须大于噪声水平
小规模先行 三类结论:方向稳定 / 幅度变化 / 方向翻转;三个规模看趋势;数据量与调度同步缩放 三个规模多花 40% 算力;筛选 / 对照 / 验证约 15 / 35 / 50
控制随机性 先量 seed 方差;多 seed 报均值与标准差;差异 > 2σ;筛选与验证用独立样本 \(n \ge (2\sigma/\delta)^2\);GSM8K 单次采样标准误 1.35%
记录与复现 代码 · 配置 · 数据 · 环境四个版本号;存逐题输出;负结果也记;检验”另一台机器复现 baseline” 复现误差应落在 seed 方差内
读论文与复现 三问:改了什么、和谁比、用什么评;先 baseline 再方法;四种怀疑:协议、挑选、污染、规模 论文收益在自己场景通常兑现 1/3–1/2
看曲线 loss · 梯度范数 · lr · 评测四条;梯度范数比 loss 先报警;按数据源分 loss;写下终止判据 lr 扫描用 5–10% 步数早期截断

核心问题的答案:一个”A 比 B 好 1.5 个点”的结论要过五关。第一关,1.5 是不是事先预期的主指标上的变化,而不是七个指标里挑出来的一个;第二关,这类实验的 seed 方差是多少,1.5 是不是超过了 2σ(多数微调任务上 σ 约 0.5–1.5,1.5 个点在边缘);第三关,如果 A 是从多个候选里选出来的,有没有用独立的 seed 或数据验证过;第四关,A 与 B 的评测协议是否完全相同、baseline 是否调好;第五关,这个结论在什么规模上得出,要用在什么规模上,效应的方向与幅度在几个规模上一致吗。五关都过,它是一个可信的结论;过了三关,它是一个值得进一步验证的线索;一关都没过,它是一个数字。

回到地图:《AI 算法工程师学习地图》

本文由 arganzheng 创作,采用 CC BY 4.0 许可协议。在保留原文作者、署名以及完整原文链接(https://arganzheng.life/experimental-methodology-for-ai-algorithm-engineers.html)的前提下,欢迎各种形式的转载、翻译或商业引用。


COMMENTS

评论存放在 GitHub Discussions, 用 GitHub 账号登录即可发表,支持 Markdown。 想针对正文某句话说?选中那段文字,点浮出的「评论」即可划线评论;觉得哪里写错了,发表时勾上「同时提交 Issue」。 有人回复你时 GitHub 会按你的通知设置发邮件,不用守在这里。

×