训练一个千亿参数模型,在数学上只是优化一个交叉熵损失;在工程上,它同时是预算规划、数据科学、显存算术和通信拓扑的联合优化问题。这四个子问题彼此咬合:预算表决定数据量与参数量的配比,数据质量决定损失的下界,显存算术决定并行拓扑,而拓扑的通信效率决定那张千万美元的账单最终烧多久。本文按这个顺序逐层拆解。
一、Scaling Law:先有预算表,后有模型
1.1 两条定律的交锋
2020 年 Kaplan 等人的第一篇 Scaling Law 论文给出了损失随参数量的幂律衰减;2022 年 DeepMind 的 Chinchilla 修正了它------前者在小数据上外推,结论系统性偏科"堆参数"。Chinchilla 的参数化形式:
L(N,D)=E+ANα+BDβ\mathcal{L}(N, D) = E + \frac{A}{N^{\alpha}} + \frac{B}{D^{\beta}}L(N,D)=E+NαA+DβB
NNN 是参数量,DDD 是 Token 数,EEE 是语料的不可约熵(任何模型都不可能低于它),后两项分别是容量瓶颈与数据瓶颈。论文报告的拟合值量级:α≈0.34,β≈0.28\alpha \approx 0.34, \beta \approx 0.28α≈0.34,β≈0.28。
训练算力有个经典估算公式:前向 2ND2ND2ND,反向约两倍,合计 6ND6ND6ND FLOPs。于是问题变成:给定预算 CCC,怎么花最划算?拉格朗日数值求解:
python
import numpy as np
from scipy.optimize import minimize
E, A, alpha, B, beta = 1.69, 406.4, 0.34, 410.7, 0.28 # Chinchilla 拟合值
def loss(N, D):
return E + A / N**alpha + B / D**beta
def optimal_ND(C):
"""固定算力 C (FLOPs),求最优 (N, D)"""
def obj(logN):
N = np.exp(logN[0])
D = C / (6 * N) # 预算约束: 6ND = C
return loss(N, D)
res = minimize(obj, x0=[np.log(np.sqrt(C / 6))])
N = np.exp(res.x[0]); D = C / (6 * N)
return N, D, D / N # 返回 tokens/param 比值
# 三个量级的预算,比值都收敛在 ~20 附近:
for C in [1e21, 1e22, 1e23]:
N, D, ratio = optimal_ND(C)
print(f"C={C:.0e}: N={N:.1e}, D={D:.1e}, D/N={ratio:.0f}")
# 这就是"每个参数配 20 个 Token"的出处
这组公式的预测力是实打实的:GPT-3 用 175B 参数只喂了 300B Token(每参数 1.7 个),严重偏科容量项;Chinchilla 用 70B/1.4T(每参数 20 个)直接打平甚至反超了 280B 的 Gopher。同样的算力,配比对了就是一代人的差距。
1.2 后 Chinchilla 时代:推理成本改写最优解
Scaling Law 的隐含前提是"算力只在训练时花一次"。现实里推理成本随部署规模线性增长,于是 2023 年之后的公开配方普遍越过 Chinchilla 点过度训练小模型:
| 模型 | 参数 | Token | D/N 比值 |
|---|---|---|---|
| GPT-3 | 175B | 300B | 1.7 |
| Chinchilla | 70B | 1.4T | 20 |
| Llama-3 8B | 8B | 15T | 1875 |
逻辑很简单:训练成本是一次性的,推理成本是永续的。把 8B 模型喂到 1875 tokens/param,损失略高于同算力的"最优大模型",但部署侧省下的显存与带宽在生命周期内远超训练差价。这条推理最优(inference-optimal)scaling 的研究线,正是 Chinchilla 结论在产品经济学约束下的修正版。
二、数据管线:损失的下界在这里决定
模型只是拟合器,损失的理论下界 EEE 完全由数据决定。万亿 Token 语料的工业化管线大致是:抓取(Common Crawl)→ 正文抽取 → 质量过滤 → 去重 → 配比混合 → 退火收尾。
2.1 去重:MinHash + LSH
网页的自然重复率惊人,且重复数据有双重危害:浪费算力,以及制造记忆。Carlini 等人的可提取记忆研究表明,一条文本在语料中出现几十次后,模型会近乎逐字记住它------训练数据的隐私与版权问题直接由此而来。
精确去重用哈希表即可,难点是近似重复(换几个词的洗稿、模板化页面)。标准武器是 MinHash:用 kkk 个随机哈希函数对文档的 shingle 集合生成签名,两个文档的 Jaccard 相似度近似为签名重合率;再用 LSH 分带把候选对找出来:
python
import numpy as np
def shingles(text, n=3):
words = text.split()
return set(tuple(words[i:i+n]) for i in range(len(words)-n+1))
def minhash(sigs, k=128, seed=0):
rng = np.random.default_rng(seed)
a, b = rng.integers(1, 2**31, k), rng.integers(0, 2**31, k)
p = (1 << 61) - 1
return tuple(min((a[i]*h + b[i]) % p for h in map(hash, sigs))
for i in range(k))
def lsh_bands(sig, bands=16):
r = len(sig) // bands
return [hash(sig[i*r:(i+1)*r]) for i in range(bands)]
# 相似度 s 的两文档至少撞出一个 band 的概率 = 1-(1-s^r)^bands
# r=8, bands=16: s=0.5 → 检出率 0.5%; s=0.8 → 99.997%
# ------ 天然的阈值闸门: 明显不同的放过, 明显相似的拦下
分带参数(r×b=kr \times b = kr×b=k)就是相似度阈值的调节旋钮:上面注释里 s=0.5 与 s=0.8 的检出率对比,展示了这个机制如何把"模棱两可"的中间地带做窄。
2.2 质量与配比
过滤分两派:启发式(语言检测、符号/文字比、平均句长、Bad Word 列表)和分类器派(FineWeb-Edu 用一个微调小模型给"教育价值"打分,保留高分文档)。消融结果反复指向同一结论:数量级相同的语料,质量过滤带来的损失下降可以抵掉一个数量级的规模。
配比是第二个杠杆。代码数据占比 30% 级别的混合配比,在多个独立消融里都被验证能提升自然语言推理基准的成绩------代码的因果结构(输入-输出对、类型约束、测试用例)是天然的逻辑训练素材。多语言配比、数学语料、以及训练末段的高质量数据退火(learning-rate 收尾时切换到精选分布,Llama-3 与 Qwen 配方均有此步骤),共同构成"数据课程"。
污染(contamination)是配比的反面:基准测试集的泄漏会让评测虚高。工业界标准检测是 n-gram 重叠(典型 13-gram)加模糊匹配,训练前剔掉与评测集近邻的文档。评测污染至今没有彻底解法,这也是为什么盲测和事后新题基准(LiveBench 类)的地位在上升。
三、显存算术:16 字节/参数的铁律
混合精度训练下,AdamW 优化器的每参数开销是一笔精确的账:
python
def train_memory_gb(n_params, zero=0, gpus=1):
per = 2 + 2 + (4 + 4 + 4)
# bf16 参数 2B + bf16 梯度 2B
# + fp32 master 权重 4B + Adam m/v 各 4B
# ------ 合计 16 字节/参数(ZeRO 论文的经典口径)
states = per * n_params # 优化状态 + 参数 + 梯度
shard = {0: 8, 1: 4, 2: 2, 3: 1}[zero] # 切分比例
return (8 * n_params + (16 - 8) * n_params * shard / gpus) / 1024**3
print(f"7B, 单卡: {train_memory_gb(7e9, 0, 1):.0f} GB") # 112 GB
print(f"7B, 8卡Z2: {train_memory_gb(7e9, 2, 8):.0f} GB") # 17 GB
单卡训 7B,光状态就 112 GB------没有任何卡装得下(H100 是 80GB),这就是并行训练的物理起因。ZeRO 系列的三个阶段对应切分三样东西:
| 阶段 | 切分对象 | 通信代价 | 显存节省 |
|---|---|---|---|
| ZeRO-1 | 优化器状态 (8B/param) | 与数据并行持平 | 4× |
| ZeRO-2 | + 梯度 (2B) | 与数据并行持平 | 8× |
| ZeRO-3 / FSDP | + 参数 (2B) | 参数 all-gather,升高 | 线性于卡数 |
注意 ZeRO 的本质仍是数据并行------每张卡看到不同 batch,只是把"每卡全量持有副本"改成"用的时候临时聚合"。它解决显存,不解决单层计算量。单层算不动或单层放不下,要靠下面两类并行。
此外还有激活值:不含 checkpointing 时与 batch × seq_len × 层数 × 隐藏宽度成正比。梯度检查点 (gradient checkpointing)只保存每层入口,反向时重算层内前向,用约 33% 的时间换激活显存降到 \sqrt{} 量级------长上下文训练几乎必开。
四、并行拓扑:DP × TP × PP 的三维组合
4.1 三种正交的切法
数据并行(DP):每卡持完整模型副本,处理不同 batch,反向后 all-reduce 梯度。扩展吞吐但不扩展模型容量。
张量并行(TP) :把单个权矩阵切开。Transformer 层的标准切法是:注意力按头切、MLP 的第一个矩阵按列切第二个按行切(Megatron-LM 布局)。代价是每层前向 2 次 all-reduce、反向 2 次,通信密度极高,要求 NVLink 级带宽------所以TP 几乎从不跨机,单机 8 卡是常见上限。
流水线并行(PP):按层切,把 40 层分给 4 台机器,各持 10 层。微批次(microbatch)流过流水线,1F1B 调度控制显存水位。气泡占比是经典公式:
python
def bubble_fraction(stages, microbatches):
# 空泡: 流水线灌满与排空的时间
return (stages - 1) / (microbatches + stages - 1)
print(f"4 级 × 8 微批: {bubble_fraction(4, 8):.1%}") # 23%
print(f"4 级 × 64 微批: {bubble_fraction(4, 64):.1%}") # 4.4%
气泡靠加大微批次数摊薄,代价是慢的层拖住快的层、跨机通信只容忍低带宽(每微批只传边界激活)。PP 跨机、TP 机内、DP 最外层,这个三维组合(3D 并行)就是 GPT-3 时代到今天训练万亿参数模型的标准形态。
4.2 怎么选拓扑
经验法则浓缩成一张表:
| 约束 | 首选 | 原因 |
|---|---|---|
| 单层放不下 / 单层算太慢 | TP(机内) | 唯一切细单个算子的方案 |
| 机间带宽低 | PP | 每微批只传边界张量 |
| 只要吞吐 | DP | 梯度 all-reduce 一次 |
| 状态放不下 | ZeRO/FSDP | 切优化器状态 |
实际部署是四者的联立方程。DeepSpeed、Megatron-LM、FSDP 提供的是把这套拓扑声明化的工程封装,选错拓扑的表现非常具体:TP 跨机会让通信占比直接吞掉 MFU,PP 微批太少会让 GPU 大量空转。
衡量整条管线的终指标是 MFU(Model FLOPs Utilization)= 实测 FLOPs / (卡数 × 峰值 × 时间)。头部万亿级训练的公开数字在 40~50%------也就是说,有一半的峰值算力天然消耗在通信、等待和访存上,这可以视为分布式训练的物理折扣率。
五、训练稳定性:loss spike 是常态,不是事故
数月量级的训练中,损失曲线几乎必然会出几次尖峰。OPT 与 BLOOM 的公开训练日志都记录了大量 spike、硬件故障与回滚重启。现代配方的应对是成体系的:
数值格式:fp16 需要动态 loss scaling 防下溢,bf16 有 fp32 同宽的指数域、免 scaling------A100/H100 时代 bf16 已是默认。
稳定化正则:QK-Norm 把注意力的 Q、K 归一化,掐掉注意力 logits 的量纲漂移;z-loss 约束输出层 logsumexp 的量级:
python
def z_loss(logits):
Z = torch.logsumexp(logits.float(), dim=-1)
return 1e-3 * (Z ** 2).mean()
# PaLM 引入: logits 无界增长是训练后期 spike 的常见前兆
Spike 处置手册(综合各家日志的标准动作):梯度范数连续监控设告警 → 触发后先降学习率或跳过当前数据批次 → 尖峰持续则回滚到上一个健康 checkpoint → 事后排查是否特定数据(超长重复、乱码、异常分布的文档)引发,加入过滤规则。一次几十分钟的尖峰如果放任,可能烧掉数万美元算力并把曲线拖离最优轨迹。
优化器侧:AdamW 仍是主力,但 2024 年后 Muon(正交化动量)类优化器在同等 loss 下显著减少所需 Token 数,已在部分前沿训练(如 K2)里上岗------优化器公式本身仍是活跃的研究前线,而非 settled 的工程件。
六、边界:什么没有随规模自动到来
最后校准两个容易过度解读的叙事。
其一,涌现可能是度量幻象。Schaeffer 等人(2023)指出:许多"涌现能力"出现在非线性指标(精确匹配、多选题全对)上,换成连续指标(对数概率、token 级准确率)后曲线是平滑的。能力是渐进积累的,跃变发生在"衡量方式"而非"模型本身"------这个批判不推翻 scale 的价值,但提醒你别把基准的断崖当物理相变去做预算。
其二,MFU 的复利是真实的。从 GPT-3 时代到今天,同等损失所需算力持续下降:更好的数据管线、更优的并行实现、更稳的数值配方,每一项都在压低同一目标的成本。Scaling Law 描述的是"给定配方下损失的轨迹",而配方本身的斜率也在被优化------两条曲线相乘,才是这两年模型成本下降快于任何单一因子解释的原因。
收束成一张总表:
| 环节 | 核心问题 | 决定性的量 | 代表技术 |
|---|---|---|---|
| 预算规划 | 算力怎么花 | D/N 配比 | Chinchilla / 推理最优 scaling |
| 数据 | 损失下界 | 质量与去重率 | MinHash+LSH、分类器过滤、退火 |
| 显存 | 装不装得下 | 16 字节/参数 | ZeRO、FSDP、梯度检查点 |
| 拓扑 | 通信与气泡 | 带宽层级 | 机内 TP × 跨机 PP × 外层 DP |
| 稳定性 | 数月不崩 | spike 处置 | bf16、QK-Norm、z-loss、回滚 |
| 效率 | 峰值利用率 | MFU 40~50% | FlashAttention、调度优化、Muon |
预训练的终局判断可以一句话说清:这是把"更多算力"翻译成"更低损失"的翻译器,翻译精度由数据质量和工程效率共同决定------前者设上限,后者定单价。