从目标到决策:训练什么、怎么做消融

训练一个大模型之前,要做的决定比想象中多得多:该不该训?训多大?用什么结构、什么数据?每个选择又怎么知道是对的?Hugging Face 训 SmolLM3(3B 参数、11T token 的多语言推理模型)时,消融和调试花掉的 GPU 小时超过了正式训练的一半。这些算力花在一件事上:先想清楚为什么要训,把目标翻译成具体的选项,再用小规模实验(消融)一个一个地验证。

这听起来像管理学,但每一步背后都有可以算的东西:参数量怎么对齐、评测分数的噪声有多大、一轮消融要烧多少 GPU 小时、给定算力该训多大的模型。

训练罗盘:Why → What → How

机器学习这个领域对「优化」有一种执念:盯着 loss 曲线、网络结构、吞吐。但在这些之前,还有一个更早的问题:这个模型到底该不该训?开源社区几乎每天都有新的强模型发布(Qwen、Gemma、DeepSeek、Kimi、OLMo……),大多带宽松的许可证。很多失败的训练项目不是死在超参或 bug 上,而是死在「训了一个世界并不需要的模型」上。

所以不妨把整件事组织成一个三段的「罗盘」:

Why:为什么训 研究 生产需求 战略性开源 决定要不要开始 What:训什么 架构类型 模型大小 数据配比 做哪些消融 把目标变成规格 How:怎么训 基础设施 训练框架 处理 loss spike 中训练 / 后训练 执行与救火
训练罗盘:每一段的答案都约束下一段。

这三段是有方向的:Why 的答案决定 What 的取值范围,What 的选择又决定 How 的难度。比如「要在手机上跑」(Why)直接把模型大小卡在几 B 以内、把 MoE 排除在外(What),进而决定你用一台 8 卡机器就能做大部分消融(How)。这些是战略层面的问题,不涉及技术细节,却决定了后面所有技术工作的方向。

Why:先问该不该训

四个不算理由的理由

先看一个太常见的场景:某个团队拿到了一批 GPU,「我们有 100 张 H100 三个月,训个模型吧!」模型大小随手一拍,数据有啥用啥;半年后算力和士气都烧光了,模型没人用,因为从没有人问过为什么。下面四个常听到的理由,其实都不成立:

说法为什么不成立
「我们有算力」算力是资源,不是目标
「别人都在训」这是同辈压力,不是策略
「AI 是未来」这是口号,不是计划
「我们想要最好的模型」太泛,不能指导任何具体决策

决策流程:能用现成的,就别从头训

技术上,判断的顺序很简单:先看现有模型靠 prompt 能不能解决;不行再看微调(后训练或继续预训练)能不能解决;都不行,才考虑从头预训练。

现有模型 + prompt 能解决吗? 能 不能 不训,直接用 微调 / 继续预训练能解决吗? 能 不能 不要从头训 从头预训练 而且理由应落在下面三类之一: 研究 有一个具体问题 需要从头训才能回答 生产 领域 / 部署 / 合规 现成模型满足不了 战略性开源 生态里有个空缺 你有理由能填上
要不要从头训练的决策流程。这里的「训」指从头训练;蒸馏和剪枝是另一条路线(可以参考 NVIDIA 的 Minitron),这里不讨论。

一个很实用的检验:先花几天时间在 Qwen3、Gemma 3 这类当前最强的开源模型上搭一下,看 prompt、工具调用、后训练能不能达到你的指标。达不到,才说明可能需要自己训。还有一个经济账:即使需要的后训练规模非常大,也往往比从头训便宜——在已有模型上继续训 1T token,比从零训 10T+ token 省得多。(规模大到这一步,人们一般就不叫它后训练,而改叫「mid-training」了。)

三类站得住的理由

研究。研究项目的共同点是一开始就有一个定义清楚的问题。几个例子,每个都对应一篇真实的论文:新优化器能不能扩到 10B 以上(Muon is Scalable for LLM Training);只用强化学习、不做 SFT 能不能得到推理能力(DeepSeek-R1);只用合成的「教科书」数据能不能训出好的小模型(Textbooks Are All You Need);只用开放许可的数据能不能有竞争力(The Common Pile v0.1)。假设越具体、对所需实验规模想得越清楚,成功概率越高。

生产。公司不能直接用现成模型,通常有三个原因,两个技术的、一个治理的:

战略性开源。成熟的实验室发布新开源模型,最常见的原因是发现了生态里的某个空缺:没有强的长上下文端侧模型;多语言模型在低资源语言上很弱;世界模型这类新方向没有好的开源权重。你有理由相信自己能做得更好——更好的数据、更好的配方、或者有算力把模型训得比别人更久(overtrain)。目标要具体:不是「史上最强模型」,而是「最好的端侧 3B 模型」「第一个有 1M 上下文的小模型」。

Hugging Face 自己的例子

Hugging Face 自己的历史就是「发现空缺 → 填上」这个模式:GPT-3 发布后没有开放的替代品,于是有了 BigScience 和 176B 的 BLOOM,几十位贡献者花一年搭训练栈、分词器和语料;OpenAI 的 Codex 闭源,于是和 ServiceNow 一起在 BigCode 下做了 The Stack 数据集和 StarCoder 15B;StarCoder2 则来自一个教训——当初应该训得更久,而且多个训得更久的小模型可能比一个大模型更有用,于是训了 3B/7B/15B 一个系列、数万亿 token。SmolLM 系列同理:强的小模型很少,而他们刚做出了 FineWeb-Edu。SmolLM(135M/360M/1.7B)→ SmolLM2(更好的数据、训得更久)→ SmolLM3(扩到 3B,加上混合推理、多语言和长上下文)。

这些例子的共同点:每个项目开始之前,都能用一句话说清楚「现在缺什么、为什么我们能补上」。

What:把目标翻译成决策

想清楚 why 之后,what 是可以推出来的。这里的 what 指:模型类型(dense、MoE、混合结构或别的)、模型大小、结构细节、数据配比。几个例子:

除了用例驱动的选择,还有一类选择是为了让训练本身更好:更稳定、样本效率更高、更快。这类选择没有那么一目了然。整个决策过程可以分成两阶段:

要学会判断什么值得测,而不只是会测。在无关紧要的选项上做完美的消融,和在重要选项上做粗糙的消融,浪费的算力一样多。

团队:迭代速度与数据

能把模型训好的团队,通常有两个「超能力」。第一是迭代速度:训练 LLM 是边做边学的手艺,训得越频繁,团队越强。一年训一个模型的团队和一季度训一个的团队,后者进步快得多;Qwen、DeepSeek 都有持续快速发布的历史。第二是数据:人们天然倾向于钻研结构来改进模型,但最强的团队是对高质量数据最执着的那些。

和迭代速度挂钩的是团队规模。主预训练任务只需要少数几个人加上足够的算力——今天要训一个 Llama 3 这样的模型,大概两三个人就够;等到要做多模态、多语言、后训练等更多方向时,再为每个方向加几个人。建议是:从一个小而装备齐全的团队开始,每两三个月训一个新模型。

为什么一切从小消融开始

开训之前要做很多决定:用什么结构?什么优化器和学习率调度?混哪些数据?人们常以为这些靠深思熟虑就能定。但 LLM 的很多事情不符合直觉。举个例子:直觉上 arXiv 这种海量科学文本「质量最高」,训上去应该更好;实际上并不会,对小模型甚至有害(DeepSeekMath 观察到了这一点)。原因是 arXiv 论文虽然知识密集,但高度专门化、文体狭窄,和模型最能学到东西的多样通用文本差别很大。

所以办法只有一个:像经验科学家那样做大量实验。今天的机器学习有点像统计力学出现之前的热力学:有可靠的经验定律和设计原则,深层理论还在路上。

这里的消融(ablation)是一个宽泛的说法:固定其他一切,只改一个组件(去掉、替换或调整它),看结果怎么变。对消融实验有两个要求:

  1. 快:跑得越快,能测的假设越多;
  2. 可靠:要有足够的区分度。如果看的指标在早期分不清不同设置,消融就说明不了什么;如果指标很嘈杂,我们就是在追逐噪声。

这两个要求互相拉扯:越小越快,但越小越可能不准、不可外推。搭消融的大部分技巧,都是在这两者之间找平衡。

选 baseline 与「去风险」

从一个被验证过的起点出发

每个成功的模型都建立在一个已被验证的基础上,再按需修改:Qwen 第一代从 Llama 的结构出发;Meta 训 Llama 3 从 Llama 2 出发;Kimi K2 从 DeepSeek-V3 的 MoE 结构出发。这不只适用于结构,也适用于超参和优化器。原因是好的结构和训练设置是很多机构多年迭代出来的,失败模式、不稳定性、高效实现都已被人踩过;从零设计意味着自己把所有坑再踩一遍。

一个好的起点应当:

截至 2025 年下半年,常见的候选起点如下:

类型模型族尺寸
DenseLlama 3.1 / 3.28B、70B / 1B、3B
DenseQwen30.6B、1.7B、4B、14B、32B
DenseGemma 312B、27B
DenseSmolLM2、SmolLM3135M、360M、1.7B、3B
MoEQwen3 MoE、gpt-oss、Moonlight、Kimi K2、DeepSeek-V330B-A3B … 1T-A32B
HybridZamba2、Falcon-H10.5B–34B
MoE + HybridQwen3-Next、MiniMax-01、MiMo-V2-Flash80B-A3B、456B-A46B、309B-A15B

「30B-A3B」这种写法表示总参数 30B、每个 token 激活 3B(MoE 的概念在下一篇细讲)。选法:找到你的结构类型,挑一个参数量接近目标的,不必想太多——起点不是一成不变的。

去风险:没测过就不改

拿着 baseline 直接训(只要数据配比好),多半能得到一个不错的模型,很多成功项目就是这么做的。但 baseline 是为别人的约束设计的,所以通常有值得改的地方。问题在于每次结构改动都有风险:可能提升、可能拉垮、也可能毫无作用还白烧了消融算力。管控这种风险的纪律叫 derisking(去风险):没有测试证明它有帮助,就什么都不改。

什么叫「去风险了」?测试表明,这个改动要么提高了目标能力上的表现,要么带来了实际好处(推理更快、显存更少、训练更稳),同时性能损失在可接受范围内。

可改的组件很多:注意力、位置编码、激活函数、优化器、超参、归一化、模型布局……而且组件之间常有非线性的交互。你既没有时间也没有算力去测所有组合。可行的做法是增量式 baseline:

baseline Llama 式 + 共享 embedding + GQA + 文档内 mask + NoPE + emb 无 WD 每一步:在当前 baseline 上只改一处 → 测 → 有效则并入,成为新的 baseline 顺序:先测久经考验的改动,再测新改动(SmolLM3 的实际顺序)
SmolLM3 的结构改动就是按这个顺序逐个验证的。每个改动的细节见架构篇。

算力允许的话,也可以对每个改动单独测试,再做 leave-one-out 分析(全部改动都加上,每次去掉一个,看去掉哪个损失最大),ScaleRL 论文就是这种方法的一个好范例。不要掉进对每个超参做穷举网格搜索、或测试每个新出的结构变体的陷阱。测任何改动之前先问两个问题:

两个都回答不了「是」,就跳过。

选训练框架

第一个具体决定是用什么框架——它同时也是所有消融要用的框架。一条很实在的建议:不要在消融和正式训练之间换框架,那是通往痛苦的路。三个考量:框架要支持目标结构或容易扩展;要稳定、能用于生产、不会训到一半莫名其妙坏掉;吞吐要高。这三者常常互相冲突。

框架功能实战检验优化代码行数(核心/总计)可扩展与调试
Megatron-LM很全Kimi K2、Nemotron3D 并行的开创者93k / 269k对新手难
DeepSpeed很全BLOOM、GLMZeRO 与 3D 并行的开创者94k / 194k对新手难
TorchTitan在快速增加较新,PyTorch 团队测过dense 优化好,MoE 在改进7k / 9k中等:需要懂并行
Nanotron精简,为 HF 预训练定制StarCoder、SmolLM为 HF 的规模优化过15k / 66k中等:需要懂并行

前三个框架的行数来自 TorchTitan 技术报告。HF 自己从零写了 Nanotron,这让他们彻底理解了大规模预训练(后来整理成了 The Ultra-Scale Playbook),但代价是大量的人力投入。另一条路是 fork 一个现成框架再改,比如 Thinking Machines Lab 的内部预训练库就是 TorchTitan 的 fork。最终取决于团队经验、目标功能和愿意投入多少开发时间。多个框架都满足需求时,在你自己的硬件上比较吞吐;做快速实验时,代码简单的往往胜出。

消融怎么搭:缩小规模、对齐参数量

两种缩小方式

消融的目标是:在小规模上跑实验,得到能放心外推到正式训练的结论。缩小有两种方式:

  1. 目标尺寸、更少 token:SmolLM3 的一部分消融直接用 3B 模型训 100B token,而不是正式的 11T。
  2. 更小的代理模型(proxy):目标太大时用小模型代替。比如 Kimi 开发 1T 总参、32B 激活的 K2 时,部分消融用的是 3B 总参、0.5B 激活的 MoE。

关键问题是小规模的结论能不能迁移。经验是不对称的:小规模上有害的东西,基本可以放心地在大规模上排除;小规模上有效的东西,则要确保训了足够多的 token,才能以较高把握认为它会外推。训得越久、消融模型越接近最终模型,结论越可靠。

HF 的 1B 消融配置

他们的主力消融设置是一个照搬 Llama 3.2 1B 结构的 vanilla Transformer,训 45B token,在一台 8×H100 上用 Nanotron 大约一天半(每卡每秒约 42k token)。这个尺寸的 Chinchilla 最优训练量大约是 35B token,多训一些是为了让信号更稳定。时间可以这样估算:

$$t = \frac{45\times10^{9}\ \text{tokens}}{42\times10^{3}\ \text{tokens/s/GPU}\times 8\ \text{GPU}} \approx 1.34\times10^{5}\ \text{s}\approx 1.55\ \text{天}.$$

对应的 Nanotron 配置,关键字段如下:

data_stages:            # 数据:三个源及权重
  dataset_folder: [fineweb-edu, stack-edu-python, finemath-3plus]
  dataset_weights: [0.7, 0.2, 0.1]
model_config:           # 结构:Llama 3.2 1B
  hidden_size: 2048
  num_hidden_layers: 16
  num_attention_heads: 32
  num_key_value_heads: 8
  intermediate_size: 8192
  max_position_embeddings: 4096
  rope_theta: 50000.0
  tie_word_embeddings: true
optimizer:              # AdamW + 预热 + cosine
  clip_grad: 1.0
  learning_rate: 0.0005
  lr_warmup_steps: 2000          # 线性预热
  lr_decay_starting_step: 2000
  lr_decay_steps: 28000          # cosine 衰减到 min_decay_lr
  min_decay_lr: 5.0e-05
  weight_decay: 0.1
  adam_beta1: 0.9
  adam_beta2: 0.95
  adam_eps: 1.0e-08
parallelism: {dp: 8, tp: 1, pp: 1}   # 1B 只需数据并行
tokens:
  sequence_length: 4096
  micro_batch_size: 3
  batch_accumulation_per_replica: 16
  train_steps: 30000

全局 batch(global batch size, GBS)由数据并行度、梯度累积步数、micro-batch 和序列长度相乘得到:

$$\text{GBS} = \underbrace{8}_{dp}\times\underbrace{16}_{\text{accum}}\times\underbrace{3}_{\text{micro-batch}}\times\underbrace{4096}_{\text{seq}} = 1{,}572{,}864\ \text{tokens}\approx 1.5\text{M}.$$

按 1.5M token 一步、30,000 步算,正好是 45B token(精确值约 47B)。学习率调度:前 2000 步线性升到 5e-4,之后 28,000 步按 cosine 衰减到 5e-5。这些超参的含义会在第三篇展开。

做消融时,按要测的东西改对应的段落,其余保持不变:测结构改 model,测优化器和超参改 optimizer,测数据改 data_stages。

一次只改一处。同时改了多个变量、性能变好了,你不会知道是谁的功劳。先逐个测,再把有效的合起来重新评估。

改结构时要对齐参数量

有些结构改动会显著改变参数量:把共享 embedding 改成不共享,embedding 参数翻倍;把多头注意力(MHA)换成分组查询注意力(GQA)或多查询注意力(MQA),注意力参数大幅减少。如果不处理,比较的其实是「改动 + 参数量变化」两个变量。公平的做法是记录参数量,必要时调整层数或宽度,让两边参数量大致相同。

对一个 Llama 式的 dense 模型,参数量可以手算。记隐藏维度 \(h\)、层数 \(L\)、query 头数 \(n_h\)、KV 头数 \(n_{kv}\)、每头维度 \(d=h/n_h\)、MLP 中间维度 \(I\)、词表大小 \(V\):

$$N = L\big(2h^2 + 2h\,n_{kv}d + 3hI + 2h\big) + h + (1\ \text{或}\ 2)\,Vh.$$

代入 baseline(\(h{=}2048\)、\(L{=}16\)、\(n_h{=}32\)、\(n_{kv}{=}8\)、\(d{=}64\)、\(I{=}8192\)、\(V{=}128256\),共享 embedding):每层注意力 \(2\cdot2048^2+2\cdot2048\cdot512 = 10.49\text{M}\),MLP \(3\cdot2048\cdot8192=50.33\text{M}\),16 层约 973M;embedding \(128256\times2048\approx262.7\text{M}\);合计约 1.24B。embedding 占了两成多——这就是为什么小模型几乎都共享 embedding。

实践中也可以直接用 transformers 的 LlamaConfig 实例化一个模型再数参数。下面的计算器按上面的公式算(门控 MLP、标准头维度、每层两个 norm、无 bias):

参数量计算器(Llama 式 dense Transformer)
总参数
embedding 占比
每层参数
头维度 d / GQA 组数
注意力MLPembeddingnorm

试试 GQA 消融里的对齐方法:在 1B 预设上把 KV 头数改成 32(MHA),总参数从 1.24B 涨到约 1.34B;再把层数降到 14,就回到约 1.20B。下一篇的 GQA 消融正是这样对齐参数量的(MHA 用 14 层,16 个 KV 头的 GQA 用 15 层)。预设的结构数字来自各模型公开的 config;Qwen 这类带 QKV bias 的模型,实际参数会比公式多一点点。

评测:用什么判断谁赢了

只看 loss 不够

第一反应是看 loss:它应当平滑下降、没有剧烈尖峰。对很多结构改动,loss 和下游表现相关性很好,单看 loss 就够了。但有四种情况 loss 会误导人:

所以需要更细的下游评测,覆盖知识、理解、推理以及你关心的其他领域。

好评测任务的四个标准

消融阶段的评测,要挑早期就有信号、不太嘈杂的任务。HF 在 FineTasks 和 FineWeb2 的工作里给出了四条标准,每条都有具体的量化方法:

标准含义怎么量化
单调性训得越久分数越高训练步数和分数之间的 Spearman 秩相关,要求所有训练 run 平均 ≥ 0.5
低噪声同设置不同随机种子,分数不应大幅波动多个种子在每一步的标准差取平均(avg-std);SNR = 30B token 时的平均分 / avg-std,目标 SNR > 20
高于随机不能长期停在随机水平随机基线 = 各题 1/选项数 之和;看所有模型最高分离基线多远
排序一致早期的优劣顺序在后期保持相邻两个 checkpoint 之间模型排名的 Kendall τ 的平均(只看 15B token 之后)

Spearman 秩相关 \(\rho_s\) 只看排名,所以分数非线性增长也能被识别为单调;Kendall τ 数的是「两两顺序一致的对数 − 不一致的对数」占总对数的比例。SNR 这一条最要紧:它直接决定你多大概率选错赢家。

题目怎么问:MCF、CF、FG

任务质量还取决于题目形式(怎么问模型)和打分方式(怎么算分)。三种常见形式:

MCF 多选格式 问:水的沸点? A. 50°C B. 100°C C. 150°C D. 0°C 答案: 比较 P(“A”)…P(“D”) 选项字母各是一个 token 要学会「选项字母 ↔ 内容」 训练早期常在随机水平 CF 完形格式 问:水的沸点? 答案:____ (选项不出现在 prompt 里) 逐个算 log P(选项|问题) “50°C” “100°C” … 按字符数归一化后取最大 只要求语言建模能力 早期就有信号 → 用于消融 FG 自由生成 问:水的沸点? 答: 贪心生成一段文本 抽取答案后判对错 需要大量潜在知识 短消融里通常太难
三种题目形式(示意)。

所以小消融用 MCF 或 CF。进一步,研究表明模型在训练早期很难做 MCF(OLMES、Du et al.、DataComp-LM),所以 CF 更适合早期信号。HF 的做法:小消融全部用 CF,正式训练里再加入 MCF(训练后期它信号更好)。对后训练模型,FG 才是主要形式。

MCF 为什么早期会停在随机水平?因为它要求模型额外学会一个「格式技能」:把选项内容和字母对应起来,再在字母上输出正确的概率。这个技能来得很晚:OLMES 发现 7B 模型在 MMLU 的 MCF 上要到约 500B token 才明显高于随机,SmolLM2 的 1.7B 模型要到 6T token。Du et al. 认为本质上是预训练 loss 要降到某个阈值以下,这个能力才会出现。

CF 怎么打分:长度归一化

CF 里每个选项是一段文本,log 概率是逐 token 相加的:

$$\log P(a_i\mid q)=\sum_{j=1}^{|a_i|}\log P\big(a_{i,j}\mid q, a_{i,\lt j}\big).$$

每多一个 token 就多加一个负数,所以不归一化的话模型会系统性偏好短的答案。FineTasks 比较了几种打分:

$$\text{acc}=\arg\max_i \log P(a_i|q),\qquad \text{acc\_char}=\arg\max_i \frac{\log P(a_i|q)}{\#\text{chars}(a_i)},$$ $$\text{acc\_token}=\arg\max_i \frac{\log P(a_i|q)}{\#\text{tokens}(a_i)},\qquad \text{acc\_pmi}=\arg\max_i \log\frac{P(a_i|q)}{P(a_i|u)},\ u=\text{“Answer:”}.$$

PMI 版本衡量「有了问题之后,这个选项变得多可能了多少」,对 MMLU 这类难任务有时是唯一高于随机的指标,但平均最弱、计算量也翻倍。HF 的消融用的是按字符数归一化的版本(acc_char):选「平均每个字符 log 概率最高」的选项。按字符而不按 token 归一化的好处是不依赖分词器——比较不同分词器时这一点很重要。

消融用的评测集

HF 的消融评测集沿用 FineWeb 消融的那组基准,去掉了太嘈杂的 SIQA;加上 GSM8K、HumanEval 测数学和代码,长上下文消融再加 RULER。为了加速,每个基准只评 1000 题(以多一点噪声为代价);GSM8K、HumanEval、RULER 在 3B 消融里全量评,1B 消融里不评。选择题全部用 CF。评测框架是 LightEval。

基准领域题型题数测什么
MMLU知识多选14k57 个学科的学术知识
ARC科学与推理多选7k小学科学推理
HellaSwag常识推理多选10k日常情境的叙事续写
WinoGrande常识推理二选一1.7k需要世界知识的代词消解
CommonSenseQA常识推理多选1.1k日常概念
OpenBookQA科学多选500小学科学事实 + 推理
PIQA物理常识二选一1.8k日常物体的物理常识
GSM8K数学自由生成1.3k小学数学应用题
HumanEval代码自由生成164根据 docstring 写 Python 函数

消融用什么数据?结构消融用一个固定的高质量混合(FineWeb-Edu 英文、FineMath 数学、Stack-Edu-Python 代码),因为结构上的结论应能外推到别的数据(包括多语言),数据保持简单即可。数据消融则反过来:固定结构,系统地改变数据配比。另外,差距很小时,算力允许就换几个种子重跑同一个消融,看结果波动多大。

评测噪声:你选对赢家的概率有多大

设想两个配置 A 和 B,B 在「真实」能力上比 A 高 \(\Delta\) 个百分点。你各训一次、在一个 \(n\) 题的基准上评一次,B 的分数高于 A 吗?不一定。分数里至少有两种噪声:

  1. 种子噪声:同样的配置换个随机种子(初始化、数据顺序),训出来的模型本身就不同。记标准差 \(\sigma_s\)(单位:准确率百分点)——这就是 FineTasks 里的 avg-std。
  2. 题目抽样噪声:基准只是题目总体的一个有限样本。单个模型的准确率估计方差是 \(p(1-p)/n\)(二项分布)。

比较两个模型时,题目抽样噪声有一个细节:两个模型做的是同一批题,它们在每道题上的对错是正相关的(难题大家都错)。记逐题对错的相关系数为 \(\rho\),配对差值的方差是

$$\operatorname{Var}\big(\hat p_B-\hat p_A\big)_{\text{题目}}=\frac{p_A(1-p_A)+p_B(1-p_B)-2\rho\sqrt{p_A(1-p_A)p_B(1-p_B)}}{n}\approx\frac{2p(1-p)(1-\rho)}{n}.$$

每个配置训 \(k\) 个种子取平均,种子噪声的方差除以 \(k\);但题目抽样噪声不会因为多训种子而下降(题目没变)。如果再把 \(m\) 个互相独立的基准取平均,两项都再除以 \(m\)(这是一个乐观的近似,真实的基准之间并不独立)。合起来,观察到的差值 \(D\) 近似服从

$$D\sim\mathcal N\!\left(\Delta,\ \sigma_D^2\right),\qquad \sigma_D^2=\frac{1}{m}\left(\frac{2\sigma_s^2}{k}+\frac{2p(1-p)(1-\rho)}{n}\right),$$

选对赢家的概率就是 \(P(D>0)=\Phi(\Delta/\sigma_D)\),其中 \(\Phi\) 是标准正态的累积分布函数。如果想要 95% 的把握(单侧),需要 \(\Delta \ge 1.645\,\sigma_D\)。

评测噪声模拟器:选对赢家的概率
差值的标准差 σD
选对赢家的概率
95% 把握需要的 Δ
题目噪声 / 种子噪声(方差比)

默认参数为示意。直方图是蒙特卡洛:每次独立抽种子噪声和(相关的)题目噪声,橙色部分是「选错了」的实验。

拖一拖就能看出几件事:

这也解释了 FineTasks 为什么要求 SNR > 20:如果某任务在 30B token 时平均分 50、avg-std 2.5,SNR 就是 20;这时 1 个点的差距相对于种子噪声只是 0.4σ,单次比较几乎是抛硬币。

扎实的消融还有另一层价值:正式训练出问题时(一定会出问题),你需要对每个决定都有把握,并能迅速找到哪些组件没测过。扎实的消融能节省调试时间。

消融的成本

消融很香,但要花 GPU 时间。SmolLM3 预训练阶段的完整算力账如下:

阶段GPU天数GPU 小时
正式预训练38430276,480
预训练消融1921569,120
中训练消融1921046,080
重启 / 调试384 / 1923 / 446,080
合计437,760

每行都可以验算:\(384\times30\times24=276{,}480\);\(192\times15\times24=69{,}120\);\(384\times3\times24+192\times4\times24=27{,}648+18{,}432=46{,}080\)。

关键数字:消融加调试共 161,280 GPU 小时,超过正式训练的一半(276,480)。整个开发过程跑了 100 多个消融:20 天预训练消融、10 天中训练消融、7 天从一个意外的训练问题中恢复。评测另算,略低于 1 万 GPU 小时:完整评测套件(英文、多语言、数学和代码)每个 checkpoint 约 1.5 GPU 小时,11T token 里每 10B token 评一次,加上大量消融;长上下文评测尤其贵,每次约 8 卡 1 小时。

这也提醒我们怎么读别人公布的训练成本:DeepSeek-V3 发布时全世界盯着它报告的 560 万美元训练成本,很多人把它当成了全部研发成本。实际上那只是最后一次训练;消融、失败的 run、调试这些看不见的研究成本要大得多。

所以预算要按「正式训练 + 消融 + 意外缓冲」来做。如果你追求 SOTA、要实现新结构、或者手上没有现成的配方,消融会是一个大的成本中心,而不是零头。下面这个计算器用标准的 \(6ND\) 估算(每个参数每个 token 约 6 次浮点运算:前向 2 次、反向 4 次,忽略注意力的额外开销):

$$\text{GPU 秒}=\frac{6ND}{\text{峰值 FLOP/s}\times\text{MFU}},\qquad \text{每卡吞吐}=\frac{\text{峰值}\times\text{MFU}}{6N}\ \text{tokens/s}.$$

MFU(model FLOPs utilization)是实际有效计算占硬件峰值的比例,SmolLM3 的正式训练约 30%。

消融预算计算器

正式训练:,,

推算每卡吞吐
单次消融墙钟
单次消融 GPU·h
全部消融 GPU·h
正式训练 GPU·h / 天数
消融 / 正式训练

3B 预设的 GPU 数为示意。只算 6ND,不含注意力 FLOPs、评测、故障停机和重启,所以是下限。1B 预设推算出每卡约 4 万 token/s、单次约 1.6 天,和实测的 42k token/s、一天半吻合;正式训练按 30% MFU、989 TFLOP/s 推算约 19 万 GPU·h,实际记账是 27.6 万(含停机和余量)。

Scaling law:多大的模型,训多少 token

「What」里最核心的是两个数:参数量 \(N\) 和训练 token 数 \(D\)。给定算力,钱该花在更大的模型上,还是更多的数据上?

从 Kaplan 到 Chinchilla

深度学习早期,训练并不太受算力约束:挑硬件能装下的最大模型和 batch,训到过拟合或数据用完为止。即便如此,人们已感觉到规模有用,比如 Hestness et al. 2017 就系统地展示了更大的模型训更久能带来可预测的收益。

LLM 时代我们总是受算力约束。Kaplan et al. 2020 证明语言模型的表现在多个数量级上都高度可预测,于是规模竞赛开始了。算力受限时最重要的问题是:钱花在更大的模型上,还是更多的数据上?Kaplan 的 scaling law 建议把多得多的算力给模型规模,这促成了「175B 参数、只训 300B token」的 GPT-3。

Hoffmann et al. 2022(Chinchilla)发现 Kaplan 的方法有问题:他们给不同 token 数的模型用了固定长度的 cosine 学习率调度,于是低估了数据量的作用(第三篇讲学习率调度时会再遇到这件事)。重新推导的结论是训练时长应该多得多——按 Chinchilla,175B 的 GPT-3 计算最优的训练量是 3.7T token。常被引用的经验比例是每个参数约 20 个 token。

训练算力的标准估算是

$$C\approx 6ND.$$

它的直觉:每个 token 的前向,每个参数参与一次乘加(2 FLOPs);反向要对激活和权重各求一次梯度(约 4 FLOPs)。所以 1B 模型训 100B token 的算力,是 2B 模型训 100B token 或 1B 模型训 200B token 的一半。

为什么大家都「过度训练」

Chinchilla 回答的是「给定训练算力,什么 \(N,D\) 让 loss 最低」,但没算训练之后的事:模型越大,推理越贵。如果模型会被大量使用(比如开源发布),用同样的训练算力去训一个更小的模型、训得远比 Chinchilla 建议的久,总成本反而更低(Sardana et al.;Harm de Vries 的 Go Smol or Go Home)。如今「过度训练」已是标准做法:Qwen3 系列号称训了 36T token。

选择过度训练,意味着 \(N\) 和 \(D\) 要自己定。SmolLM3 的做法:

  1. 先定 N:参考 Qwen3-4B、Gemma 3 4B、Llama 3.2 3B,3B 大到足以有推理、工具调用这类有意义的能力,又小到可以在本地快速推理。
  2. D 由算力决定:拿到 384 张 H100 约一个月,按约 30% MFU 能训 11T token。

反过来,也可以从 token 数推需要多少张 GPU。H100 上 BF16 矩阵乘实测大约能跑到 720 TFLOP/s(低于 989 的标称峰值),再乘 30% 的 MFU,训 4 周:

$$C=6\times3\times10^{9}\times11\times10^{12}=1.98\times10^{23}\ \text{FLOPs},$$ $$\#\text{GPU}=\frac{1.98\times10^{23}}{720\times10^{12}\times0.30\times4\ \text{周}\times604{,}800\ \text{s/周}}\approx 379.$$

最后拿了 384 张,和并行策略对得上,还留了一些应对节点故障和重启的余量。按 \(D/N\) 算,11T / 3B 约是每参数 3600 个 token,是 Chinchilla 比例的 180 倍左右。

即便不照搬,scaling law 仍有实际价值:它给实验设计提供基线(很多人用 Chinchilla 最优的设置做消融,HF 的 1B × 45B 也在这个量级附近),也能预测某个模型大小能不能达到目标表现。de Vries 还指出,模型缩小到某个「临界大小」以下,再缩就进入收益递减区。

实验守则

做消融的态度可以概括成一句话:保持多疑。具体是四条守则:

黄金原则:一旦有了好的设置,没有任何改动可以不经测试。否则你会花好几天调查一个神秘的性能下降,最后发现是几天前某个无关依赖的更新导致的。

SmolLM3 的答案

套到 SmolLM3 上,从目标到决策的链条是这样的:

目标 / 约束推出的决策详见
端侧运行(手机)3B dense;排除 MoE(所有专家都要放进内存)架构篇
约三个月工期、团队熟悉 dense不碰混合结构;Llama 式 baseline架构篇
多语言(6 种欧洲语言为主)Llama 3 的 128k 词表分词器;约 12% 多语言数据第三篇
长上下文(目标 128k)从一开始就用 NoPE 混合与文档内 mask架构篇
可延长训练、方便做中途实验WSD 学习率调度第三篇
384 张 H100 约一个月11T token(大幅过度训练)Scaling law

其中「长上下文」那一行最能说明为什么要先想 why:SmolLM2 在预训练末尾扩上下文时遇到了困难,所以 SmolLM3 从训练开始就做了有利于长上下文的结构选择,回头看这一步做对了。具体是哪些选择(NoPE 混合、文档内 mask),见架构篇。

参考与延伸阅读