从0训练LLM · 现代大模型体系 阅读 + 实验 ≈ 30 分钟 页内实验 ×1
C7 数据:从哪来、怎么洗、怎么配 第 6 课

最好的数据什么时候喂?

退火与 mid-training
C5 留下的问题在这里兑现:loss 的大幅下降集中在学习率衰减段,所以最好的数据应该留到那时加量——这就是退火,再往后发展成独立的 mid-training 阶段。同叫「退火」,Qwen3 的高质量阶段占 13.9%,Llama 3 只有最后 40M token,差 5 个数量级。
❓

本课一问:数据洗好了、配比定了、不够的也补上了。最后一个问题:最好的那部分数据,应该在训练的哪个阶段喂?

这一课先不碰:长上下文扩展里位置编码怎么改(C2 第 5 课、C11);后训练(C12)。

从已有出发:C5 留下的问题

从已有出发 · 累计数据流 点已学环节看形状与参数
解码层

模型这条流水线上,本章始终停在最左边的「文字」一格;把这一格展开,就是下面这条数据管线:

从已有出发 · 数据管线 本课其他环节点环节看它做什么、真实数字

回扣 C5:讲 WSD(warmup-stable-decay)时有一个现象——学习率进入最后的衰减段,loss 会快速下降。当时留了一个问题:衰减段该喂什么数据?这一课兑现它。

贯穿任务里就有这个现象的真实记录。第 5 课结尾留下的那个疑问:同样的数据,400 步的基线在 6.5 个 epoch 时 val loss 4.626,比 1,500 步的 run 在 4.9 个 epoch 时的最低点 4.771 还低。两者都是 cosine 调度、峰值 0.003:1,500 步的 run 在第 300 步时学习率还有 2.87e-3,基线在第 400 步时已经降到 3.00e-4。val loss 的一大段下降,是学习率降下来之后才出现的。

先自己设计:全程均匀打乱

最朴素的做法:所有数据(包括最好的那部分)倒进一个池子均匀打乱,训练全程随机抽。

  1. ① 朴素方案
  2. ② 它在哪失败
  3. ③ 改进方案
朴素方案全程均匀打乱:最好的数据平均撒在每一步

假设衰减段占训练的 f。好数据均匀分布在全程,落在衰减段里的只有 f:

  • f = 10%(MiniCPM 发现衰减段约占 10% 就够,2.5% 不够)时,只有 10% 的好数据落在衰减段;
  • 其余 90% 在学习率还高的阶段被「用过」了。

MiniCPM 的实验:在衰减段混入高质量数据与 SFT 数据,比只在 SFT 阶段才加入这些数据效果更好 。

WSD 学习率调度(回扣 C5)· 以 SmolLM3 的取法为例
η(t) = → →
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
C5 讲的是这条曲线的形状;这一课讲的是在它下面铺什么数据。下面的组件把两者画在同一条 token 轴上。

改进:从退火到独立的 mid-training

退火一开始只是「衰减段换一换配比」,后来越做越大,变成了预训练与后训练之间一个独立的阶段,叫 mid-training。它通常同时做几件事:提高数学、代码、推理数据的比例;加入合成数据;把上下文拉长。

真数据 · 各家的分阶段配比与学习率画在同一条 token 轴上

🎯

试三件事:① 默认的 SmolLM3:看学习率(绿线)开始下降的位置,正好对上第三阶段——数学从 3% 加到 13%、代码从 12% 加到 24%;② 切到 Llama 3 405B,在线性横轴上找退火段(找不到),再点「对数:距结束还剩多少」,那 40M token 才出现;读统计条里它和 Qwen3 第二阶段差几个数量级;③ 切到 Qwen3 与 GLM-5,读下方说明:哪些数字原文给了、哪些没给,没给的组件就不画。

同一个词,量级差异巨大(实算):

模型「后期高质量阶段」占训练的比例
Qwen3第二阶段约 5T 高质量 token(STEM、代码、推理、合成比例上调,学习率加快衰减),总共 36T5 ÷ 36 = 13.9%
SmolLM3第三阶段 10T → 11.1T(学习率线性降到 0 的那一段)1.1 ÷ 11.1 = 9.9%
OLMo 2mid-training(Dolmino 配比,学习率线性降到 0)训练算力的 5–10%(原文按 FLOPs 算)
Llama 3 405B最后 40M token 线性退火到 0,上采样最高质量来源,并对检查点取平均40M ÷ 15.6T = 2.6e-6

Qwen3 与 Llama 3 相差约 5 个数量级。同叫「退火」,一个是训练的七分之一,一个是最后几步;读技术报告时,「退火」两个字本身不提供配方信息,要看它的 token 数、学习率和数据 。

OLMo 2 还多做了一步:用不同的数据顺序跑几次 mid-training,再把得到的模型参数取平均(「model soup」)——7B 是 3 次、每次 50B token;13B 与 32B 是 3 次 100B 加 1 次 300B,四个一起平均。合并后的模型总是不差于其中任何一个 。

长上下文也在这个阶段加(旧版 M7 迁入)

把上下文拉长是 mid-training 的另一项主要任务:长序列的注意力计算贵,所以先用短序列训完大部分 token,最后才用长序列训一小段。

预训练数据的演进:每一代都被上一代的某个真数字逼出来
  1. 起点 有多少用多少:原始网页直接进训练 Common Crawl 原始快照
    解决了量几乎无限:Common Crawl 定期抓取全网,FineWeb 用了 96 个快照。
    卡在WET 纯文本里样板和菜单太多(FineWeb §3.2);我们的原始文件不还原硬换行就跑 C4 句末规则,整本书只剩 17.02% 的字。
  2. 第一代 让人当过滤器:只取被点过赞的链接 GPT-2 WebText,2019
    解决了Reddit 上至少 3 karma 的外链,4,500 万个链接,清洗后约 800 万文档、40 GB。
    卡在量太小:C6 算出的需求是十几 T token;而且只覆盖被分享过的那一小部分网页。
  3. 第二代 只看长相的规则过滤 C4 2019 · Gopher 2021
    解决了句末标点、词数、平均词长、停用词、重复行……便宜,能在全网快照上跑。
    卡在绑语言、绑求值单位:英文原版在整本《三國志演義》3,697 段上通过 0 段;C4 句末标点规则删掉约 30% 的 token,FineWeb 最后没用它。
  4. 第二代 近重复去重:MinHash + 分桶 Broder 1997 → Lee 2021 → FineWeb 2024
    解决了C4 里一句话重复 61,036 次;去重后模型复述训练文本的频率降到 1/10。MinHash 把两两比较变成查桶。
    卡在去得越狠未必越好:跨 96 个快照全局去重只剩 4T,训不出更好的模型;每快照独立去重留 20T,才追平 RefinedWeb。
  5. 第三代 让模型给数据打分 CCNet 2019 · GPT-3 2020 → FineWeb-Edu、DCLM 2024
    解决了判断「有没有营养」:FineWeb-Edu 让 Llama-3-70B 标 46 万页、蒸馏成分类器,MMLU 33% → 37%。
    卡在参考语料的困惑度偏向「像参考」:我们模型写的胡话困惑度 93.417,低于真原文 273.209;阈值 3 删掉 92%,长程训练不够用。
  6. 第四代 配比:从手工权重到代理模型搜索 The Pile 2020 → DoReMi 2023
    解决了DoReMi 用 280M 代理模型搜域权重,8B 模型下游平均 +6.5 个点,达到基线快 2.6 倍。
    卡在权重一变就要重复:按 DoReMi 的权重花完 The Pile 的有效体量,YouTube 字幕要走约 16.9 遍(按字节近似 token,只看量级)。
  7. 第五代 数据墙:重复与合成 Muennighoff 2023 · WRAP 2024 · Phi-4 2024
    解决了重复 4 遍以内几乎等于新数据;改写真实网页(WRAP)预训练约快 3 倍;Phi-4 约 10T token 里合成占 40%。
    卡在让模型只吃自己生成的数据,分布的尾巴一代代消失:在三国演义真实字频上重采样,只出现 1 次的字每一代有约 36.8% 的概率丢掉,丢了就回不来。
  8. 第六代 按时机投放:退火 → mid-training MiniCPM、Llama 3 2024 → OLMo 2、Qwen3、GLM-5 你在这里
    解决了最好的数据放到学习率衰减段(C5 的 WSD)加量;再发展成独立阶段,顺便拉长上下文。
    卡在同名不同方:Qwen3 的高质量阶段占 13.9%,Llama 3 的退火只占 2.6e-6;收益与学习率调度缠在一起,很难单独归因。
数字口径:我们语料上的数字由 gen_c07_corpus.py 在《三國志演義》上实算(c07-*.json);FineWeb、GPT-2 数字出自本地 PDF;DoReMi、Muennighoff、WRAP、Phi-4、Qwen3、Llama 3 出自原文(核实记录见设计卡);「约 16.9 遍」「36.8%」「13.9%」在构建时现算。
⚠

常见误解一:「退火是一种固定配方。」Qwen3 的高质量阶段占 13.9%,Llama 3 的退火只占 2.6e-6,差 5 个数量级。术语不等于配方。

常见误解二:「mid-training 是 OLMo 2 发明的词。」OLMo 2 自己说这个词取自 Phi-3 与 OpenAI 的用法;目前找不到唯一的首创者(R4 D6)。

常见误解三:「由易到难的课程学习(curriculum learning)是预训练的主流。」Bengio 等人 2009 年提出的课程学习是「先易后难」;现代预训练的做法是「高质量后置 + 学习率衰减」,排序依据是质量而不是难度,而且收益和学习率调度缠在一起,很难单独归因(第 5 课的项目曲线就是一个例子)。

🔍 为什么衰减段 loss 会骤降?

一种常见的解释(理论动机,不是证明):学习率高时,参数在 loss 地形的「河谷」里来回震荡,平均位置已经不错,但单步的位置离谷底有一段距离;学习率降下来,震荡幅度变小,参数沉到谷底附近,loss 随之快速下降。在这个图景里,衰减段喂的数据决定了参数「沉到哪一个谷底」——所以这一段的数据对最终模型的影响特别大。这个图景能解释现象,但没有被证明是唯一原因。

证据三问

问本课的回答
① 它解决什么问题?让最好的数据在最「有用」的时候出现:学习率衰减、loss 大幅下降的那一段
② 数学上为什么可能有效?只有理论动机:衰减段决定参数最终落在哪里(见 Dig)
③ 实验上为什么选了它?MiniCPM 的衰减段实验、Llama 3 的退火评估(8B 上 GSM8k +24.0%)、OLMo 2 与 Qwen3 的分阶段配方

一句话

📌

最好的数据留到学习率往下走的那一段再加量;同叫「退火」,Qwen3 的高质量阶段占 13.9%,Llama 3 只有最后 40M token——读报告要看数字,不要看名字。

🚦

先停在这里:记住「衰减段决定落点,所以好数据后置」与「术语不等于配方」。
再深一层:读 MiniCPM 博客里衰减段长度的对照实验,想一想为什么 2.5% 不够、10% 就够;再对照上面 SmolLM3 的配方,它的第三阶段恰好也是最后 10%。

下一个缺口

数据和配方都齐了,模型放大以后,为什么训练会炸? → 进入 C8 稳定性:放大后为什么会炸

本章的收尾在实验课:把《三國志演義》当成一次网页快照,完整跑一遍前六课的管线。

你可能会问