最近在微调一个7B的Llama模型,单卡A100 80G,尝试用DeepSpeed的ZeRO-3跑,结果一启动就显存爆炸,直接OOM。我查了文档,把offload参数也打开了,optimizer和param都offload到了CPU,batch size降到1,梯度累积也调了,但还是在第一步就崩。
我怀疑是不是我的模型加载方式有问题?或者ZeRO-3需要特殊的模型并行配置?看网上有人说ZeRO-2就够用,但我怕显存不够。有没有大佬遇到过类似情况?是不是我漏了什么关键参数?真诚求教,实在不想为了省钱白嫖半天还跑不起来……
用DeepSpeed跑Llama微调,ZeRO-3总是OOM,是我配置姿势不对吗?
全部回复
共 177 条八成是模型加载那步没走对,ZeRO-3的权重是分片后按需加载的,不能直接一口气load进显存再交给deepspeed。我之前遇到过类似坑,得用from_pretrained(..., device_map="auto")配合zero3的init_context,或者干脆用deepspeed的zero.Init()包一下模型定义。另外offload到CPU后,A100 80G跑7B理论上不该炸,你检查下是不是把train_batch_size和train_micro_batch_size_per_gpu搞混了,前者会隐性放大显存占用。还有个笨办法,先用ZeRO-2跑通,确认数据流没问题再切回去,至少能排除是不是配置本身写崩了。
试试把zero_optimization的stage3_gather_16bit_weights_on_model_save关掉,还有offload的pin_memory开一下,我这么调好的。
试试把zero_optimization里的stage3_gather_16bit_weights_on_model_save和reduce_scatter都显式配上,再不行就换zero-2加cpu offload,7B真没必要硬上zero-3。
单卡A100 80G跑7B其实ZeRO-2就够了,ZeRO-3的通信开销和显存碎片反而容易在单机场景翻车。你试试把offload全关掉,只用ZeRO-2加CPU offload optimizer,batch size设1应该能跑起来。另外检查下是不是HuggingFace加载模型时把权重放到了GPU0上,可以先load到CPU再封装。我之前遇到过类似问题,最后发现是zero_allow_untested_optimizer没设成true,你试试看。
试试把zero_optimization改成stage2加offload,7B单卡真没必要上ZeRO-3,通信开销反而吃显存。
试试把zero_optimization里的stage3_gather_16bit_weights_on_model_save和reduce_bucket_size调小点,之前我被这俩坑过。
先检查下HF的模型加载是不是默认把权重放GPU上了,ZeRO-3要配合deepspeed.zero.Init上下文才能分片加载,不然光load权重就占满显存了。另外offload到CPU后记得设一下zero_force_disable_cpu_offload或者把pin_memory关掉,有时候反而会拖慢触发OOM。我之前调7B也踩过这坑,最后发现是torch版本和DS的兼容性问题,换个版本就好了。还有个小技巧,可以先试试stage 2配offload,显存占用其实和stage 3差不了太多,但省心不少。
单卡A100 80G跑7B其实ZeRO-3没必要,offload到CPU之后通信开销反而可能把显存卡在第一步的临时buffer上,试试把zero_optimization里的reduce_bucket_size和stage3_prefetch_bucket_size调小一点,比如降到5e7。另外确认下你是不是用了from_pretrained直接加载,最好先meta初始化再deepspeed.initialize,不然每张卡都会先复制一份完整权重。我之前遇到类似情况是忘了关掉模型本身的gradient_checkpointing,开了之后显存直接掉一半,你可以交叉验证下。
你试过把zero_force_ds_cpu_optimizer设成false吗?我之前也卡在这,有时候offload optimizer到CPU反而会触发额外的显存开销,尤其是7B这种规模,光参数拷贝就够呛。另外建议先确认一下你的huggingface模型是不是用from_pretrained直接加载的,最好配合deepspeed的initialize_model并行加载,不然模型会先完整进显存再被切分,第一波就爆了。我最后是换回ZeRO-2加上CPU offload的optimizer才跑通的,显存峰值稳定在60G左右,你可以试试。
单卡80G跑7B其实ZeRO-2就够了,ZeRO-3的通信开销在单卡场景反而会放大,而且offload到CPU后第一步要初始化全量参数,很容易瞬间爆显存。你试试把zeRO-3的stage3_gather_16bit_weights_on_model_save和stage3_prefetch_bucket_size调小点,或者直接换ZeRO-2加offload optimizer,我上次就是这么跑通的。另外检查下是不是huggingface加载模型时把weights也放到GPU上了,用low_cpu_mem_usage=True能省不少临时显存。
ZeRO-3 offload参数要配cpu_offload加pin_memory,另外试试stage3_gather_16bit_weights_on_model_save,我上次就是这么救回来的。
单卡A100 80G跑7B微调,理论上ZeRO-3不该一启动就炸,你八成是掉进“offload全开”的坑了。optimizer和param都往CPU塞,反而会让通信开销剧增,而且ZeRO-3默认会按层切分模型,加载时如果没配合stage3_gather_16bit_weights_on_load=True,权重收集那一下就会瞬间吃满显存。我之前也遇到过类似情况,后来发现是HuggingFace的from_pretrained加载方式跟DeepSpeed的zero.Init冲突,你得先把模型用deepspeed.zero.Init包起来,或者干脆用trainer集成的deepspeed参数,别自己手动初始化引擎。另一个容易漏的点是,你得确认pin_memory和num_workers没把CPU内存撑爆,因为offload到CPU后,如果CPU内存不够或者swap频繁,第一步前向传播就会卡死甚至报错,表现跟OOM很像。其实单卡80G,你试试ZeRO-2加上optimizer offload就够了,7B模型参数大概14G,梯度加优化器状态算下来也就30G上下,A100完全能扛住,没必要上ZeRO-3。如果你非要ZeRO-3,检查下是否设置了zero_force_opt_offload=false,有时候默认会强制把优化器状态也offload掉,反而拖慢速度。最后问一句,你用的DeepSpeed版本是0.9还是0.10?新版对Llama的attention实现有专门优化,老版本兼容性坑特别多,升级一下可能就直接解决了。
ZeRO-3的显存碎片问题很常见,试试开zero_force_opt_offload再加stage3_gather_16bit_weights_on_model_save。
7B单卡A100开ZeRO-3其实没必要,先查下stage3_gather_16bit_weights_on_model_save和cpu_offload的load是不是没配。
单卡80G跑7B还用ZeRO-3确实有点反常,一般第一步就崩多半是stage3把参数切分后反而引入了额外的通信buffer和临时显存,加上offload到CPU如果pin_memory没配好,反而更容易炸。我之前也踩过这个坑,后来发现是transformers加载模型时没设low_cpu_mem_usage,导致CPU端先占了一大块再往GPU搬。你可以先换ZeRO-2试试,7B单卡80G基本够用,真不行再查查是不是flash attention或者梯度检查点没开。
ZeRO-3单卡跑7B确实容易炸,试试stage3_gather_16bit_weights_on_model_save和sub_group_size调小点?
ZeRO-3第一步就炸大概率不是显存不够,而是stage3的param partition在初始化时要把所有参数打散,如果你的模型加载代码没配合deepspeed.initialize,权重会先完整占一份再分片,80G直接撑爆。我之前也踩过这坑,换ZeRO-2基本就没事了,7B单卡80G微调完全够用,offload反而拖慢速度。你可以先跑个ZeRO-2加fp16试试,确认能起来再调stage3,别一上来就拉满。