大模型训练吃显存,但显存不是被模型参数一样占完的。仔细拆开,训练时要驻留显存的有三类东西:参数本身、参数的梯度、优化器状态(比如 Adam 的动量和方差)。后面两类常常比参数还占地方。ZeRO 的核心洞察就是:这三样不必每张卡都存全,切碎了分着存,用的时候再取。本文按机制层讲法把这条线捋清。
三类训练状态各是什么
先看三类状态。参数是模型权重,梯度是反向传播算出来的误差信号,优化器状态是更新规则自己记的账。以 Adam 为例,混合精度下每个参数要配 FP16 权重、FP32 主权重、FP32 梯度,再加两个 FP32 优化器动量,一个参数实际要占十几个字节。模型一百亿参数的话,光优化器状态就是几百 GB 级别,这就是为什么要从状态本身下手。记住一个数量级感:混合精度训练下,一个参数的「状态全家桶」常是参数本身的十倍以上,优化器状态又占其中大头,所以 ZeRO 从它下手最划算。
第一级:只切优化器状态
ZeRO 第一级切的是优化器状态。进来的是各卡本地梯度,计算时每张卡只负责一部分参数的更新,把负责段的动量方差留在自己显存里。出去的是分片存放的优化器状态,显存立刻降一大截。参数和梯度仍然是每卡全量,所以第一级对通信量几乎没有额外要求,是性价比最高的一档。
第二级:梯度也分片
第二级在第一级基础上再切梯度。反向传播时,每张卡只保留自己负责那段参数的梯度,别段梯度算完即传即弃。进来的是本卡算出的梯度,传给对应负责卡后本地不留副本。出去的梯度占用也降下来,但通信模式变了,各卡之间开始按段交换数据。
第三级:参数用完即还
第三级连参数也切。前向时每张卡按需 all-gather 自己那段要用的参数,算完就把不属于自己的部分还回去;反向和更新同理,用哪段取哪段,用完即弃。进来的是分片存放的全量参数,某时刻每卡只驻留一小片;出去的是省到底的显存占用,代价是通信量明显上升,接近数据并行的量级。
三级逐层加码,切什么、留什么、通信涨多少并排看:
| 级别 | 切的对象 | 每卡常驻 | 显存变化 | 通信代价 |
|---|---|---|---|---|
| 第一级 | 优化器状态 | 参数与梯度 | 降一大截 | 几乎没有额外要求 |
| 第二级 | 优化器状态、梯度 | 参数 | 梯度占用也降下来 | 模式变了,各卡按段交换 |
| 第三级 | 优化器状态、梯度、参数 | 一小片参数 | 省到底 | 明显上升,接近数据并行 |
三级不是互斥选项,是按显存压力逐级加码。放不下且通信扛得住时,第三级能把单卡可训的模型规模推高一个档;但 ZeRO 不改模型结构,只改状态存放方式,这决定了它的适用边界——如果一层矩阵本身就塞不进单卡,得看张量并行是怎么切开一层的;模型层数太多跨机放不下,流水线并行是另一条路。日常使用中,ZeRO 常和数据并行叠加,后者管速度前者管显存。
微调场景下还有更轻的组合打法:先冻结大部分参数,再对剩下可训部分量化,配合 ZeRO 分片,消费级显卡也能动一些原本不敢想的模型,这套组合在微调的显存是怎么省的里有逐个拆解。日常同时维护 DeepSeek 和通义千问两套使用笔记也是这个思路:公共部分只存一份,各自的进展单独放,用时互取。
- 三类状态:参数、梯度、优化器状态,后两者常比参数更占显存
- 一级:只切优化器状态,通信几乎不变
- 二级:再切梯度,算完即传即弃
- 三级:参数也切,用时 all-gather,用完即还
- 边界:单层放不下找张量并行,跨机分层找流水线并行
聊聊 ZeRO 的常见疑问
- ZeRO 会让训练变慢吗?:一级几乎无感,二级略增通信,三级通信量接近数据并行,用不用看显存和速度怎么权衡。
- 它和模型并行是一回事吗?:不是,模型并行改计算归属,ZeRO 只改状态存放,参数该谁算还谁算。
- 推理阶段用得上 ZeRO 吗?:推理没有优化器状态和梯度,省显存主要靠量化与分页管理,思路不同。


