第 9 课:预训练全流程

上一课我们备好了数据。这一课把这些 token 真正跑起来——做一次预训练要走哪些阶段、学习率怎么设、模型怎么切到几千张卡上、跑崩了怎么办、最后能跑出多少算力利用率。

🎯 学完这 6 步你将能够:
① 说清一次预训练的三个阶段与各自的 token 预算
② 解释学习率 warmup + cosine 的必要性,并算出衰减比例
③ 会估训练显存、会选并行策略、会处理 loss spike、会算 MFU
🗺 本节推理链(6 步:从"分几个阶段"到"算力利用率有多高")
1要把万亿级 token 真正训完,必须先回答"这事能不能一次跑完"——因为上下文长度、学习率与数据配比在训练不同时期的最优值不同,所以一次预训练通常拆成初始预训练、长上下文扩展、退火三个阶段。
↓
2既然分阶段跑,这就要求给每个阶段配好学习率曲线——因为训练初期参数是随机的、gradient(梯度)的方向很不可靠,于是要先 warmup(学习率预热)把学习率从小升到峰值,再用 cosine 衰减到接近 0,否则会一步走飞。
↓
3学习率定好了,但 405B 参数的模型根本装不进一张卡——因此必须把模型与数据切分到几千张卡上,这就要求按切分维度选择并行策略(数据并行 / 张量并行 / 流水线并行 / 上下文并行)——其中上下文并行是专为长序列的 attention 计算设计的。
↓
4切分之后要提效、更要防崩,这就要求把计算压到 BF16(一种训练常用的半精度浮点格式)以换取更快的矩阵乘(注意它省的是算力而非显存),并给 gradient 加上裁剪——否则一个异常批次就能把参数一次推飞。
↓
5上一步的裁剪只挡住了"梯度范数已超阈值"的批次;但训练长达数月,仍会有"范数没超、却与当前参数组合出坏结果"的批次,让与 logits(模型对词表里每个 token 打出的原始分数)相关的损失突然飙升——所以还要一道兜底:loss spike 的检测与回滚机制,从 spike 前的检查点重跑、跳过那几批数据。
↓
6【支链 · 效率维度】最后要给这次训练一个效率读数:因此引入 MFU(模型算力利用率 = 实际算力 ÷ 硬件峰值)——分子就是实际达到的模型 FLOPs/秒(FLOPs=一次浮点运算,FLOPs/s=每秒可做的浮点运算次数),于是才能判断这套并行与精度方案到底跑得好不好,而不是只看"跑了多少天"。
Pre-trainingLR ScheduleParallelismMixed PrecisionLoss SpikeMFU
1
一次预训练能不能一口气跑完,还是必须分成几个阶段?
提示:先想"短上下文训练"和"长上下文训练"的最优设置是不是同一套;再想训练最后阶段,数据配比和前面该不该一样。
▾
知识背景
Llama 3 的预训练分三个阶段(Meta Llama Team, arXiv:2407.21783):① 初始预训练——8K 上下文、15.6T token 中的绝大部分;② 长上下文扩展——分 6 个阶段把窗口从 8K 撑到 128K,累计约 800B token;③ 退火(annealing)——最后约 40M token,学习率降到 0,同时上采样高质量数据。三阶段的数据配比、上下文长度、学习率都不相同。

上一课我们把语料备好了。现在问:这些 token 能不能一口气训完?

因为不同训练阶段的最优设置并不相同,所以必须分阶段。可以把这类比成盖楼:打地基、砌主体、精装修三道工序用的材料和手法都不一样,硬要一次做完只会两头不讨好。

🧮 三阶段的 token 预算与设置差异
Step 1:三个阶段各自在做什么
阶段上下文长度token 预算关键设置
① 初始预训练8K绝大部分(15.6T 减去后面两段)高学习率、稳定为主
② 长上下文扩展8K → 128K(6 个子阶段)约 800B逐步拉长序列,配 RoPE(给每个 token 注入位置信息的位置编码)频率调整
③ 退火同②约 40M学习率降到 0,上采样高质量数据
Step 2:为什么不能合成一段
若强行合并会发生什么
一开始就用 128K 上下文注意力成本按序列长度平方增长,早期算力被大量浪费在长序列上
全程用同一套数据配比无法在末期"精准补课",推理与代码能力上不去
末尾不做退火学习率停在半空,最后一段数据的影响被稀释
三阶段的共同逻辑是:先学通用能力(量大、便宜),再学长上下文(针对性强、贵),最后用高质量数据精修(量小、影响最大)。
Step 3:退火为什么"量最小、影响最大"
阶段token 量占比学习率对最终权重的影响
初始预训练约 14.8T≈ 94.9%高决定能力底座
长上下文扩展约 800B≈ 5.1%逐步降低决定窗口能开多大
退火约 40M≈ 0.0003%(量级示意)衰减到 0决定"最后一公里"的风格与专项能力
占比极小却能显著影响最终表现——因为学习率越低,同一批数据对权重的改变方向越"定"。这也是"数据退火"成为标准工序的原因。
🎯 关键认知

预训练不是"一条曲线跑到底",而是三个目标不同的阶段串联:初始预训练打底座(便宜、量大)、长上下文扩展补窗口(贵、针对性强)、退火做精修(量极小、影响极大)。不理解分阶段,就会误以为"多喂数据就能变强"——实际上末期喂什么,往往比总量更重要。

AI 助教
👋 对预训练阶段有疑问?比如"长上下文扩展为什么要分 6 个子阶段?""退火的数据从哪来?"

我会用具体数字帮你算。
2
学习率该一路保持峰值不变,还是随训练进程变化?两端各会出什么问题?
提示:先想训练最开始,参数是随机的,此时算出的梯度方向可信吗?再想训练快结束时,如果学习率还很大,会发生什么。
▾
知识背景
Llama 3 405B 的学习率设置(arXiv:2407.21783):峰值 8×10⁻⁵,用 8,000 步线性 warmup(学习率预热)从 0 升到峰值,再用 cosine 调度在 1,200,000 步内衰减到 8×10⁻⁷。同族的 70B 峰值是 1.5×10⁻⁴、8B 是 3×10⁻⁴——模型越大,峰值学习率越小。warmup 的经典依据来自大批量训练实践(Goyal et al., arXiv:1706.02677)。

上一张卡片我们看到预训练分三阶段。每个阶段都要配一条学习率曲线,而这条曲线的形状是先升后降——为什么?

因为训练初期参数是随机初始化的,gradient(梯度)方向噪声极大,所以要用 warmup 把步长从小放大;因为训练末期已经接近最优解,所以要把步长收敛到接近 0。可以把这类比成开车:起步时缓慢加油(warmup),到站前必须减速(decay)——上来就地板油或者到站不刹车都会出事。

更早、更自然的做法是一步到位就用峰值学习率——但那恰好落在训练最脆弱的时刻:初始权重随机,早期 gradient(梯度)既大又乱,一次更新就能把参数推入「logits 饱和、范数爆掉」的区域,训练在最初几百步内直接 NaN 或发散(Goyal et al., arXiv:1706.02677 的 warmup 方案正是为此提出)。warmup 只用 8,000 步(占总步数 0.67%)就把这段危险期护了过去。

🧮 学习率曲线:三个数决定形状
Step 1:Llama 3 三档模型的峰值学习率
模型峰值学习率相对 405B说明
8B3 × 10⁻⁴3.75×小模型可用更大步长
70B1.5 × 10⁻⁴1.875×——
405B8 × 10⁻⁵1×越大越保守
规模越大、单步影响越广,因此峰值学习率必须更小——这也是"大模型更怕训崩"的量化体现。
Step 2:warmup 有多长、衰减到多小
参数数值占总步数比例
总训练步数1,200,000100%
warmup 步数8,000≈ 0.67%
峰值学习率8 × 10⁻⁵——
最终学习率8 × 10⁻⁷峰值的 1%
warmup 只占不到 1% 的步数,但缺了它往往直接训崩——因为它保护的是"最脆弱的最初几千步"。
Step 3:cosine 衰减到底降了多少
项目计算结果
学习率降幅8e-7 ÷ 8e-51%(降了 99%)
对照:线性衰减(同样端点)中点同为 50% 峰值cosine 在前 1/4 段更高、后 1/4 段更低
若不衰减(恒定 8e-5)末期步长过大损失在最优解附近来回震荡,收敛不到底
cosine 的形状特征:前 1/4 段比线性更高(前期学得快)、后 1/4 段比线性更低(末期收得住)——两条曲线在中点都是峰值的 50%。这是 cosine 比线性衰减更常用的原因。
🎯 关键认知

学习率曲线是"先探索、后收敛"的量化表达:warmup 用不到 1% 的步数换取训练不崩,cosine 把学习率从峰值压到 1% 换取收敛到最优解附近。三个数(峰值、warmup 步数、衰减终点)就决定了整条曲线——而峰值随模型变大而减小,是"规模越大越保守"的直接体现。

AI 助教
👋 对学习率有疑问?比如"warmup 8000 步是怎么定的?""为什么不用线性衰减?"

我会用具体数字帮你算。
3
模型装不进一张卡,该怎么切分到几千张卡上?
提示:先算一个 405B 模型光"权重 + 梯度 + 优化器状态"要多少显存,再想一张 80GB 的卡能装下多少。
▾
知识背景
大模型训练用多维并行(Megatron-LM, Shoeybi et al., arXiv:1909.08053;GPipe, Huang et al., arXiv:1811.06965):DP(数据并行,每卡一份模型、分不同数据)、TP(张量并行,把矩阵乘切成几块)、PP(流水线并行,把不同层放到不同卡)、CP(上下文并行,把长序列切开)。工业配置示例(MLPerf / NVIDIA NeMo):Llama 3.1 405B 被记为一组 TP=8 / PP=9 / CP=2 / DP=4 的并行度(全局批大小 2,304),但总卡数在 NVIDIA 官方文档之间不一致——有文档记 512 张 H100(https://docs.nvidia.com/dl-cuda-graph/examples/llama-31-405b.html),而并行度之积 8×9×2×4 = 576,两者对不上;本课不替它选定一个,引用时两处来源都要注明。

上一张卡片把学习率定好了。但还有一个更硬的问题:405B 参数的模型,一张卡装得下吗?

因为权重、梯度和优化器状态加起来有好几 TB,所以必须切分。可以把这类比成搬一张超大沙发进小公寓:要么拆成几块分别搬(张量并行),要么先把客厅、卧室分开搬(流水线并行),要么雇几组人各搬各的家具(数据并行)。

🧮 显存账:为什么必须切分
Step 1:405B 模型的训练显存构成
项目每参数字节405B 总计
fp16/BF16 权重2405e9 × 2 = 810 GB
fp16/BF16 梯度2405e9 × 2 = 810 GB
Adam 优化器状态(fp32 主权重 + 一阶 + 二阶矩)12405e9 × 12 = 4,860 GB
合计16≈ 6,480 GB(6.48 TB)
注意:这里还没算激活值。真实训练还要额外几百 GB 到几 TB 的临时缓冲。
Step 2:一张 80GB 的 H100 能装多少
项目计算结果
单卡显存——80 GB
仅装训练状态所需卡数6,480 ÷ 80≥ 81 张
加上激活与缓冲(经验上再留 50% 余量)6,480 × 1.5 ÷ 80≈ 122 张起
所以上千张卡不是"想跑快点",而是装下的最低要求。
Step 3:几种并行各切什么
策略切什么解决什么问题代价
DP 数据并行数据提高吞吐每卡都要存完整模型状态
TP 张量并行矩阵乘单层显存与算力分摊通信量最大(每层都要同步)
PP 流水线并行网络层按层分摊模型有空泡(流水线等待造成的空闲),需微批填充(把大批切成小块塞满流水线)
CP 上下文并行序列支撑超长上下文attention(注意力)通信增加
实践是组合使用:MLPerf / NVIDIA NeMo 的 405B 参考配置标注为 TP=8、PP=9、CP=2、DP=4。选择依据是通信开销——TP 优先放在同一台机器内(NVLink),PP 与 DP 跨机器。总卡数等于各并行维度之积(8×9×2×4 = 576);但 NVIDIA 某文档把同一组并行度记作 512 张(https://docs.nvidia.com/dl-cuda-graph/examples/llama-31-405b.html),与连乘结果对不上——这是官方文档之间自身不一致,引用时两处数字与来源都要写明,不要替它选定一个。
🎯 关键认知

并行策略不是"为了快",而是"为了装得下":405B 的训练状态就要 6.48 TB,单卡 80GB 至少需要 81 张卡,实际配置往往上千张。选哪种并行的核心判据是通信开销——通信量最大的张量并行放在机内高速互联,通信量小的数据并行放到跨机器。

AI 助教
👋 对并行策略有疑问?比如"为什么 TP 不能跨机器?""流水线空泡怎么消?"

我会用具体数字帮你算。
4
为什么要用低精度训练?梯度裁剪又在防什么?
提示:先想如果把每一步的参数都翻倍存,显存会变成几倍;再想如果某一批数据让梯度突然变得特别大,参数会被推到哪里去。
▾
知识背景
混合精度训练(Micikevicius et al., arXiv:1710.03740):前向与反向用 16 位(BF16 或 FP16——都是训练常用的半精度浮点格式)跑,同时保留一份 fp32 主权重做更新。Llama 3 405B 的训练用 BF16,MLPerf 参考实现进一步在计算密集算子用 FP8(8 位浮点:比 BF16 更激进的低精度格式,靠缩放因子把数值压进可表示范围)。梯度裁剪(gradient clipping, Pascanu et al., arXiv:1211.5063)把 gradient 的范数限制在阈值内,防止个别批次把参数推飞。

上一张卡片把模型切分开了。但显存仍然紧张,而且训练还有个更隐蔽的风险:某一步梯度爆炸——为什么这两个问题要一起解决?

因为降低精度既能省显存又能加速,所以用 BF16 混合精度;因为低精度下梯度更容易溢出,所以必须配梯度裁剪兜底。可以把这类比成开车既换轻量轮胎(省油),又加装限速器(防超速失控)——前者提高效率,后者保证不出事。

更早的做法是全程 fp32——但代价是双份:权重与梯度都要按 4 字节存(BF16 只需 2 字节),矩阵乘吞吐也低得多(H100 上 FP32 CUDA Core 峰值 67 TFLOPS、BF16 张量核 dense 989 TFLOPS,跨口径差约 15 倍;同为张量核口径时 TF32 约 495 TFLOPS,差距要小得多。来源:NVIDIA H100 官方规格)。不做裁剪也一样会翻车:正常批次梯度范数约 0.3,异常批次可达 50(均为示意值),不裁剪时后者的更新幅度是前者的约 167 倍;而把全局学习率调小来兜底,又会拖慢所有正常批次——裁剪只对异常批次收手,正是为了不动正常学习。

🧮 精度账:省了多少显存,裁掉了什么
Step 1:BF16 vs FP16 的关键差别
格式指数位尾数位能表示的最大值是否需要 loss scaling(损失缩放:把损失放大以避免小梯度下溢)
FP16510约 6.5 × 10⁴需要(容易溢出)
BF1687约 3.4 × 10³⁸不需要(指数范围与 fp32 一致)
FP32823约 3.4 × 10³⁸不需要
BF16 用"牺牲尾数精度"换"保留 fp32 的动态范围"——大模型训练最怕的是溢出而不是精度不够,所以 BF16 成了默认选择。
Step 2:显存省了多少
方案权重梯度优化器状态合计(字节/参数)
全程 fp32(Adam)444 + 4 = 816
BF16 混合精度22fp32 主权重 4 + 4 + 4 = 1216
反直觉但重要:混合精度省的是算力不是显存——权重与梯度各减半(省 4 字节),但要多存一份 fp32 主权重(加 4 字节),两者正好抵消,合计仍是 16 字节/参数。真正省显存的是 ZeRO(把优化器状态、梯度和参数分摊到不同卡上,避免每张卡各存一份)。
Step 3:梯度裁剪在防什么
情形梯度范数若裁剪到阈值 1.0后果对比
正常批次0.3(示意)不触发(0.3 < 1.0)正常更新
异常批次50(示意)缩放到 1.0(缩小 50 倍)避免一步走出有效区域
若裁剪到 1050缩放到 10(仅缩 5 倍)可能仍不够,模型仍有被推飞的风险
裁剪的本质是给单步更新设上界:它不改变正常批次的更新,只把异常批次的步长压回安全范围。阈值太松等于没裁,太紧会拖慢正常学习。
🎯 关键认知

低精度与梯度裁剪是一对:BF16 换的是更快的矩阵乘,而不是更小的显存(权重梯度各减半、但要多存 fp32 主权重,合计仍是 16 字节/参数),梯度裁剪则给单步更新设上界,防止个别异常批次把参数推飞。两者合起来,才让"几千张卡连续跑几个月"成为可能——任何一步坏掉,整轮训练的时间成本都极高。

AI 助教
👋 对混合精度有疑问?比如"FP8 训练靠谱吗?""loss scaling 具体怎么做?"

我会用具体数字帮你算。
5
训练到一半 loss 突然飙升,该怎么处理?
提示:先想 loss 飙升时那一步的参数还值不值得保留;再想如果直接从头重训成本有多高。
▾
知识背景
Loss spike(损失尖峰)在大规模训练中很常见。PaLM 540B 的论文记录(Chowdhery et al., arXiv:2204.02311):训练期间出现约 20 次 loss 尖峰,即使已启用梯度裁剪;它们的处理办法是"从尖峰前约 100 步的检查点重启,并跳过那附近约 200~500 个批次",之后 loss 恢复原趋势。论文把原因归为数据驱动(特定批次与当前参数值交互不好),而非系统性不稳定。

上一张卡片讲了精度与裁剪。但即便这些都做对,训练仍可能突然崩一下——loss 在几步之内飙升。该怎么处理?

因为尖峰往往是"坏批次 × 当前参数"的偶发组合——具体表现为某一批数据算出的 logits 异常,交叉熵损失随之跳高——所以处理思路不是改超参,而是回滚 + 跳过。可以把这类比成走山路遇到塌方:不用重修整条路(从头重训),退回到塌方前的位置(回滚检查点)、绕开那一段(跳过坏批次)就够了。

🧮 Spike 处置账:回滚 vs 重训
Step 1:PaLM 的实际处置数据
项目数值说明
尖峰次数约 20 次540B 训练全程
回滚步数约 100 步从尖峰前最近的检查点重启
跳过批次约 200~500 批绕开导致尖峰的数据段
是否启用梯度裁剪已启用却仍发生说明裁剪不是万能的
关键观察:尖峰出现在"高度不规则的间隔",有时发生在训练后期——说明它不是某个固定阶段的问题。
Step 2:为什么回滚比重训划算
方案要重算的量相对成本
从头重训全部 1,200,000 步1×(完整预训练成本)
回滚 100 步 + 跳过 500 批约 100 步的重复 + 跳过的数据约 0.008%
不回滚、继续训0但参数可能已进入坏区域,后续 loss 长期偏高
计算:100 ÷ 1,200,000 ≈ 0.0083%。这就是"检查点频率"背后的权衡——存得越密,回滚损失越小,但存储与 I/O 开销越大。
Step 3:怎么判断该回滚还是继续
现象判断动作
loss 飙升后几步内自行回落偶发波动不必回滚,继续观察
飙升后持续在高位不降参数已坏回滚检查点 + 跳过该数据段
同一数据段反复引发尖峰数据本身有问题回滚并永久剔除该数据
判据是"能否自行恢复":能恢复的是噪声,不能恢复的是损坏。这也意味着必须有自动化的 loss 监控,才能第一时间发现并处置。
🎯 关键认知

Loss spike 是大规模训练的常态而非异常——PaLM 540B 全程遇到约 20 次,且梯度裁剪已启用。标准处置是"回滚约 100 步 + 跳过约 200~500 批",成本仅约 0.008% 的一轮训练,远低于从头重训。所以工程上的关键不是"如何避免尖峰",而是"多快能发现、多近能回滚"——这直接决定了检查点策略。

AI 助教
👋 对 loss spike 有疑问?比如"怎么自动检测尖峰?""检查点该多密?"

我会用具体数字帮你算。
6
几千张卡跑几个月,实际用上了多少算力?
提示:先算这张卡理论上一秒能做多少浮点运算,再算实际训练摊到每张卡每秒做了多少。两者一比,就是答案。
▾
知识背景
MFU(Model FLOPs Utilization,模型算力利用率)这个度量由 PaLM 论文引入(Chowdhery et al., arXiv:2204.02311):MFU = 实际达到的模型 FLOPs/s ÷ 硬件理论峰值 FLOPs/s(FLOPs=一次浮点运算,FLOPs/s=每秒可做的浮点运算次数)。PaLM 540B 在 6,144 块 TPU v4 上达到 46.2% MFU。它与"硬件利用率"不同:MFU 只统计"模型真正需要的那些运算",重算(gradient checkpointing)带来的额外计算不计入分子。

前面五张卡片讲了阶段、学习率、并行、精度、故障处理。最后要回答一个问题:这套方案跑下来,到底用上了多少算力?

因为"跑了多少天"不能反映效率(卡多、模型小、效率低也能耗掉同样时间),所以需要一个归一化指标——MFU。可以把这类比成评价一辆货车的运输效率:不看它跑了多久,而看"载重 × 里程 ÷ 理论最大载重里程"——MFU 就是这个比值。

🧮 MFU 账:从公开数字反推利用率
Step 1:MFU 的定义
符号含义来源
分子实际达到的模型 FLOPs/s由 6ND ÷ 训练时长 ÷ 卡数 反推;厂商或论文通常直接报告 MFU
分母硬件理论峰值 FLOPs/s厂商规格(需注明精度口径)
MFU分子 ÷ 分母越高说明算力浪费越少
口径要点:分母必须写清是哪种精度、是否含稀疏加速——否则同一张卡算出的 MFU 能差 2 倍以上。
Step 2:用 Llama 3 405B 的公开数字反推
模型报告的 MFU硬件与口径
PaLM 540B46.2%6,144 TPU v4
Llama 3 405B约 38%~43%H100,BF16 口径(区间随并行与批配置而异,非同一配置)
反推一下这个区间对应多少算力:按 BF16 dense 峰值 989 TFLOPS 算,40% MFU ≈ 每卡 396 TFLOP/s,16,384 卡跑完 3.8e25 FLOPs 约需 68 天——与"几千张卡跑一两个月"的公开印象一致。
Step 3:剩下的算力去哪了
损耗项大致影响能否消除
通信等待(TP/PP/DP 同步)主要损耗部分(重叠通信与计算)
流水线空泡随 PP 级数增大部分(增加微批、交错调度)
重算(gradient checkpointing)多算约 30% 前向不计入 MFU 分子,但真实耗时增加
激活与缓冲的访存次要部分
故障回滚(loss spike 等)少量不可完全消除
注意最后一行与上一张卡片的联系:每次回滚都要重算一段,直接拉低整体效率——这就是"稳定性"也能换算成"算力成本"的地方。
🎯 关键认知

MFU 是衡量"这次预训练跑得好不好"的归一化读尺:PaLM 540B 是 46.2%,Llama 3 405B 论文自报约 38%~43%(BF16 口径)。剩下的算力损耗主要来自通信、流水线空泡与故障回滚。所以"能不能训成"之外,"能不能把 MFU 做上去"才是工程能力的直接体现——同一笔预算,MFU 差 10 个百分点就是十天级别的差距。

AI 助教
👋 对 MFU 有疑问?比如"MFU 和 GPU 利用率有什么区别?""怎么把 MFU 提上去?"

我会用具体数字帮你算。