最近在尝试用DeepSpeed微调一个7B的LLaMA模型,卡是两张A100 40G。用了ZeRO-3,offload也开了,但每次跑起来没几分钟就报OOM。我看了一些教程说7B模型用ZeRO-3应该能跑,但我设置zero_optimization.stage=3之后,显存占用直接冲到35G以上,训练步数一多就崩。我试过调小per_device_train_batch_size到1,还是不行。是不是我offload_param和offload_optimizer的device没设对?或者ZeRO-3本身对多卡通信有额外显存开销?有没有大佬分享下实际成功跑7B微调的config配置?先谢过了。
用DeepSpeed跑LLaMA微调,ZeRO-3总报显存不足,是我配置有问题吗?
全部回复
共 112 条我之前也踩过这个坑,ZeRO-3的显存开销其实不光在参数和优化器上,通信缓冲区和临时激活值也会占不少,两张40G跑7B确实紧巴巴。你offload设了device但没提offload_optimizer的pin_memory,试试把pin_memory开成true,再把zero_force_ds_cpu_optimizer设成false,有时候能省出几个G。另外建议把per_device_train_batch_size调到1的同时,看看gradient_accumulation_steps是不是设太小了,多攒几步梯度反而能摊薄通信消耗。实在不行就换LoRA吧,效果差不多,省心太多了。
40G双卡跑7B按理说ZeRO-3+offload是够的,但你注意下offload_param和offload_optimizer的device是不是都设成了nvme,如果只offload到CPU,那每张卡还得留够放模型参数和梯度的空间,35G起步很正常。另外ZeRO-3在每步前向反向都有all-gather通信,会临时拉满显存,你把zero_force_ds_cpu_offload开上试试,或者调低zero_quantile压缩梯度。我之前跑13B用双卡也遇到过,最后是把offload_param的pin_memory关掉,batchsize调成0.5(梯度累积两步)才稳住。你检查下zero_optimization里还有个reduce_bucket_size和allgather_bucket_size,默认值偏大,改小到5e8能省不少临时缓冲。
看到你报的35G占用我大概猜到问题了,ZeRO-3把参数和梯度切到每张卡上,但优化器状态和中间激活值还是会有额外开销,你两张40G其实挺紧的。offload_param和offload_optimizer的device确实要设成cpu,但建议别全offload,把offload_optimizer留到gpu上,param全丢cpu,这样能省不少显存。另外你检查过zero_force_ds_cpu_optimizer吗?这个不开的话即使offload了optimizer状态也可能留在显存里,很多人栽在这。还有个小坑,ZeRO-3通信会临时分配buffer,默认的reduce_bucket_size和allgather_bucket_size是5e8,如果你不手动调小,多卡通信那一下能吃掉好几G显存,建议把这两个降到2e8以下试试。我跑7B用的单机8卡A100 40G,stage3+offload param,per_device_batch_size设的2,梯度累积8步,峰值大概35G左右,你两张卡确实得batchsize=1加梯度累积16步才稳。最后检查下activation_checkpointing开了没,这个对降低激活显存特别关键,不开的话即使权重全offload了,前向一深还是会炸。
offload设cpu试试,另外gradient_checkpointing开了没,这俩才是省显存关键。
同感,之前我跑13B也遇到过这问题。ZeRO-3的显存占用看着吓人,其实有一部分是通信buffer,你把zero_force_opt和zero_offload_optimizer分开设试试,还有reduce_bucket_size调小点能省不少显存。
另外offload到CPU的话,offload_param的device必须写cpu,offload_optimizer同理,但别两个都开,优先offload优化器,参数offload反而容易卡IO。我最后是batch size=1,加上gradient_accumulation_steps凑到8,再把zero3_init设成false,勉强能跑起来,不过速度慢得感人。
你检查下stage3_max_live_parameters和stage3_max_reuse_distance,这两个调太大会让峰值显存飙高,改成1e8和1e6试试。还有最关键的一步,把optimizer换成AdamW,别用默认的,有时候是优化器本身占的显存超预期。
你这情况我原来也踩过坑,ZeRO-3的显存占用看着吓人其实很多是通信buffer和临时激活值,不完全是参数本身。offload_param和offload_optimizer的device设成cpu没问题,但别忘了把offload到nvme的路径也配上,光靠cpu内存有时候还是不够。另外试试把zero_force_ds_cpu_optimizer设成false,有些版本默认开这个会额外吃显存。还有个小技巧,把梯度检查点打开,能把激活值那部分省出一大块,我上次7B在两张卡上跑batch size 2就是这么过的。
offload设cpu试试,另外检查下allgather的buffer,7B两张卡确实紧但能跑。
把gradient_checkpointing打开,offload全扔cpu,batch再小点应该能稳。
我之前跑13B也这样,多半是通信峰值爆了,试试reduce_scatter的碎片优化参数。
显存冲到35G不是模型本身,是激活和通信峰值,关掉offload直接纯ZeRO-
我之前也遇到过一模一样的情况,最后发现是offload的device没配对,参数和优化器都放cpu之后显存直接掉到12G左右,你可以先确认下"device": "cpu"和"pin_memory": true这两个字段是不是都写了。另外ZeRO-3确实有通信缓冲区的额外开销,建议把zero_force_ds_cpu_optimizer设为false试试,有时候默认的cpu优化器会偷偷多占显存。还有个小坑是,如果用了gradient_checkpointing,记得把partition_activations打开,不然activation峰值照样爆。我自己最后是把batch size压到2,加上offload和checkpointing,才稳定跑完的,你那个35G的占用明显不正常,八成是offload没生效。
offload_param和offload_optimizer的device设成cpu只是基础,关键还得看offload是否真的生效——你确认过nvidia-smi里显存没涨但内存涨了吗?另外ZeRO-3在2卡场景下通信开销确实不小,试试把zero_force_opt_offload和zero_force_param_offload都开成true,同时把stage3_gather_16bit_weights_on_model_save改成false,能省不少峰值显存。我之前跑13B也遇到过类似问题,后来发现是gradient_checkpointing没开,开了之后7B两张40G随便跑,batch size还能调到4。你检查下是不是漏了这个,顺便看看all_gather的bucket大小设小点,比如5e8,能明显降低瞬时显存尖峰。
我之前也踩过这个坑,ZeRO-3在A100上跑7B确实不是无脑开offload就行。你提到显存直接冲到35G以上,我怀疑问题不在offload的device设置,而是你忘了关掉zero_force_ds_cpu_optimizer或者没设zero3_leaf_module,导致某些参数还是留在GPU上。另外,ZeRO-3的通信量比stage2大不少,多卡时每个step会做全量参数gather,这部分临时buffer很容易吃掉几个G,你可以试试把communication_data_type改成fp16,或者调低reduce_bucket_size和allgather_bucket_size,默认值太大了。我这边跑通7B用的配置是per_device_train_batch_size=1、gradient_accumulation_steps=8,然后offload_param的device设为cpu,offload_optimizer用nvme,但关键是把zero3_init的stage3_gather_16bit_weights_on_model_save设成true,否则保存checkpoint时又会爆。还有个小技巧,如果跑的是lora微调,可以直接把base model冻结,用stage=2加offload就够了,省很多心。你试试把zero_optimization.stage降回2,只开offload optimizer,看是不是就稳了?另外检查下你的optimizer是不是用的AdamW,DeepSpeed的CPUAdam需要单独配,不然会悄悄回退到GPU实现。
我之前也遇到过一模一样的坑,两张40G跑7B按理说ZeRO-3是够的,但你注意下offload_param的device设成cpu后,pin_memory要开,不然通信和拷贝会拖垮显存。另外检查下zero_force_ds_cpu_optimizer是不是false,有时候这个默认值会跟offload_optimizer冲突。我之前是把offload_optimizer的device设成nvme才稳住的,虽然慢点但至少不崩。还有个小技巧,把gradient_checkpointing打开,能省不少激活显存,batch size可以保持1但梯度累积步数调大点。
之前用ZeRO-3跑7B也踩过这坑,你试试把offload_optimizer.device设成nvme,光靠CPU offload有时反而会因PCIe瓶颈拖慢节奏,显存峰值不一定降。另外ZeRO-3的partition size和zero_force_ds_cpu_offload这两个参数也会影响内存分配,默认值在40G卡上很容易超。还有个小细节,gradient_checkpointing开了吗?不开的话activation占的那部分显存比你想的夸张。