大模型训练与推理显存账对比

作者:很菜不狗2026.11.04 10:17浏览量:0

简介:从显存占用、精度策略、并行切分三个维度,拆解大模型训练与推理的本质差异,帮助读者理解为什么“能推理”不等于“能训练”,以及并行方案选型时的关键权衡与评估要点。

大模型训练与推理显存账对比:为什么“能跑推理”不等于“能训练”

一、对比背景:一个常见的误判

在评估大模型落地可行性时,很多人会先做一个简单测算:一个 7B 参数的模型,用 bf16 存储大约需要 14GB 显存,而一张 80GB 的加速卡看起来绰绰有余。于是得出结论:这张卡可以跑这个模型。

这个结论对推理场景基本成立,但对训练场景则完全不成立。本文要对比的,正是“大模型推理”与“大模型训练”这两个阶段在显存占用、精度策略和并行切分方式上的核心差异,并进一步对比不同并行切分方案之间的取舍。

理解这组差异,直接决定了三件事:需要多少卡、通信开销有多大、训练能不能稳定收敛。

二、对象定义:推理与训练分别在做什么

推理:模型参数固定,前向计算产出结果。显存主要被权重和激活占用,不需要保存梯度,也不需要优化器状态。

训练:除了前向,还要反向传播计算梯度,并用优化器更新参数。显存要同时容纳权重、梯度、优化器状态以及大量中间激活。三者叠加,量级与推理完全不在一个层面。

换句话说,推理是“读模型”,训练是“读模型 + 写模型 + 记录修改历史”。多出来的部分,才是显存账的真正大头。

三、相同点:两者共享的基础约束

尽管差异巨大,推理与训练仍有共同的技术底座:

  • 都依赖相同的模型结构定义与权重格式;
  • 都受限于单卡显存上限和卡间互联带宽;
  • 都可以通过量化、切分等手段降低单卡压力;
  • 都需要在吞吐、延迟、成本之间做权衡。

正因为底座相同,才容易让人误以为“推理能跑,训练也能跑”。差异恰恰出现在底座之上的额外开销。

四、核心差异一:显存账的结构完全不同

4.1 推理的显存构成

推理阶段,显存大致由两部分组成:

  • 权重:bf16 下每参数 2 字节;
  • 激活:与批次大小、序列长度相关,通常可控。

7B 模型 bf16 推理,权重约 14GB,加上激活和 KV 缓存,单卡 80GB 通常可以容纳。

4.2 训练的显存构成

训练阶段采用混合精度 + Adam 类优化器时,每个参数要背负的状态远不止权重本身。以下是通用账目(不含激活):

项目 精度 每参数字节
权重 bf16 2
梯度 bf16 2
主权重 fp32 4
优化器一阶动量 fp32 4
优化器二阶动量 fp32 4
合计 — 16

用一段通用示意代码可以直观看到这个账:

  1. P = 7e9
  2. bytes_per_param = 2 + 2 + 4 + 4 + 4 # bf16权重 + bf16梯度 + fp32主权重 + 两个fp32动量
  3. total = P * bytes_per_param / 1e9
  4. print(f"每参数 {bytes_per_param} 字节,总计 {total:.0f} GB")
  5. # 每参数 16 字节,总计 112 GB

7B 模型光“状态”就要约 112GB,还没算激活。序列一长,激活往往比状态还大。所以“一张卡装不下”是训练的起点,而非例外。

五、核心差异二:精度策略不能一刀切

既然 fp32 主权重占了 4 字节,看起来像浪费,能否全部用 bf16?答案是:不能。

原因是 bf16 的有效尾数位远少于 fp32。当参数更新量很小时,更新值在 bf16 下会被舍入到零,参数实际上不再变化。用一段通用示意代码可以复现这个现象:

  1. import numpy as np
  2. def to_bf16(x):
  3. b = np.asarray(x, dtype=np.float32).view(np.uint32) & np.uint32(0xFFFF0000)
  4. return b.view(np.float32)
  5. w = np.float32(1.0)
  6. for upd in (1e-2, 1e-3, 1e-4):
  7. print(f"更新量 {upd:g}: fp32 -> {np.float32(w+upd):.6f} "
  8. f"bf16 -> {to_bf16(to_bf16(w)+to_bf16(upd)):.6f}")
  9. w32 = np.float32(1.0); w16 = to_bf16(1.0)
  10. for _ in range(10000):
  11. w32 = np.float32(w32 + 1e-4)
  12. w16 = to_bf16(w16 + to_bf16(1e-4))
  13. print(f"累加 10000 次 1e-4: fp32 = {w32:.4f}, bf16 = {w16:.4f}")

典型输出会显示:更新量 1e-3 和 1e-4 时,bf16 结果几乎不变;累加一万次后,fp32 从 1.0 涨到约 2.0,而 bf16 仍停在 1.0。这就是必须保留 fp32 主权重的原因——它承载的是“小步慢走”的累积精度。

六、核心差异三:并行切分方案的选择

单卡放不下,就必须切。切分方式和通信代价,是训练与推理差异最大的工程环节。

6.1 常见切分维度

切分方式 切什么 主要代价 典型适用
数据并行(含状态分片) 优化器状态、梯度、权重 每步需 all-gather 权重、reduce-scatter 梯度 模型能放进单卡但状态放不下
张量并行 单层内的矩阵 每层前后都要通信,延迟敏感 单层过大,单卡放不下
流水并行 按层切分 存在流水气泡,需调度填充 层数多、跨节点带宽有限
序列并行 序列维度 注意力计算需跨卡通信 长序列场景

6.2 状态分片的账

以状态分片为例,112GB 的状态切到不同卡数:

卡数 每卡状态显存
1 112.0 GB
8 14.0 GB
64 1.8 GB

看起来 64 卡很美好,但代价是每一步都要把参数 all-gather 回来、梯度 reduce-scatter 出去。卡越多,单卡算得越少,通信占比越高。切法不对,加速卡大部分时间在等网络。

七、对比表格:推理与训练的关键差异

维度 推理 训练
显存构成 权重 + 激活 权重 + 梯度 + 优化器状态 + 激活
每参数开销(bf16+Adam) 约 2 字节 约 16 字节
7B 模型基础显存 约 14GB 约 112GB(不含激活)
精度要求 bf16 通常足够 需 fp32 主权重保精度
并行需求 单卡或少量卡即可 必须多卡切分
通信压力 较低 高,随卡数上升
主要瓶颈 显存带宽、KV 缓存 通信、激活、收敛稳定性

八、典型场景下的选型思路

  • 只做推理服务:优先评估单卡能否放下权重与 KV 缓存,显存不足时优先考虑量化、批调度优化,而非引入复杂并行。
  • 小规模微调:若模型能放进单卡,优先用状态分片类数据并行;若单层过大,再叠加张量并行。
  • 全量预训练或大规模微调:需要组合多种并行策略,重点评估卡间互联带宽与通信占比,切分维度要与网络拓扑匹配。
  • 长序列训练:激活占用可能超过状态,需要单独考虑激活重计算与序列并行。

九、迁移与使用注意事项

从推理方案转向训练方案,或从一种并行策略切换到另一种,需要提前评估:

  1. 显存预算重算:不能沿用推理的显存估算,必须按 16 字节/参数重新核算,并预留激活空间。
  2. 通信拓扑匹配:张量并行对带宽敏感,通常放在节点内;流水并行可跨节点,但要处理气泡。
  3. 精度配置检查:确认主权重、动量是否用 fp32,避免小更新量被吞掉导致不收敛。
  4. 断点与容错:训练周期长,需考虑检查点保存频率与恢复成本。
  5. 监控指标:除显存外,重点关注通信等待时间、梯度范数、loss 曲线,判断切分是否合理。

十、总结

大模型训练之所以难,不是难在“模型放不下”这一句话,而是难在三笔账同时成立:状态账要求多卡切分,精度账要求保留 fp32 主权重,通信账要求切分方式与网络拓扑匹配。推理与训练的最大差异,就在于训练多了梯度与优化器状态这两层开销,并因此被迫引入并行与通信。

选型时,先判断场景是推理还是训练,再按 16 字节/参数估算状态显存,最后根据单层大小和互联带宽选择切分维度。切法不对,卡再多也是在等网络;精度配错,步长再小也训不动。把这两点想清楚,大模型训练的显存与并行方案就不难落地。