最近在尝试用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总报显存不足,是我配置有问题吗?
全部回复
共 125 条我之前也踩过这个坑,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占的那部分显存比你想的夸张。
offload设cpu试试,另外记得把gradient_checkpointing打开,显存能省不少。
offload只offload到cpu的话,7B全参微调两张40G确实紧,试试把optimizer和param都放nvme,batch再压到1看看。
说实话我也踩过差不多的坑,ZeRO-3那个offload不是开了就完事,你检查下offload_param和offload_optimizer的device是不是都设成nvme了,光写cpu有时候反而会让显存和内存来回倒腾更吃紧。另外你两张卡40G跑7B理论上是够的,但关键在通信开销,ZeRO-3每个step都要做all-gather,这玩意儿在双卡环境下反而比ZeRO-2更费显存,因为 partitioned参数要临时重组。我建议你先试试stage=2加offload,batch size开到4,如果这能稳跑,说明瓶颈根本不在显存总量,而是碎片化和通信峰值。还有个容易被忽略的点,你checkpoint的保存频率和gradient checkpointing开了没,不开activation的话7B的中间激活值也能吃掉好几个G。我之前是改成stage=3但把zero_force_disable_cuda_graph设成true,顺手把pin_memory关掉,莫名其妙就稳了,你可以参考下。最后问一句,你用的DeepSpeed版本是0.9还是0.10?新版对LLaMA的kernel优化差挺多的。
40G两张卡跑7B全参微调本来就紧,ZeRO-3的显存大头其实在activation和gradient checkpointing上,你试试开gradient_checkpointing,再把offload_param和offload_optimizer都设成cpu,应该能压到30G以内。另外你确认下stage3的reduce_bucket_size和allgather_bucket_size是不是默认值,这俩调小点能省不少峰值显存,我之前调到5e7左右就稳了。还有个小坑,多卡通信的buffer是额外占显存的,但一般不会超过2G,主要问题还是activation,建议你换deepspeed的zero3加上cpu offload,batch size保持1,同时把序列长度砍到512试试。
同款配置踩过坑,ZeRO-3的显存占用有一部分是通信buffer和参数分区带来的固定开销,40G两张卡跑7B确实很紧。建议试试把zero_force_ds_cpu_offload打开,然后offload_param和offload_optimizer都设成nvme,同时把zero3_prefetch_factor调小到2,能省不少显存。另外你checkpoint的保存频率调低点,保存瞬间会复制全量参数,经常是OOM的罪魁祸首。我最后是把sequence length砍到512才稳定跑起来,你可以参考下。
试试把offload全扔CPU,optimizer的stage3_init也开着,batch再砍半,我7B单卡32G就是这么苟下来的。
ZeRO-3分区后每步通信量确实大,显存碎片也猛,建议加个--optimizer=adamw再调低zero_3_max_live_parameters试试。
offload设了device参数但没设cpu offload的pin_memory的话,其实数据搬运也会卡显存,我建议你把offload_param和offload_optimizer都显式写成cpu,然后加上pin_memory: true试试。另外ZeRO-3的partition size是按layer数切的,7B模型在40G卡上理论够,但你得注意all-gather的临时buffer,那个峰值很容易被忽略,建议把zero_optimization.allgather_bucket_size调小到5e7看看。我之前跑13B也是卡这个,调完就稳了,你可以先不开offload只调stage3试一轮,确认是通信峰值还是offload配置的问题。
我之前也卡在过这一步,后来发现ZeRO-3的显存占用不是线性的,它每张卡都要保留完整的模型参数切片和梯度,通信缓冲区也吃不少,尤其是A100 40G跑7B,理论上勉强够但实际峰值很容易超。你offload开了的话,先确认下是不是把参数和优化器状态都扔到CPU了,但激活值还在显存里,序列长度一长照样爆。我建议你开一下zero_force_ds_cpu_offload,还有把optimizer换成AdamW,别用默认的Lamb,那个在ZeRO-3下会额外分配状态。另外检查下offload_param的device是不是写的cpu,pin_memory要开成true,不然数据搬运也会卡到显存。我之前用单机双卡跑13B,batch size只能设1,但梯度累积调到16,反而比硬撑大batch稳定多了。你试着把zero3_allgather_bucket_size和zero3_reduce_bucket_size调小到5e7,能省不少峰值显存。如果还是崩,干脆试下ZeRO-2加offload,7B微调其实用不到stage3,很多教程都是拿多节点演示的,单机双卡反而得不偿失。