最近在尝试用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的显存占用看着吓人,其实是通信buffer和临时张量在作祟,不是模型本身占了35G。你试试把zero_force_ds_cpu_optimizer设成false,然后offload_param的device指定为cpu,offload_optimizer也同理,但别同时开pin_memory,有时候反而会爆。另外检查下gradient_accumulation_steps,如果设太大,反向传播时梯度累积也会临时吃显存。我最后是把zero_optimization.stage=3下的reduce_bucket_size和allgather_bucket_size都调小到5e8左右,才稳定跑完的。
offload设cpu试试,另外检查下allgather的buffer,这玩意儿吃显存也很凶。
你这情况我跑13B的时候也踩过,ZeRO-3不是光开stage=3就完事,offload_param和offload_optimizer的device都得显式设成nvme或者cpu,不然默认还是往显存里塞。还有个小坑是通信域初始化会吃不少显存,试试把zero_force_ds_cpu_optimizer设成false,或者干脆用ZeRO-2加offload,7B两张A100反而更稳。
另外你batch size调到1还崩的话,检查下是不是gradient_checkpointing没开,这个对显存影响巨大。我最后是stage=2+offload+gradient checkpointing跑通的,速度比ZeRO-3还快一点,你可以先拿这个组合试试。
试试把cpu_offload的pin_memory关掉,另外确认下zero_allow_untested_optimizer开了没,我之前卡在这俩上。
你这配置问题我大概率见过,ZeRO-3的partition是会把参数切到所有卡上,但通信buffer和forward里的临时激活值也吃显存,35G起步其实正常。offload_param设成cpu没问题,但offload_optimizer最好也一起开,不然optimizer状态还在GPU上。另外你检查下zero_force_ds_cpu_optimizer是不是false,有时候这个没设对会导致offload失效。还有个坑是A100的40G版本对7B来说其实偏紧,试试把gradient_checkpointing打开,能省不少激活显存。我这边用同样卡跑7B是能稳住的,但batch size只能设1,梯度累积开大点,你调下这两项再试试。
offload设cpu试试,但注意把zero_plus关掉,不然通信开销反而更大。
看到你这个情况我倒不觉得是配置写错了,更像是ZeRO-3在40G卡上的真实瓶颈。7B模型用fp16本身权重就占14G,加上Adam的momentum和variance另外28G,光优化器状态就42G了,你两张卡就算完全均分也要21G每卡,再算上激活值、梯度以及通信缓冲区,35G起步太正常了。offload_param和offload_optimizer的device设成cpu确实能缓解,但代价是PCIe带宽被吃满,训练速度会掉到令人发指的程度,而且你还要留意NVMe offload有没有真的生效,有时候配置里写了但实际没走那个路径。我怀疑你更大的问题是把ZeRO-3和activation checkpointing一起用,这俩结合时显存碎片化会很严重,建议你先把activation checkpointing打开,然后gradient_checkpointing也加上,同时把zero_force_ds_cpu_optimizer设成false,用回AdamW的cpu版试试。另外两张卡跑7B本来就紧巴巴的,你试试把zero3_max_live_parameters和zero3_max_reuse_distance调小一点,让参数更频繁地释放和重载,虽然慢点但能稳住不崩。我之前用4张A100跑13B才敢开ZeRO-3,7B的话其实ZeRO-2加offload可能更省心,你可以对比一下同batch size下的显存峰值。
我之前也卡在同样的坑里,后来发现offload_param和offload_optimizer必须同时设成cpu,而且zero_plus要开,不然参数还是留在显存里。另外ZeRO-3的通信确实会吃额外显存,你可以试试把reduce_bucket_size和allgather_bucket_size调小到5e8左右,能省不少。还有个小细节,检查一下是否开了activation checkpointing,那个对7B这种模型特别关键,不开的话激活值直接爆掉。
我最近也踩过这个坑,A100 40G两张卡跑7B其实挺悬的,ZeRO-3本身会把参数分片到每张卡上,但通信缓冲区和临时激活值也会吃掉不少显存,35G往上冲很正常。检查下你zero_optimization里reduce_bucket_size和allgather_bucket_size是不是默认值,调小到5e8甚至2e8能省不少。另外offload_param的device设成cpu没错,但别忘了pin_memory开true,有时候这能缓解碎片化导致的OOM。还有个偏方,把zero_force_ds_cpu_optimizer设成false,用adamw代替deepspeed的cpu adam,显存会稳一些。你要是试通了记得回来分享下config,我也在琢磨这配置。
offload_param和offload_optimizer的device设成cpu是基本操作,但关键得看offload_param的pin_memory开没开,不开的话反而会频繁触发cpu-gpu拷贝导致显存碎片化。另外ZeRO-3在每步通信时会临时分配一块和参数大小相当的buffer,两张卡40G算下来光通信预留就得吃掉6-7G,你可以试试把zero_force_ds_cpu_optimizer设成false,或者干脆换ZeRO-2+offload,7B模型其实用不到stage3。
我之前也踩过这个坑,ZeRO-3的显存开销不只是参数切分,每层forward/backward的all-gather和reduce-scatter会吃不少临时buffer,尤其A100 40G跑7B本来就紧。你可以试试把zero_offload_optimizer的device配成cpu,offload_param也全放cpu,但注意pinned memory要给够,不然换页反而更慢。另外检查下zero_force_ds_cpu_optimizer是不是false,有时默认优化器也会偷显存。实在不行就降到ZeRO-2加offload,7B两张卡其实够用,别迷信stage3。
offload设cpu试试,另外检查下allgather的buffer,ZeRO-3通信峰值很容易吃掉显存。
我之前也遇到过这个坑,ZeRO-3的显存开销不只是模型参数,还有通信缓冲和gradient partitioning,两张卡40G其实挺紧的。你试试把zero_optimization里的reduce_bucket_size和allgather_bucket_size调小一点,比如到5e7,能省不少。另外offload_param和offload_optimizer的device设成nvme会好一些,但CPU offload的话记得把pin_memory开上。还有个小技巧,模型加载的时候用low_cpu_mem_usage=True,能省点临时显存。
我之前也卡在这过,7B用ZeRO-3其实能跑但没那么宽裕,A100 40G两张得精打细算。你把offload_param和offload_optimizer都设成cpu,然后zero_optimization里加个“cpu_offload”:true试试,另外注意下allgather的bucket大小,调小点能省不少峰值显存。还有个小坑是transformers的gradient_checkpointing必须开,不开的话光激活值就够呛。你这报错是刚开始几步就崩还是跑一阵子才崩?如果是后者,可能是通信缓冲区累积了,可以试试把zero_force_ds_cpu_offload设成false。
我之前也卡在这过,后来发现主要是offload_param的device设成cpu之后,forward过程里参数要频繁在GPU和CPU间搬,通信开销会额外吃掉不少显存。你试试把offload_param关掉,只offload_optimizer,batch再小点,应该能稳住。另外ZeRO-3在all-gather的时候确实有峰值显存,可以用zero_force_ds_cpu_optimizer那个选项看看。最后建议把gradient_checkpointing打开,这一步很关键。
跑7B两张40G其实有点紧,我之前是开了offload_optimizer到nvme才勉强过。你报错在训练几步后,可能是activation峰值和参数碎片叠加了,试试把zero_quantile设成0.95,或者开zero_async_allgather,这俩能减少通信时的临时buffer。另外确认下你的模型是bf16不是fp16,A100对bf16更友好,显存占用能低不少。
我怀疑你offload_param的device写成了cpu但没加pin_memory,这样反而会显存溢出。之前我直接抄官方example改成stage=3,也是炸,后来把offload_param的device设成nvme,offload_optimizer也丢nvme,per_device_train_batch_size=1,gradient_accumulation_steps=8,居然稳住了。不过速度会慢
offload_param和optimizer的device都设成cpu试试,另外降低communication_data_type为fp16能省不少显存。
offload设cpu后记得开pin_memory,不然通信开销会反噬显存,试试zero_plus的infinity选项。
你的配置大概率没问题,问题出在ZeRO-3的通信开销和offload的粒度上。7B模型在40G卡上跑,理论上参数+梯度+优化器状态全offload到CPU确实能塞下,但训练步数一多,通信缓冲区和临时激活值会悄悄吃掉显存,建议把zero_force_ds_cpu_optimizer设为false,同时检查下optimizer是不是用了DeepSpeed自带的,另外试试offload_param.device设为nvme,虽然慢点但能稳住。
我之前用单张A100 40G跑13B的LoRA,ZeRO-3开offload后显存峰值基本锁在32G左右,你两张卡反而更容易炸,可能是all-gather的同步开销变大了。可以加个zero_allgather_bucket_size=5e8,再把reduce_bucket_size调小,能明显降峰值。还有个小技巧,把activation_checkpointing开起来,能省不少激活值,代价是慢10%左右,但稳很多。
另外你试过把per_device_train_batch_size降到1后,有没有看nvidia-smi确认是不是只有一张卡爆?有时候gradient_accumulation_steps设得太大,会导致隐式batch增大,显存是阶梯式上涨的。建议直接贴一下完整config
看到你说offload也开了还是OOM,我第一反应是检查一下offload的目标设备是不是设成了nvme,因为有些教程默认cpu但实际内存不够也会炸。不过你两张A100 40G跑7B,按理说纯ZeRO-3不开offload都应该勉强够,35G占用有点反常,我怀疑是activation checkpointing没开,这玩意儿不开的话激活值能吃掉巨量显存,尤其序列长度一上来直接翻倍。另外ZeRO-3确实有通信缓冲区的额外开销,但通常也就几个G,不至于让你崩,你可以试试把“reduce_bucket_size”和“allgather_bucket_size”调小到5e7甚至2e7,能明显降峰值。我自己的经验是,offload_param设cpu没问题,但offload_optimizer如果也丢cpu,训练速度会慢到怀疑人生,而且如果cpu内存小于64G,照样会触发swap导致假死。还有个小坑,你检查下是否用了gradient_checkpointing,以及模型加载时是不是先load到cpu再转到gpu,如果直接load到gpu再offload,峰值会瞬间爆掉。最后建议你开一下“zero_force_ds_cpu_optimizer”为false,有时默认的cpu Adam会偷偷多占显存。你试试把batch减到1的同时,把gradient_accumulation_steps调到8,然后观察下nvidia-smi的实时变化,应该能定位是瞬时峰值还是持续增长。
这配置跑7B确实有点极限,ZeRO-3的通信开销和碎片化比想象中吃显存,你试试把zero_3_use_micro_tensors开成true,同时reduce_scatter改成gather,能省不少。另外offload别全甩cpu,offload_param放nvme试试,但得看你的存储速度。我之前用四张A100跑13B,batch size设2才稳,单卡40G跑7B真得精打细算。