最近在尝试用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 条offload设cpu之后记得把optimizer也扔过去,光开param没用,我这么配7B单卡都能跑。
ZeRO-3的显存占用高其实不全是offload的锅,通信buffer和activation checkpointing也会吃不少,你试试把activation checkpointing开起来,能省下很大一块。另外offload_param和offload_optimizer都设成cpu,但注意offload_param要配合pin_memory,不然反而会因为频繁换页拖慢甚至爆显存。我之前跑13B用四张A100也遇到过类似问题,后来发现是gradient_accumulation_steps设太小导致每步通信太频繁,你可以调大一点试试。
说实话ZeRO-3在7B这个规模上翻车太常见了,我一开始也以为是offload配置的问题,后来排查下来发现是通信缓冲区的锅。你试试把zero_force_ds_cpu_optimizer设成false,然后zero3_round_robin开一下,这两个参数经常被教程漏掉。另外你的offload_param和offload_optimizer如果都设成cpu,那pin_memory必须开,不然CPU和GPU之间的传输会卡成瓶颈,显存反而释放不干净。我自己的经验是,两张A100跑7B其实没必要硬上ZeRO-3,ZeRO-2加offload optimizer就够了,除非你序列长度特别长。你还可以看一眼stage3_gather_16bit_weights_on_model_save,这个默认true会在保存模型时把所有参数聚回GPU,训练过程中如果触发了checkpoint,那一下就能把显存顶爆。我怀疑你崩的时机是不是正好在保存或者评估的时候?如果是的话,把save_interval调大或者临时关掉验证集,能续命很久。最后一个小技巧,partition_activations和cpu_offload一起用,能把激活内存也挪走一部分,代价是速度慢个20%但稳很多。
我之前也遇到过一模一样的情况,7B+ZeRO-3双卡40G按理说够的。你检查下是不是把offload全都丢到CPU了,但NVMe offload没开,导致参数和优化器状态在CPU和GPU间频繁搬运反而增加峰值显存。另外可以试试把zero_force_ds_cpu_optimizer设成false,有时候这个默认值会坑人。
还有个小细节,ZeRO-3的通信确实会吃显存,建议把zero_quantized_weights和zero_quantized_gradients打开,能省不少。我最后是把gradient_checkpointing开了,加上把offload_param.device设成nvme,才稳定跑起来,你可以参考下。
我也遇到过一模一样的情况,7B加ZeRO-3在双卡A100上确实容易翻车,但问题往往不在stage本身,而在offload的配置细节。你试试把offload_param和offload_optimizer的device都设成nvme,同时给offload_param加上pin_memory=true,这样能显著降低峰值显存,不过要确保你的NVMe盘读写够快,不然训练会慢到怀疑人生。
另外你提到的通信开销确实存在,ZeRO-3在每步前向反向都要做all-gather,这会在显存里临时存全量参数,所以光靠减小batch size治标不治本。我后来是把zero_optimization.allgather_partitions设成true,再把reduce_bucket_size和allgather_bucket_size都调到5e8,显存瞬间降了6G多。
还有一个坑是混合精度,如果你没开fp16,显存占用会直接翻倍。我建议你在deepspeed config里显式加上fp16: enabled: true,同时把loss scale设为0(让系统动态调整),这样7B在40G卡上跑batch size 2应该没问题。
如果你实在调不动,可以退而求其次用ZeRO-2加offload,虽然参数梯度不切分,但7B模型本身也就14G左右权重,offload到CPU后显存压力小很多,速度反而可能比ZeRO-3还快,因为省去了频繁的all-gather通信。我最后就是用ZeRO-2跑通的,batch size能上到4,稳定不崩。
我之前也卡在过这,7B+ZeRO-3双卡40G确实紧,但你的显存涨到35G不太正常。offload_param和offload_optimizer的device设成cpu就行,不过注意offload_param要配合pin_memory开,不然CPU换页会拖慢还占显存。另外ZeRO-3分区后每张卡只存1/2的模型状态,但通信缓冲区和activation峰值会额外吃几个G,你可以试试把zero_force_disable_cpu_offload打开,或者干脆把gradient_checkpointing也开了,能省不少activation显存。我最后是batch_size=1+offload全开+gradient checkpointing才稳住的。
说到这个我太有感触了,之前用ZeRO-3跑13B也踩过一模一样的坑,最后发现根本不是显存不够,是通信缓冲区在捣鬼。你试试把zero_optimization.allgather_bucket_size和reduce_bucket_size都调小到5e7左右,默认的2e8在双卡A100上反而会预留大量显存给all-gather操作,实际训练时峰值直接爆炸。另外offload_param的device设成cpu没问题,但offload_optimizer的pin_memory一定要开false,否则内存和显存之间频繁拷贝会拖垮整个流水线。还有个细节,ZeRO-3下每个layer的参数是分片的,前向和反向时会发生临时的gather,这本身就要额外占用接近单层参数两倍的显存,你把gradient_checkpointing打开能省不少,代价是慢大概20%。如果还是崩,建议看一眼NVLink是否真的启用了,两张卡如果走PCIe通信,那ZeRO-3的同步开销会大得离谱,我试过把stage改成2+offload反而更稳。你那边报错是纯OOM还是带cuda error,如果是后者,可能还要查一下是否混用了不同代的卡。
之前也踩过这个坑,ZeRO-3的显存开销确实比想象中大,尤其是多卡通信的buffer和碎片化问题,40G两张卡跑7B很极限。我后来是关掉offload_param,只offload_optimizer,再把zero_plus把communication_data_type改成fp16,勉强稳住了。另外检查下你用的transformers版本,太老的话对LLaMA的layer norm有额外显存占用。你training的sequence length是多少?如果超过1024,建议先砍半试试。
offload设cpu试试,还有你checkpoint留够余量没,35G看着像是激活值爆了。
我之前也遇到过一模一样的情况,7B加ZeRO-3在40G卡上跑到后面必炸。你试试把offload_param和offload_optimizer的device都设成nvme,然后给offload_optimizer的pin_memory开成false,能省不少显存。另外ZeRO-3确实有通信缓冲开销,你把zero_force_opt_offload开一下,再配合gradient_checkpointing,基本能压到30G以下。不过说实话两卡A100跑7B还是有点勉强,我后来换4卡才稳,你如果方便的话还是多搞两张卡省心。
offload_param和offload_optimizer的device都得设成cpu,另外试试把zero_force_opt_offload开成true,显存能降不少。
offload设cpu试试,另外把zero_plus远程内存关掉,A100 40G跑7B不该爆的。
ZeRO-3通信峰值吃显存很凶,你试试把分区数调小或者换ZeRO-2,省心很多。
看到你这个情况我第一反应是offload配置可能真有点问题,但更大概率是ZeRO-3在40G卡上的实际可用显存比理论值低不少。我之前在两张A100上跑13B模型也遇到过类似现象,最后发现是通信缓冲区占掉了将近6G,这还没算上activation和临时梯度。你那个batch size调到1还是崩,建议先看下zero_force_ds_cpu_optimizer和zero_offload_optimizer是不是同时生效了,有时候offload到NVMe反而比CPU更省显存但速度慢一些。另外你可以试试把stage3_gather_16bit_weights_on_model_save关掉,训练过程中它会在forward前把完整权重拉回GPU,那个瞬间显存峰值很吓人。还有个冷门技巧是把stage3_prefetch_bucket_size和stage3_param_persistence_threshold调小到几千,虽然通信次数变多但能压住峰值。如果还是OOM,干脆用ZeRO-2加offload optimizer,7B模型在两张40G上其实完全够跑,没必要死磕ZeRO-3。最后检查下是不是gradient_checkpointing没开,这个对激活显存影响巨大,开了之后通常能省一半以上。
offload设成cpu基本能压住,但记得把pin_memory关掉,不然显存照样爆。
offload后反而更吃显存,多半是通信缓冲没调,试试把zero_force_ds_cpu_optimizer设false,再把reduce_bucket_size调小点。
我之前也卡在这过,40G双卡跑7B理论够但ZeRO-3的显存峰值很迷。你试试把zero_force_opt_optimization设成true,然后offload_param的device别用cpu,改成nvme试试,虽然慢点但能稳。另外多卡通信的buffer会临时吃几个G,你可以把zero3_allgather_bucket_size调到5e7左右,别用默认值,我调完爆显存频率低了很多。还有个骚操作是开zero3_round_robin_gather,把权重收集打散到两步,亲测有效。
我也踩过这坑,ZeRO-3的offload参数别看教程写个device: cpu就完事,实际得把offload_optimizer的pin_memory开起来,不然碎片化很严重。另外你两张卡互联是NVLink还是PCIe?带宽不够的话通信开销会把显存缓冲区撑爆,试试把zero_force_ds_cpu_optimizer设成false,用回原生AdamW能省不少。还有个偏方,把model并行切分维度调成4,虽然慢点但比反复OOM强。
我之前也遇到过一模一样的情况,A100 40G两张跑7B,ZeRO-3配offload照样炸。你试试把zero_force_ds_cpu_optimizer设成false,然后offload到nvme而不是cpu,虽然慢点但显存能压下来。另外多卡通信的buffer大小很关键,zero_optimization.allgather_bucket_size和reduce_bucket_size调小到5e7左右,能省不少临时显存。还有个坑是activation checkpointing没开,这个不开的话激活值直接吃掉一大块,开了之后batch size可以回到2。你检查下这几项,应该能稳住。
offload设成cpu试试,另外把zero_plus的通讯池开大点,A100 40G跑7B不该爆。
offload_param和optimizer都指到nvme试试,我上次这么配才稳,通信开销比想象中大。
我之前也卡在过这步,7B用ZeRO-3按理说40G两张卡是够的,但你把offload全开反而可能让通信和参数搬运挤爆显存。建议试试只offload optimizer,param留在GPU上,然后zero_quantized_weights开一下,显存能省不少。另外跑之前确认下CUDA_VISIBLE_DEVICES是不是两张卡都可见,我遇到过DeepSpeed只认到一张卡然后疯狂OOM的情况。