同一个 7B 模型,只算权重是 14 GB,算模型状态是 112 GB,算激活又是 52.08 GB;三个答案都对,因为它们属于三本账。 这页把参数量、模型状态、激活、FLOPs拆成四组公式,每组标清单位、适用条件和来源,再用一个计算器把 config 变成可对账的估算。
训练显存不是“参数量 × 一个系数”,而是模型状态 + 激活 + 临时 buffer。模型状态里,bf16 混合精度 Adam 的五个字节块是 2 + 2 + 4 + 4 + 4 = 16 B/参数;1.5B 的 GPT-2 光这一项就要 24 GB,而 fp16 权重只有 3 GB。
算力也不是一个系数:Kaplan 的 6N/token 是模型 FLOPs(前向 2N + 反向 4N),不含 embedding、长上下文注意力项和重算; 全量重算的硬件口径约 8N/token,selective recompute 的硬件/模型倍数约 1 + s/(6h),即只多 s/(6h)。三者不能混用。
参数量和激活都能从 config 直接复算:Megatron Eq 2 用 L/h/V/s 数参数,Korthikanti Eq 2/4/6 用
s/b/h/L/a/t 数激活。每个公式都带条件;条件一换,系数就换。下面的计算器把条件变成输入,输出一张能逐项对账的账单。
同一个 7B 模型,只算权重、算模型状态、算激活、算算力,会得到四个不同的数量级。
先看一个具体问题:7B 模型,bf16 混合精度 Adam,单卡 80GB,batch 能放多大?
7B × 2 B = 14 GB,看起来余量很大。7B × 16 B = 112 GB,单卡已经放不下。L=32、h=4096、s=4096、b=4、TP=8,Korthikanti Eq 5 给 52.08 GB;模型状态切到 TP=8 后是 14.00 GB,合计 66.08 GB,才勉强放进 80GB。6N = 42.00 GFLOPs/token;这个数只回答“算多少”,不回答“放不放得下”。四个答案都对,只是分别属于四本账:权重、模型状态、激活、算力。容量规划的错误,通常不是公式算错,而是把一本账的结论套到了另一本上。
更麻烦的是,每本账都有自己的适用条件。16 B/参数只对 bf16 混合精度 Adam 成立;6N/token只对 dense、短上下文、无重算成立;34sbhL/t只对 TP+SP+selective recompute 成立。条件一换,系数就换。
| 问题 | 用的账 | 结果 | 条件 |
|---|---|---|---|
| 权重占多少 | 2N | 14 GB | bf16 |
| 训练状态占多少 | 16N | 112 GB | bf16 混合 Adam;未切分 |
| 激活占多少 | Korthikanti Eq 5 | 52.08 GB | L=32, h=4096, s=4096, b=4, TP=8, 2 B/elem |
| 训练算力多少 | 6N | 42.00 GFLOPs/token | dense、短上下文、无重算 |
常见公式不是错,是“只在这个精度、这个并行、这个重算策略下”才对。
16 B/参数:只算模型状态,且是 bf16 混合精度 Adam、无 ZeRO/offload。它不含激活,也不含通信 buffer。
6ND:只算模型 FLOPs,且 N 不含 embedding、上下文项小、无重算。它不是硬件 FLOPs,也不是墙钟时间。
34sbhL/t:只算 transformer 层激活,且是 TP+SP+selective recompute、2 B/elem。它不含 embedding/output、碎片和 workspace。
torch.cuda.max_memory_allocated() 给 allocator 实际分配出去的峰值;max_memory_reserved() 还包含缓存块,两者之差可以粗略看成碎片/缓存。
nvidia-smi 还包含其他进程、CUDA context 和驱动开销;profiler 能看到 GEMM/attention 的临时 workspace。
代价:必须先跑起来;换一个 batch、seq、TP 就要重测;单点实测不能告诉你“下一档配置会不会爆”。
不发明新系数:参数用 Megatron Eq 2,模型状态用 ZeRO 的 16Ψ,激活用 Korthikanti Eq 2/4/6,FLOPs 用 Kaplan 的 6N。每个公式后面写清楚“在什么条件下成立”,再用 §05 的计算器把这些条件变成输入。
这样做的代价是:估算不再是“一个系数乘到底”,而是四项相加;好处是每一项都能对账,也能看出哪一项在主导。
每个公式只在括号里的条件成立;先把条件记住,再记系数。
一个 dense decoder layer,在 ffn=4h、MHA、bias 和 LayerNorm 都算上的标准配置下:attention 的 Q/K/V/O 四个 h×h 矩阵是 4h²;MLP 的两个 h×4h 矩阵是 8h²;合计 12h²。每层还有约 13h 的 bias/LayerNorm 零头,L 层就是 L(12h²+13h)。再加词嵌入 Vh 和可训练位置编码 sh(用 RoPE 时没有 sh 项)。
把公式展开看,三项分别是:12Lh² 的 attention+MLP 主干、13Lh 的 bias/LayerNorm 零头、(V+s)h 的 embedding/位置编码。h 越大,第一项越占主导;词表越大,Vh 越不能忽略。
Megatron-Core 的字段能一一对上:num_layers(megatron/core/transformer/transformer_config.py:72)、hidden_size(:170)、num_attention_heads(:173)、ffn_hidden_size(:211,缺省 4*hidden_size 在 :1957–1958)、vocab_size(megatron/core/models/gpt/gpt_model.py:105,赋值在 :167)。
heads 不进 P 的主干。 MHA 把 h 切成 a 份,Q/K/V/O 仍是 h×h;头数只改变 attention 的 FLOPs 和激活项 5as/h。GQA/MQA 会让 K/V 投影变小,Eq 2 会高估;MoE 只激活部分 expert,Eq 2 也不适用。
注意一个源码层面的分叉:GPTModel 类的默认参数是 share_embeddings_and_output_weights=False(gpt_model.py:112),而训练 CLI 的默认是 tied(megatron/training/argument_utils.py:650 把 not args.untie_embeddings_and_output_weights 传进去)。Eq 2 只数了一次 Vh,对应 tied;如果 untied,输出投影再加一个 Vh。
一个 token 过一遍模型,每个参数参与一次乘加,按 2 FLOPs 计;所以前向约 2N。反向要算对权重和对输入的梯度,约是前向的 2 倍,即 4N;训练合计约 6N。乘以 token 数 D,就是 6ND。
Kaplan 的精确前向式是 C_forward ≈ 2N + 2 n_layer n_ctx d_model(Eq 2.2;标准配置 d_model = d_attn = h)。第二项是 attention 的 QKᵀ/AV,随 seq 线性增长;论文的条件是 d_model > n_ctx/12,此时它占 n_ctx/(12 d_model)。这个比例不是 0:s=32768、h=4096 时已经是 66.7%,长上下文必须单独加。
还要区分三个系数:Kaplan 的 6N 是模型 FLOPs,不含重算;Megatron Eq 3 写 F = 96Bslh²(...),其中 96 = 8×12,按文中说明包含 activation recomputation 的额外前向,所以是 8N/token 的硬件口径;Korthikanti Eq 9 的 selective recompute 只重算 attention,硬件/模型约 1 + s/(6h)。三个数不能混用。
bf16 混合精度 Adam 的模型状态不是“参数量 × 2”,而是五项相加:
| 项 | 字节/参数 | 作用 |
|---|---|---|
| bf16 参数 | 2 | 前向/反向计算 |
| bf16 梯度 | 2 | 与参数同精度 |
| fp32 master | 4 | 稳定更新 |
| Adam m | 4 | 一阶动量 |
| Adam v | 4 | 二阶动量 |
| 合计 | 16 | 2+2+4+4+4 |
变体要单独记账:SGD+momentum 是 2+2+4+4 = 12 B;fp32 Adam 是 4+4+4+4 = 16 B(总数一样,构成不同);如果梯度也存 fp32(有的库这么做,Megatron 的 precision-aware optimizer 也提供 --main-grads-dtype fp32,arguments.py:3578),就是 2+4+4+4+4 = 18 B。不要拿 16Ψ 去套所有优化器。
在切分之前,模型状态与 N 成正比:1.5B → 24 GB(论文原例;fp16 权重只要 3 GB)、7B → 112 GB、70B → 1,120 GB、175B → 2,800 GB。这就是为什么 175B 光模型状态就需要 2.8 TB 的聚合容量;单卡放不放得下,取决于后面怎么切。
切分时,三项各走各的维度:TP 把每个权重/梯度/优化器张量按 t 切;PP 把层按 p 切;ZeRO-1/2/3 在 DP 维度上分别切优化器状态、梯度、参数。三者都完全分片且不复制时,一阶近似是 16Ψ/(t·p·d);只开 ZeRO-1 时只有 KΨ 被 d 除,不能直接套 16Ψ/d。推导见 ZeRO 页,这里不再重复。
激活随 batch 线性增长,随 seq 至少线性(attention 项是 s²);它是四本账里唯一随 b/s 增长的显存项(FLOPs 总量也随 token 数增长,但那是算力账,不占显存)。Korthikanti et al. 把前向要留给反向的每个张量按字节数出来,假设 2 B/element(bf16/fp16)。
把四个式子放在一起看:TP 切的是每层的宽度,SP 切的是 seq 维的复制项,PP 切的是层数但首 stage 仍按 L 层计,selective recompute 去掉 attention 的 s² 项。 这就是为什么长上下文下 activation 会先爆:5as/h 随 s 线性涨,它相对 34 的占比是 5as/(34h),s 越大越占主导。
GPT-3 的 5as/h = 80,MT-NLG 的 5as/h = 64(§5);所以 selective recompute 对两者的激活节省分别是 70.18% 和 65.31%(34/(34+80)、34/(34+64))。这两个数在 §06 会和论文的 70%/65% 对照。
同一页里出现 bytes、GB、GiB、params、FLOPs,先统一口径,再做加减。
| 项目 | 公式 | 单位 | 适用条件 | 出处 |
|---|---|---|---|---|
| 参数量(dense, tied) | P = 12Lh²(1 + 13/(12h) + (V+s)/(12Lh)) |
params | ffn=4h、MHA、tied embedding、learned pos;不含 GQA/MoE | Megatron Eq 2 |
| 前向 FLOPs / token | 2N + 2L·s·d_model |
FLOPs | N 不含 embedding;d_model=d_attn=h;上下文项未丢 | Kaplan Eq 2.2 |
| 训练 FLOPs / token | 6N |
FLOPs | dense、s≪12h、无重算;模型口径 | Kaplan §2.1 |
| 推理 FLOPs / token | 2N |
FLOPs | forward only、s≪12h、N 不含 embedding/LM head、不计 KV 读写 | Kaplan Eq 2.2(forward;本页推得) |
| 模型状态 | 16Ψ |
bytes | bf16 混合 Adam、fp32 master、梯度 bf16 | ZeRO §3.1 |
| 激活 / 层(TP only) | s b h (10 + 24/t + 5as/(ht)) |
bytes | 2 B/elem、无 SP、无重算 | Korthikanti Eq 2 |
| 激活总量(TP+SP) | s b h L / t (34 + 5as/h) |
bytes | 2 B/elem、SP、无重算;首 stage 上界 | Eq 5(Eq 4×L) |
| 激活总量(selective) | 34 s b h L / t |
bytes | TP+SP+selective recompute | Eq 6 |
| 激活总量(full recompute) | 2 s b h L |
bytes | 只存层输入;不除 t(除 t 需额外 all-gather) | Table 2 / §5 |
| 模型状态切分(一阶) | 16Ψ / (t·p·d) |
bytes | TP×PP×ZeRO-3 全分片、无复制、无 offload | ZeRO §3 / Fig.1 |
表里的 N 和 Ψ 都指参数量,但口径不同:Kaplan 的 N 不含 embedding;Megatron 的 P 含 (V+s)h;ZeRO 的 Ψ 通常指全部参数。混用会让 FLOPs 和状态账对不上。
本页一律用十进制:1 GB = 10^9 B。1 GiB = 2^30 B = 1,073,741,824 B;同一个字节数用 GiB 表示会小 6.87%,反过来说 1 GiB 比 1 GB 大 7.37%。论文、框架、云厂商的“80GB”有时指 GiB,有时指 GB;对账前先看单位。
另一个口径是 N:Kaplan 的 N 不含 vocabulary/positional embeddings(§1.3);Megatron Eq 2 的 P 含 (V+s)h。对 175B,这一项约 0.65B,占 0.38%;小模型或大词表时不可忽略。把 Eq 2 的 P 当作 N 代进 6N,会把 embedding 也算进 FLOPs,结果偏高。
六步把 L/h/a/V/s/b/t/p 变成参数量、模型状态、激活和 FLOPs;每个输出都能回指一个公式。
L, h, a, V, s;从训练脚本取 b, t, p, d 和精度/优化器。N_config,和手填 N 对比;差异大时先检查 ffn 是否 4h、是否 GQA/MoE、embedding 是否 tied。bytes_per_param × N / (t·p);开 ZeRO-3/FSDP 再除以 d。6N × tokens;tokens/step = b·s·d·grad_accum。max_memory_allocated 校准,差额归到 §07 的边界项。下面把六步做成可调的计算器。默认值与 Figure 5-1 一致;切换精度/优化器会改每参数字节,切换激活策略会在 Eq 2、Eq 5、Eq 6 之间换公式。改动任何滑块,五项输出和显存条会一起更新。
结论:7B 在 TP=8、b=4 时,模型状态 14.00 GB、激活 52.08 GB,合计 66.08 GB,80GB 卡还剩 13.92 GB。这个余量不大;b=8 会把激活翻倍到 104.15 GB,直接超出。公式默认 ffn=4h、MHA、tied embedding;实际模型换 ffn 或 GQA,要重算 config N。
简化与未覆盖:只算 transformer 层激活,不含 embedding/output、cross-entropy logits;模型状态按完美切分;GB 用十进制;没有碎片、通信 buffer、workspace、交错调度因子。JS 与手算同公式,输出保留两位小数。
结论:175B 在 TP=8、PP=8、b=1 时,状态 43.75 GB + 激活 34.43 GB = 78.18 GB,只剩 1.82 GB;selective recompute 把激活压到 10.27 GB,合计 54.02 GB,余量 25.98 GB。这个对比解释了为什么大模型配置常把 microbatch 设为 1,也为什么 selective recompute 不是“可选优化”。
简化与未覆盖:激活按 Eq 5 的首 stage 上界,不除以 PP;PP 只进入模型状态的分母。未计 embedding/output 激活、碎片、通信 buffer、workspace 和交错调度因子(Table 6-B 才乘 1.2917)。config N 与论文标签 175B 的差是 −0.22%((174.62−175)/175),与上面“手填 N 相对 config +0.22%”方向相反,因为分母不同。
用四篇论文的公开配置回代:参数量误差在 1% 内,激活+状态的下界能解释“为什么必须重算”。
把 Korthikanti Table 3 的四个配置代进 Megatron Eq 2。四个配置都用 V=51200、s=2048、ffn=4h、tied embedding;误差主要来自标签的四舍五入与 Eq 2 的结构假设(ffn=4h、MHA、tied embedding、V=51200);13h 项只有 0.004–0.043B,解释不了 1T 的 8.04B 差。
| 模型标签 | L | h | a | P (Eq 2) | 标签值 | 差 | 相对偏差 |
|---|---|---|---|---|---|---|---|
| 22B | 48 | 6144 | 64 | 22.07B | 22B | +0.07B | +0.34% |
| 175B (GPT-3) | 96 | 12288 | 96 | 174.62B | 175B | −0.38B | −0.22% |
| 530B (MT-NLG) | 105 | 20480 | 128 | 529.60B | 530B | −0.40B | −0.08% |
| 1T | 128 | 25600 | 160 | 1008.04B | 1000B | +8.04B | +0.80% |
偏差 = (P − 标签值)/标签值;标签是论文的近似规模名,不是精确计数;1T 按十进制 1000B 计。最大相对偏差 0.80%(绝对差 8.04B),来自 1T;其余三个都在 0.34% 以内。
这张表说明 Eq 2 的一阶项足够解释这些模型的规模,但也提醒:标签不是精确值。1T 配置复算到 1008.04B,差 8.04B;如果拿 “1T” 当精确数去反推 h 或 L,会得到不合理的结果。
用 Table 3 的 175B/530B 配置,b=1、s=2048、TP=8、interleaved m=3,把模型状态和 Eq 5/6 的激活相加。模型状态按 16Ψ/(t·p) 均匀切分;激活乘交错因子 (1+(p−1)/(pm))。
| 模型 | PP | 状态/卡 | Eq 5 激活 | 合计 | Eq 6 激活 | 合计 | 80GB |
|---|---|---|---|---|---|---|---|
| 175B (GPT-3) | 8 | 43.75 GB | 44.47 GB | 88.22 GB | 13.26 GB | 57.01 GB | 否 / 是 |
| 530B (MT-NLG) | 35 | 30.29 GB | 71.42 GB | 101.70 GB | 24.78 GB | 55.06 GB | 否 / 是 |
状态 = 16Ψ/(t·p);激活 = Eq 5/6 × 交错因子(175B ×1.2917,530B ×1.3238);只算 transformer 层,不含 embedding/output、碎片、通信与 workspace。合计是下界;“否 / 是”指无重算 / selective 两个下界是否 ≤80GB。
无重算时,两个配置的下界都超过 80GB;selective 后都低于 80GB。这与 Korthikanti §6.1 的结论方向一致:“Without the memory savings provided by sequence parallelism and selective recompute together, none of the these models will fit into memory.” 论文的实测是最终证据;这里的计算只是下界。
selective 的激活降幅:175B 从 44.47 GB 到 13.26 GB,降幅 70.18%;530B 从 71.42 GB 到 24.78 GB,降幅 65.31%。这两个数分别对应 §5 的 70% 和 65%(GPT-3 的 5as/h=80,MT-NLG 的 64)。
为什么 Table 3 的大模型 microbatch 都是 1?即使不乘交错因子,175B 的 Eq 5 下界相加已经是 78.18 GB,只剩 1.82 GB;b=2 会把激活翻倍,直接超过 80GB。推断(由 Table 3 的 microbatch 列与 Eq 5 下界相加;交错因子只会更紧)。
公式给的是可解释的下界;真实峰值由这些项决定。
保留上下文项时,训练 FLOPs ≈ 6N(1 + s/(12h))(d_attn≈h、backward≈2×forward)。在 s≪12h 时上下文项可忽略;s=32768、h=4096 时 s/(12h)=66.7%,条件已不成立,必须单独加 +66.7%。
全量重算的硬件 FLOPs ≈ 8ND(Megatron Eq 3 的 96=8×12)。selective 只重算 attention,硬件/模型 ≈ 1+s/(6h)(s=2048;3h≫s、12hL≫v):h=12288 时 +2.78%,h=20480 时 +1.67%。
PyTorch 的 max_memory_allocated 是分配出去的峰值,max_memory_reserved 还包含缓存块;差值可以粗略看成碎片/缓存。公式给的是稳态下界,峰值可能更高。
TP 的 all-reduce、PP 的 p2p、ZeRO/FSDP 的 all-gather 都要 buffer;buffer 大小随实现、重叠策略、microbatch 数变,16Ψ 和 34sbhL/t 里都没有。
GEMM、attention、optimizer step 的临时 workspace 不进 16Ψ,也不进激活公式;一次 step 的峰值可能出现在某个 kernel 内部,而不是稳态。
模型状态用 N_total(全部 expert),FLOPs 用 N_active(top-k expert)。把 N_total 代进 6ND 会高估算力;把 N_active 代进 16Ψ 会低估显存。
Eq 2 的 4h² 假设 MHA。GQA/MQA 让 K/V 投影变小,Eq 2 的 4h² 参数项会高估;激活公式里变小的是 34 项中的 K/V 存储,5as/h 是 query 的 score 矩阵项,不因 K/V 头数减少而缩小。换 attention 结构要重数,不要只改 h。
梯度存 fp32 时 2+4+4+4+4 = 18 B/参数;SGD+momentum 12 B;fp32 Adam 16 B(构成不同)。不要拿 16Ψ 去套所有优化器。
还有一个常被忽略的边界:推理的 2ND 不是延迟。2ND 是前向的模型 FLOPs;decode 阶段每生成一个 token 只做一次前向,但受 KV cache 带宽和 batch 调度限制,墙钟时间主要由 memory bandwidth 决定。2ND 可以用来估“算多少”,不能直接用来估“多快”。