✨ 复制成功!

以文会友,打造好学人设!

📋 已复制到剪贴板:

为什么优化器状态占那么多显存?

创建时间:2026-09-24 更新时间:2026-09-24 阅读次数:1241 次 分类:分布式训练与工程优化

这个问题问到了 ZeRO 之所以存在的根本原因。答案很简单:优化器状态里存的不是一份参数,而是好几份和参数同样大的副本。

以 Adam 为例:一个参数,四份存储

假设模型有 1 个参数 w,用 Adam 优化器训练。训练时需要存这些东西:

存储项含义大小
参数 ww模型权重本身1 份
梯度 gg反向传播算出的梯度1 份
一阶动量 mm梯度的指数移动平均1 份
二阶动量 vv梯度平方的指数移动平均1 份

所以每个参数实际需要 4 份存储(参数 + 梯度 + 两个动量)。

如果模型有 N 个参数,用 FP32(4 字节)存储:

  • 参数:4N 字节
  • 梯度:4N 字节
  • 一阶动量:4N 字节
  • 二阶动量:4N 字节
  • 合计:16N 字节

其中优化器状态(m 和 v)占了 8N 字节,也就是一半。

实际数字有多夸张

以一个 10B(100 亿)参数的模型为例:

存储项大小
参数(FP32)40 GB
梯度(FP32)40 GB
一阶动量(FP32)40 GB
二阶动量(FP32)40 GB
总计160 GB

一张 A100 只有 80 GB 显存,光模型状态就装不下,更别说还要留空间给激活值了。

而其中优化器状态就占了 80 GB,正好是一整张 A100 的容量。

为什么优化器状态这么大

根本原因在于:Adam 这类自适应优化器,需要为每个参数单独维护历史信息。

  • 一阶动量 m:记录梯度的“平均方向”,让更新更平滑。
  • 二阶动量 v:记录梯度平方的“平均大小”,用来给每个参数自适应调整学习率。

这两个量都是和参数一一对应的,参数量有多大,它们就有多大。而且它们必须用 FP32 存,因为需要高精度累积,否则训练会不稳定。

这正是 ZeRO 的切入点

ZeRO 的核心洞察就是:参数和梯度在每个 GPU 上都必须有完整副本(计算需要),但优化器状态其实不需要每个 GPU 都存一份。

因为在标准数据并行中,每个 GPU 算完梯度后,会通过 All-Reduce 把所有 GPU 的梯度求和平均,得到完全相同的梯度。既然梯度都一样,那么用这个梯度去更新优化器状态,每个 GPU 算出来的新优化器状态也是一模一样的。

也就是说,每个 GPU 都在重复存储和计算完全相同的优化器状态——这是巨大的浪费。

ZeRO-1 做的就是:把优化器状态切成 N 份,每个 GPU 只存自己那份。更新参数时,每个 GPU 只更新自己负责的那部分参数,然后再把更新后的参数广播给其他 GPU。

这样:

  • 优化器状态显存占用:从 8N 降到 $8N/N_{GPU}$

  • 参数和梯度暂时还是完整的(ZeRO-2 再切梯度,ZeRO-3 再切参数)

一句话总结

优化器状态之所以占显存,是因为 Adam 为每个参数都存了两个 FP32 的历史动量,加上参数和梯度,每个参数实际需要 4 份存储。 而在数据并行中,这些优化器状态在每个 GPU 上都是完全重复的,ZeRO 就是把这部分重复彻底消除掉。


📌 面试天下网:一款服务于大一新生的口袋书,让大家在无聊的公共课上可以学习大模型技术!
📌 网站公告:【悬赏 200 元/篇】寻找“大模型面试战场”的一手回忆录
📌 网站公告:【大模型/Agent面试陪练1V1指导】正式启动......

评论专区

评论加载中...