第 14 课:显存账本与混合精度

上一课讲了"一张卡放不下怎么切",但只用了一个结论——每参数 16 字节。这一课把这个结论拆到底:16 字节分别属于谁、为什么优化器状态占了四分之三、激活为什么会和权重同量级、ZeRO(即把优化器状态、梯度、参数分片存到各卡的省显存方案)三把刀各砍掉什么、FP8 到底省的是显存还是算力。最后合起来算一道实操题:训一个 70B,到底要几张 80 GB 卡。

🎯 学完这 6 步你将能够:
① 把训练显存拆成四项并逐项算清(权重 / 梯度 / 优化器状态 / 激活)
② 写出 ZeRO-1/2/3 的每参数显存公式,并判断哪一档能把 70B 放进 80 GB 卡
③ 用激活公式与重算口径算出一份显存预算,给出"至少几张卡"的答案
🗺 本节推理链(5 步逻辑递进 + 1 条汇总支链:从"四类东西"到"最小卡数")
1训练一个 70B 稠密模型,要求每张 80 GB 的卡同时放下四类东西:bf16 权重、bf16 gradient、优化器状态、以及这一批 token 的激活——这就要求先算清每类各占多少。
↓
2顺着上一步的四类东西往下分辨:哪一类最大?——因为 Adam 要为每个参数维护两份 fp32 动量再加一份 fp32 master,所以优化器状态一项就吃掉 12 B/参数,是 bf16 权重的 6 倍(而 bf16 权重与 gradient 各只占 2 B)——优化器状态是最大的一项。
↓
3既然「优化器状态是最大的一项」已经确定,所以先切它最划算——这就是 ZeRO 三把刀:ZeRO-1 只切优化器状态、ZeRO-2 再切 gradient、ZeRO-3 连参数也切(这套分片方案在 PyTorch 里叫 FSDP,即把优化器状态、梯度、参数都切开放到各卡),每张卡的状态从 16 B/参数一路降到 16/N。
↓
4「ZeRO 三把刀」切完状态,剩下占地方的是它切不动的那部分——激活。因为注意力要存 softmax 前后的中间量,激活里含一个随序列长度平方增长的激活的二次项,所以序列越长,激活越可能反超权重。
↓
5「激活的二次项」可以用激活重算(activation recomputation)消掉,于是状态与激活两边都已封顶——因此剩下能改的只有数值精度:把数据的数值精度降到 8 bit 之后,省的主要是算力与带宽——FP8 省的是算力而非显存,权重与优化器照样要留 fp32 master。
↓
6【支链 · 汇总】既然「FP8 省的是算力而非显存」,最后能动的只有 ZeRO 与重算两条路——因此把四类东西相加再除以 80 GB(每张卡还要留出 token 激活与碎片的余量),就得到 70B 的最小卡数,而且这个答案对"激活按哪种方式算"极其敏感。
Memory LedgerMixed PrecisionZeRO / FSDPActivation RecomputationFP8 / MXFP8Master Weights
1
要让 70B 训得动,显存到底花在哪几项?
提示:把训练一步里需要同时留在显存的东西列全——模型本身、它的更新方向、优化器为它记的账,以及这一批数据算出来的中间量。别漏掉最后一项。
▾
知识背景
Llama 2 70B(Meta,2023-07,arXiv:2307.09288):80 层、隐藏维 8,192、64 个注意力头、8 个 KV 头(GQA,即多组注意力头共享同一份 K/V 的注意力变体)、FFN 维 28,672,4,096 上下文。MLPerf 的 LoRA(即冻结大部分权重、只训练一小部分低秩增量参数的省显存微调)基准用 64 张 H100 训 70B。而全量微调 70B 的显存,工程上常被引作"混合精度下约 140 GB"——这句说的通常是 bf16 权重本体(70e9 × 2 B = 140 GB),不含梯度与优化器状态(那两项加起来是 980 GB,见 Step 1);该说法的确切出处与限定语境待人工核实。DeepSpeed 的显存估算文档把每参数口径写死:Adam 用 4 B 存动量、4 B 存方差(共 8 B)。把训练显存拆成四项的分类框架来自 Korthikanti 等(arXiv:2205.05198,MLSys 2023)。

上一课我们只借用了"16 B/参数"这一个结论,没有把它拆开。这一课拆到底——先把账算清,才谈得上省。

先把四个名词说白:权重(weight)是模型参数本身;梯度(gradient)是这一步要往哪个方向改;优化器状态(optimizer state)是优化器为了算出这个方向而替每个参数记的账;激活(activation)是前向算出来、反向还要再用的中间量。可以把这四项类比成一个装修现场:家具(权重)、搬运清单(梯度)、两份账本加一份原始图纸(优化器状态),以及施工中摊开的所有材料(激活)——只有最后一项能在收工后收起来。

🧮 第一笔账:四类东西各占多少
Step 1:四类东西分别是什么
项内容精度与字节70B 合计
权重参与前向与反向的模型参数bf16,2 B/参数140 GB
梯度每个参数这一轮的更新方向bf16,2 B/参数140 GB
优化器状态fp32 master 权重 + Adam 两个动量12 B/参数840 GB
激活前向产出、反向要用的中间量随序列长度变化见 Card 4
前三项合计—16 B/参数1.12 TB
140 + 140 + 840 = 1.12 TB。注意"权重"这一行的 140 GB 是 bf16 的训练副本;同一份参数还有一份 fp32 master,被算进了"优化器状态"里——同一份参数据精度不同被拆到两行,这是最常见的口径混淆点。
Step 2:换成 GB 与占比看
项每参数字节70B占 16 B 的比例
bf16 权重2140 GB12.5%
bf16 梯度2140 GB12.5%
fp32 master 权重4280 GB25%
Adam 一阶动量 m4280 GB25%
Adam 二阶动量 v4280 GB25%
合计161.12 TB100%
校验:70e9 × 16 B = 1.12 TB ✓。用占比看更直观——权重本身只占 12.5%,优化器状态独占 75%。这解释了为什么后面所有省显存的手段,第一刀都砍向优化器状态。
Step 3:前三项不随序列涨,激活会
对比按什么规模增长70B 在 4K 序列下的量级
权重 / 梯度 / 优化器状态∝ 参数量(固定)1.12 TB(与序列长度无关)
激活∝ 序列长度 × 批大小 × 隐藏维 × 层数与 1.12 TB 同量级(Card 4 精算)
DeepSpeed 的显存文档明确写过一句:激活可能和 params + grads + optim states 加起来一样大。所以显存账必须把激活单独算——前三项是常数,它随序列长度涨。
🎯 关键认知

训练显存只有四项,但它们的"增长方式"完全不同:权重、梯度、优化器状态 ∝ 参数量(与序列无关);激活 ∝ 序列长度(与参数量无关)。这一条决定了后面所有手段的分工——砍前三项要靠切分与低精度,砍激活只能靠"别存它"(重算)。先把四项分开算,是本节接下来 5 张卡片的共同地基。

AI 助教
👋 对显存四项有疑问?比如"推理时为什么只有两项""LoRA 能把哪几项砍掉?"

我会用具体数字帮你算。
2
为什么优化器状态占了全部显存的四分之三?
提示:Adam 不只是"记一个方向"。数一数它为一个参数保存了几份数、每份多少字节,再问一句:其中哪几份是为了"精度"而不是为了"信息"。
▾
知识背景
Adam(Kingma & Ba,arXiv:1412.6980,2014)为每个参数维护两个状态:一阶动量 m(梯度的滑动平均)与二阶动量 v(梯度平方的滑动平均),都是 fp32、各占 4 B。混合精度训练再加一份 fp32 master 权重(4 B),原因是 bf16 精度不够:1.0 附近 bf16 的间距(ULP,相邻两数的最小间隔)约 7.8×10⁻³、舍入误差(半个间距)约 3.9×10⁻³,而学习率 1e-5 时的每步更新量只有 1e-5,会被直接舍成 0。DeepSpeed 官方显存文档把这 8 B(动量 + 方差)写成估算的固定口径。想要更省,可以用 8 bit 优化器(如 bitsandbytes 的 8-bit Adam)把两个动量量化到各 1 B。训练里常用的是 AdamW(即 Adam 加上权重衰减的工程标准写法)。

上一张卡片看到四项里优化器状态最大。这一张把它拆开,看这 12 B/参数 到底花在哪。

先给个直觉:梯度(gradient)只告诉你"这一步往哪走",而 Adam 还想记住"过去几十步都往哪走、走得有多抖"——这就是两个动量的作用。可以把它类比成开车:梯度是这一刻的方向盘角度,一阶动量是你最近的行驶方向,二阶动量是路面的颠簸程度——后两者都要随时间累积,所以必须一直留着。

🧮 第二笔账:12 字节是谁
Step 1:一个参数的 12 B 分别是什么
项字节作用能不能省
fp32 master 权重4累积更新、避免 bf16 舍入不能(精度需要)
一阶动量 m4平滑梯度方向不能(Adam 的定义)
二阶动量 v4自适应学习率不能(Adam 的定义)
合计12——
12 B 是 bf16 权重(2 B)的 6 倍,是 fp32 权重(4 B)的 3 倍,也是全部 16 B 的 75%。
Step 2:规模不同,"几张卡"的账
模型参数量前三项(16 B/参数)80 GB 卡至少
7B7e9112 GB2 张(112 ÷ 80 = 1.4)
13B13e9208 GB3 张(208 ÷ 80 = 2.6)
70B70e91.12 TB14 张(1120 ÷ 80 = 14,整除)
405B405e96.48 TB81 张(6480 ÷ 80 = 81)
校验:7e9×16 = 112 GB;13e9×16 = 208 GB;70e9×16 = 1.12 TB;405e9×16 = 6.48 TB。注意这些数字都没有算激活——它是"下限的下限"。
Step 3:换优化器能省多少
优化器优化器状态/参数总账/参数70B 总账
SGD + 动量4 B 动量 + 4 B master = 8 B12 B840 GB
AdamW8 B(m+v)+ 4 B master = 12 B16 B1.12 TB
8-bit Adam2 B(量化 m+v)+ 4 B master = 6 B10 B700 GB
算术:70e9 × 12 B = 840 GB;× 10 B = 700 GB。换成 SGD 省下 280 GB,代价是收敛更慢、对学习率更敏感;8-bit Adam 把两个动量各压到 1 B,再省 140 GB,代价是量化误差与额外工程复杂度。
🎯 关键认知

优化器状态之所以最大,是因为它为每个参数存了三份 fp32(master 权重 + 两个动量 = 12 B),而参数本身只占 2 B。它不是"多余的开销",而是 Adam 能自适应调学习率的前提——想省,只有两条路:换成更省的优化器(SGD / 8-bit),或把它切开分给其他卡(这正是下一张卡片的 ZeRO)。

AI 助教
👋 对优化器状态有疑问?比如"为什么 master 不是 fp16?""8-bit Adam 掉点吗?"

我会用具体数字帮你算。
3
ZeRO 三把刀,各砍掉什么、代价是什么?
提示:把状态分成"每张卡都必须有一份"和"可以切开分给各卡"两类。想想每升一档,省下的是哪一项,付出的又是什么。
▾
知识背景
ZeRO(Zero Redundancy Optimizer)由 Rajbhandari 等提出(arXiv:1910.02054,2019-10)。DeepSpeed 官方文档把三档定义得很清楚:Stage 1 切优化器状态(含 fp32 master 与两个动量);Stage 2 再切 16-bit 梯度;Stage 3 连 16-bit 参数也切,并在前向/反向按需 all-gather 回来。文档同时给出结论:在典型 Adam 设置下,Stage 1 就能带来最高 4 倍显存缩减。PyTorch 的原生实现叫 FSDP。

上一张卡片确定了一件事:优化器状态是最大的一项,所以先切它最划算。这就是 ZeRO 三把刀的分工。

先把机制说白:ZeRO 不改变训练数学,只改变"东西存在哪、什么时候通信"——梯度(gradient)与参数在该切的时候切、该拼的时候拼。可以把它类比成合租公寓——原本每人房间里都存一整套共用的工具(8 个人就 8 套,纯浪费),ZeRO 改成工具放公共储藏室、每人只负责其中一柜,用到时才去取。

🧮 第三笔账:三档的公式与读数
Step 1:三档的每参数显存公式
方案每参数显存(N = DP 度)N = 8 时70B(N = 8)
DDP16 B16 B1.12 TB
ZeRO-14 + 12/N5.5 B385 GB
ZeRO-22 + 14/N3.75 B262.5 GB
ZeRO-316/N2 B140 GB
校验:4 + 12÷8 = 5.5;2 + 14÷8 = 3.75;16÷8 = 2。对应 70B:70e9 × 5.5 B = 385 GB;× 3.75 B = 262.5 GB;× 2 B = 140 GB。
Step 2:省的是"重复存了几份"
方案每卡8 张卡合计冗余
DDP1.12 TB8 × 1.12 TB = 8.96 TB8 份完全相同的状态
ZeRO-1385 GB3.08 TB1 份状态 + 8 份权重与梯度
ZeRO-3140 GB1.12 TB1 份
算术:8 × 0.385 = 3.08 TB;8 × 0.14 = 1.12 TB。这一步很关键——ZeRO 省的是"重复存了几份",不是"少存了":集群里总得有人存下那 1.12 TB,物理下限不变。
Step 3:代价是通信量(只有 ZeRO-3 真的加)
方案每步通信相对 DDP
DDP梯度 all-reduce(环形 ≈ 2 份量)1.0×(基准)
ZeRO-1梯度 reduce-scatter + 参数 all-gather1.0×(与 DDP 相同)
ZeRO-2梯度 reduce-scatter + 参数 all-gather1.0×(与 DDP 相同)
ZeRO-3前向 all-gather 参数 + 反向 all-gather 参数 + 梯度 reduce-scatter约 1.5×(消息也更碎)
官方口径(微软 ZeRO 发布博客)写得很明确:ZeRO-1 与 ZeRO-2 都是「same communication volume as data parallelism」,只有 ZeRO-3 才有「约 50% 的通信量增加」。算术直觉:DDP 的梯度 all-reduce(≈2 份量)在 ZeRO-1/2 里被换成 reduce-scatter(1 份)+ 参数 all-gather(1 份),总量不变;ZeRO-3 因为前向还要再 all-gather 一次参数,变成 3 份量,3 ÷ 2 = 1.5×。这正是 ZeRO 的核心卖点——切状态几乎不额外付通信。真正的差别在消息粒度:ZeRO-3 每层都要 all-gather 一次,消息更多更碎,对延迟更敏感(所以它通常与计算重叠)。(口径提示:少数教材按「梯度仍走完整 all-reduce」记账,会把 ZeRO-1 也算成 1.5×;差别在梯度用 all-reduce 还是 reduce-scatter。)
🎯 关键认知

三把刀砍的对象完全不同:ZeRO-1 砍优化器状态(12 B → 12/N)、ZeRO-2 再砍梯度(+2/N)、ZeRO-3 连权重也砍(+2/N)。但有一条容易忽略的推论:ZeRO-1 与 ZeRO-2 都要在每张卡上保留完整 bf16 权重(2 B/参数 = 140 GB);ZeRO-1 还多留一份完整梯度(再 2 B,合计 280 GB)——两者单卡都 ≥ 140 GB,永远装不进 80 GB 卡。真正能做到的只有 ZeRO-3(Card 6 会用到这个结论)。

AI 助教
👋 对 ZeRO 三档有疑问?比如"为什么 ZeRO-1 是 4 + 12/N?""三档能叠加吗?"

我会用具体数字帮你算。
4
激活重计算:用算力换显存,划算吗?
提示:激活里有一个随序列长度平方增长的项。先问"这一项是谁产生的",再问"重新算它一遍,比把它存下来贵多少"。
▾
知识背景
一层 transformer 的激活(16-bit)约为 s·b·h·(34 + 5·a·s/h) ÷ t(s 序列长度、b 微批大小、h 隐藏维、a 注意力头数、t 张量并行度)。其中 5·a·s/h 一项来自注意力分数与 softmax——它随 s 平方增长。Korthikanti 等(arXiv:2205.05198,MLSys 2023)的选择性重计算只重算这一项,激活降到 34·s·b·h·L ÷ t;论文结论:激活显存降到约 1/5,重算的时间开销从 30~40% 降到 10% 以内,530B 模型在 2240 张 A100 上 MFU(MFU = 实际算力 ÷ 硬件峰值算力)从 42.1% 提升到 54.2%(快 29%)。重算的源头是 Chen 等 2016 年的 O(√n) 方法(arXiv:1604.06174)。

上一张卡片把状态切完了,但还有一项切不动——激活。它不是"每个参数一份",而是"每个中间张量一份",所以换一套算法来省:不存,等反向用时重算(activation recomputation,激活重算)。

为什么值得这么做?因为激活里有一项的规模随序列长度平方增长(注意力分数矩阵,形状是 token 数 × token 数),而它"占地方大、算起来却便宜"。把这类比成做菜:与其把切好的备料全摆在台面上占满厨房,不如用到时再切一次——多花点时间,台面一下就空了。

🧮 第四笔账:把公式代进 70B
Step 1:一项一项代进去
变量 / 项取值算式
s(序列长度)4096—
b(微批大小)1—
h(隐藏维)8192—
a(注意力头数)64—
5·a·s/h(二次项)1605 × 64 × 4096 ÷ 8192
每层系数19434 + 160
每层激活(元素)6.51e94096 × 8192 × 194
每层激活(bf16)13.0 GB6.51e9 × 2 B
全模型(80 层)1.04 TB13.0 GB × 80
本例取 t = 1(不切张量并行),故公式里的 ÷t 不生效,校验:4096 × 8192 = 3.36e7;× 194 = 6.51e9;× 2 B = 1.30e10 B = 13.0 GB;× 80 = 1.04e12 B = 1.04 TB。这个数字意味着:激活已经和"权重 + 梯度 + 优化器状态"的 1.12 TB 同量级——不能忽略。
Step 2:三种账法,各占多少
方式存什么算式激活显存
全存所有中间量194 × 3.36e7 × 80 × 2 B1.04 TB
选择性重算存便宜的,重算 softmax 与注意力分数34 × 3.36e7 × 80 × 2 B183 GB
全量重算只存每层输入2 × 3.36e7 × 80 × 2 B10.7 GB
算术:34 × 3.36e7 = 1.14e9/层;× 80 = 9.13e10;× 2 B = 183 GB。全量重算:2 × 3.36e7 = 6.71e7/层;× 80 = 5.37e9;× 2 B = 10.7 GB。三种口径的相对关系是 1.04 TB → 183 GB(约 1/5.7)→ 10.7 GB(约 1/97)。
Step 3:多花的时间是多少
方式激活显存额外时间开销来源
全量重算10.7 GB+30 ~ 40%NVIDIA 在 530B 上的实测
选择性重算183 GB< 10%论文:重算开销降低 > 90%
不重算1.04 TB0—
所以问题不是"划算不划算",而是"重算哪一部分划算":softmax 与注意力分数"占地方大、算起来便宜",重算它们的性价比最高——这正是选择性重计算的全部内容。
🎯 关键认知

激活是四项里唯一"可以不存"的——因为它是中间结果,丢了能重算。三种口径要按场景选:显存极紧就全量重算(10.7 GB,代价 30~40% 时间)、想两头兼顾就选择性重算(183 GB,代价 <10%)、显存够就直接存(1.04 TB)。工程上默认选择是第二种,而判断依据永远是同一句话:这一项占多少显存、重算它要多少 FLOPs。

AI 助教
👋 对激活重算有疑问?比如"为什么二次项可以单独重算?""序列翻倍激活会涨多少?"

我会用具体数字帮你算。
5
BF16(16 位浮点)换成 FP8(8 位浮点),省的是显存还是算力?
提示:先分清三件事——同样的数用几位表示(存储)、每秒能算多少次(算力)、每秒能搬多少字节(带宽)。FP8 改变的是哪几件?再想:为什么权重还要留一份 fp32 master?
▾
知识背景
先明确两个格式:BF16(半精度浮点,用 16 位存一个数)与 FP8(只用 8 位存一个数)。FP8 训练的第一个前沿级公开证据是 DeepSeek-V3(arXiv:2412.19437,2024-12):671B、14.8T token,用 fp8 前向/反向 + fp32 master 权重 + 分块缩放,报告原文给的训练成本是 2.788M H800 GPU 小时 ≈ 557.6 万美元(报告未给 BF16 对照成本;流传的"约 800 万"是第三方估算,非报告原文)。工程侧读数:TorchAO 报告 float8 训练可带来约 1.3~1.5× 的端到端加速(其发布说明中规模与硬件记载不一,具体口径需人工核实);AMD 团队在 Llama3-8B 上测到 rowwise FP8 相对 BF16 有约 +13% 吞吐、峰值显存几乎不变——结论是"收益来自更快的 FP8 矩阵核,不是省显存"(示意读数,需人工核实)。MXFP8(每 32 个元素共享一个 E8M0 缩放因子)则是 Blackwell 原生支持的新格式。

上一张卡片用激活重算(activation recomputation)把激活压下来了,还有一路是低精度。但这里有一个常见误解要先破掉:FP8 不等于"显存减半"。

先把三个词分开:存储(一个数占几字节)、算力(张量核每秒能算多少次矩阵乘,也就是 FLOPs 的高低)、带宽(每秒能搬多少字节)。可以把它类比成换成更快的货车:跑得是快了(算力与带宽都上去),但仓库里那批必须常年存放的库存(优化器状态)一件都没少。这就是本张卡片要算清的事。

🧮 第五笔账:FP8 到底动了哪几项
Step 1:三个"省"不是一回事
维度fp16 / bf16fp8是否减半
表示一个数占的字节21是(权重与激活的存储副本可减半)
张量核的矩阵乘吞吐基准约 2×是(是吞吐不是容量)
参数与优化器状态的总账16 B/参数15 B/参数(只降 6%)否
第三行是关键:FP8 训练不会把优化器状态减半——master 仍是 fp32、两个动量仍是 fp32,那 12 B 一动不动。省下的是权重与激活的存储副本,以及矩阵乘的算力开销。
Step 2:16 B 会不会降?只降一点
项BF16 训练FP8 训练变化
权重副本2 B1 B−1 B
梯度2 B2 B(通常留 bf16)0
fp32 master 权重4 B4 B0
Adam m + v8 B8 B0
合计16 B15 B−6%
70B 上:16 B → 15 B,只省 70 GB(1.12 TB → 1.05 TB)。所以"用 FP8 省显存"这个直觉基本是错的——真正的收益在吞吐:论文与工程报告给的是 1.3~1.8× 的端到端加速。
Step 3:为什么 master 不能也降到 8 bit
精度1.0 附近的舍入误差(roundoff,=半个间距 ULP)能否表示 1e-5 的更新
fp8(E4M3,尾数 3 位,间距 0.125)约 0.0625不能
bf16(尾数 7 位,间距 7.8×10⁻³)约 3.9×10⁻³不能
fp32(尾数 23 位,间距 1.2×10⁻⁷)约 6.0×10⁻⁸能
算术直觉:学习率 1e-5、权重 1.0 时每步更新量是 1e-5,比 fp8 的 0.0625 小约 4 个数量级(0.0625 ÷ 1e-5 = 6,250)、比 bf16 的 3.9e-3 小两个多数量级(3.9e-3 ÷ 1e-5 = 390),只有 fp32 的 6.0e-8 能把它累积起来。(列口径统一为"舍入误差=半个间距",与 Card 2 的 bf16 3.9×10⁻³ 一致。)这就是"低精度算、高精度记"这条铁律的算术依据。
🎯 关键认知

FP8 的收益几乎全在算力与带宽上(矩阵乘约 2× 吞吐、端到端 1.3~1.8×),显存只顺带降到 15 B/参数(−6%)。把它当"省显存手段"用,会失望;把它当"提速手段"用,很划算。而 fp32 master 必须留着,原因是纯算术的:更新量比低位宽的刻度还小,只有 32 位能累积。所以本课的省显存路线只有两条——ZeRO(切状态)与重算(不存激活),下一张卡片把两条合起来算总数。

AI 助教
👋 对 FP8 有疑问?比如"MXFP8 和普通 FP8 差在哪?""既然不省显存,为什么还要用它?"

我会用具体数字帮你算。
6
合起来算:70B 全量训练到底要几张 80GB 卡?
提示:分三步——先只算模型状态并用 ZeRO 摊薄,再加上激活(用第 4 张卡片的重算口径),最后除以 80 GB。注意真机还要留显存碎片与通信缓冲。
▾
知识背景
NVIDIA 的 Llama 2 70B LoRA 基准(MLPerf v5.0)用 64 张 H100(TP4 × CP2 × DP8),LoRA 只训约 55M 个参数(占 0.08%)、单卡约 80 GB;工程上另常引"全量微调 70B、混合精度下约 140 GB"(即 bf16 权重本体,出处待人工核实)。DeepSpeed 提供官方估算 API(`estimate_zero2/zero3_model_states_mem_needs_all_cold`),可以对任意参数量与卡数直接算出每卡显存——但它只覆盖模型状态,不含激活、显存碎片与通信缓冲,所以真实预算必须在此基础上另留余量。

上一张卡片证明了 FP8 省不了显存,所以能动的只剩两条:ZeRO 切状态与重算省激活。这一张把它们合起来,算出一个具体数字。

算账的顺序很重要,可以类比成搬家前估车:先量"必须带走的东西"(模型状态),再算"打包时才出现的临时占位"(激活),最后除以单车的容量——顺序反了就会反复推翻结论。

🧮 第六笔账:从 1.12 TB 到"几张卡"
Step 1:只算模型状态(不含激活)
方案每参数理论最低(N→∞)80 GB 卡装得下吗
DDP16 B1.12 TB装不下
ZeRO-14 + 12/N4 B/参数 = 280 GB装不下
ZeRO-22 + 14/N2 B/参数 = 140 GB装不下
ZeRO-316/N→ 0装得下
这一步有个容易忽略的结论:ZeRO-1 与 ZeRO-2 无论加多少卡都装不下 80 GB——因为两者都要在每张卡上保留完整 bf16 权重(2 B/参数 = 140 GB),ZeRO-1 还要多留一份完整梯度(合计 4 B = 280 GB)。只有 ZeRO-3 能把权重也切开。取 N = 16:16 ÷ 16 = 1 B/参数 = 70 GB/卡;取 N = 32:0.5 B/参数 = 35 GB/卡。(状态是"每卡一份",激活是"每个 token 一份"——两张账要分开算。)
Step 2:再加上激活,看总和
组合(s = 4096)状态激活合计装得下吗
ZeRO-3 N=16 + 全量重算70 GB10.7 GB80.7 GB差 0.7 GB,不行
ZeRO-3 N=32 + 全量重算35 GB10.7 GB45.7 GB可行
ZeRO-3 N=32 + 选择性重算35 GB183 GB218 GB不行
ZeRO-3 N=32 + 不重算35 GB1.04 TB1.08 TB不行
算术:70 + 10.7 = 80.7 > 80(就差 0.7 GB,但装不下);35 + 10.7 = 45.7 GB ✓。所以本题的答案是:至少要 32 张 80 GB 卡(ZeRO-3 + 全量激活重算)。换成长序列 s = 8192,全量重算的激活翻倍到 21.5 GB,N = 32 时仍是 56.5 GB ✓。
Step 3:为什么真实配置还会更多
余量来源量级为什么必须留
显存碎片与临时缓冲若干 GB分配器做不到零碎片(按约 1.5× 余量示意估算,非官方默认值)
集合通信缓冲若干 GBall-gather / reduce-scatter 需要临时区
吞吐目标倍数关系卡越多、每卡算得越少、越容易把通信藏起来
长序列与大批量线性增长激活随序列长度与批大小线性上涨
所以"装得下"只是下限。真实配置常在数十张量级(估算/示意,无可核实的一手来源,需按具体配置实测);本课算出来的 32 张是下限,真实配置由余量与吞吐目标决定。这也解释了为什么同一个模型,不同团队的"需要几张卡"能差一倍——他们报的是下限、推荐值、还是实测配置。
🎯 关键认知

把三张卡片的结论串起来就是一条完整的账:① ZeRO-1/2 因为要留完整权重,永远装不进 80 GB,只有 ZeRO-3 可行;② 激活必须靠重算压到 10 GB 量级,否则永远超标;③ 两者的组合给出了明确的下限——32 张。算账的价值正在这里:它把"要几张卡"从一个经验数字,变成一句可以逐项复核的乘法与除法。

AI 助教
👋 对卡数估算有疑问?比如"如果换成 40 GB 卡呢?""为什么不能靠 offload 解决?"

我会用具体数字帮你算。