最近在微调一个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 条八成是模型加载时没走from_pretrained的device_map,ZeRO-3得配合deepspeed.initialize重新包装,试试直接load模型到CPU再转。
我之前也卡这,后来发现offload加zero_force_opt_offload这参数才行,你翻翻版本更新日志。
同款配置踩过坑,你多半是没开zero_3的reduce_bucket_size和stage3_prefetch_bucket_size,默认值对7B来说太大了,显存瞬间被通信缓冲区吃满。另外模型加载别用from_pretrained直接读,先用meta device初始化再deepspeed.initialize,不然光权重就占30多G。还有个小坑,offload到CPU后要确认pin_memory关了,不然内存页锁定会拖垮PCIe带宽。我最后是ZeRO-3 + offload + batch1硬跑起来的,但速度慢到怀疑人生,后来换了LoRA才舒服。
检查下zero_3_leaf_modules是不是没配,Llama的decoder层得手动标出来,不然容易爆。
试试把zero_optimization里的stage3_gather_16bit_weights_on_model_save和reduce_scatter都显式配上,另外确认下cpu_offload的pin_memory关没关。
A100 80G跑7B按理说ZeRO-3不该第一步就炸,你是不是把offload的device类型设成nvme了?我之前踩过这个坑,cpu offload得配合pin_memory和足够大的swap空间。另外检查下是否开了zero_force_ds_cpu_optimizer,有时候默认配置反而触发隐形的显存分配。实在不行换ZeRO-2加activation checkpointing,7B用这个组合基本能稳住,速度还更快。
单卡A100 80G跑7B,ZeRO-3不是必须的,反而容易因为通信开销和碎片化把显存搞崩。你试试直接用ZeRO-2,配合offload optimizer,7B全参数微调大概需要60-70G,卡着边能过,但你要把eval和checkpoint的临时显存都算进去。另外确认下你是不是用from_pretrained加载的,有时候模型本身占的显存比预期高,可以先打印一下torch.cuda.memory_summary看看是哪个环节炸的。我之前遇到过类似问题,最后发现是tokenizer填充导致序列长度没对齐,batch size=1也没用。
看到你说optimizer和param都offload了还OOM,大概率是模型加载时没有用meta device初始化,ZeRO-3必须配合from_pretrained(..., low_cpu_mem_usage=True)或者先建空模型再load_state_dict,不然光权重就吃满显存了。另外7B在单卡上其实没必要硬上ZeRO-3,ZeRO-2加offload足够,甚至直接LoRA更省心,A100 80G跑7B全参微调本身就有点勉强。建议先试试只offload optimizer,不offload param,batch size设1,看能不能跑通第一步,如果还崩就检查一下transformers版本和DeepSpeed是否匹配。
模型加载用from_pretrained时加low_cpu_mem_usage=True试试,ZeRO-3还要配zero_force_ds_cpu_optimizer=False。
offload全开但batch size=1还爆,大概率是CPU内存带宽瓶颈,先试试把optimizer offload关掉只留param。
offload都开了还OOM,八成是模型加载时没走deepspeed的init,得用from_pretrained带device_map。
试试把zero_force_opt_offload设成true,顺手把pin_memory关掉,我上次这么弄好的。
说实话你这情况我太熟了,之前调6.7B的时候也卡在第一步,后来发现是HuggingFace的from_pretrained默认把模型直接load到GPU上,ZeRO-3还没接管就爆了。你得先让模型在CPU上初始化,比如用meta device或者先load到CPU再转成DeepSpeed engine,顺序错了后面全白搭。另外offload到CPU不是万能的,你把optimizer和param都off了,但gradient还是留在显存里,而且CPU offload的带宽瓶颈在第一步尤其明显,A100 80G单卡跑7B按理说纯ZeRO-3不开offload都够,你先试试不开offload只开ZeRO-3,说不定反而能跑。还有你检查一下activation checkpointing开了没,这个省显存效果比offload直接得多,不开的话即使不OOM也会在反向传播时炸。最后建议把zero_force_ds_cpu_optimizer设成false,有时候DeepSpeed会强制用CPU优化器导致额外开销。你要是还不行,干脆试试ZeRO-2加offload,7B参数用80G卡其实ZeRO-2就挺稳的,别迷信ZeRO-3。
单卡A100 80G跑7B其实ZeRO-2就够了,ZeRO-3在这规模下反而会引入大量通信和碎片化开销,尤其你把参数也offload了,第一步的forward/backward都要频繁跟CPU换数据,OOM多半是临时激活值或者碎片导致的。建议先试试ZeRO-2加offload optimizer,batch size开1,如果还崩就检查一下huggingface的model.to('cuda')是不是和DeepSpeed的engine初始化重复占显存了。我之前遇到过类似情况,最后是把模型先load到CPU,再用deepspeed.initialize接管,别自己提前搬GPU。你用的是transformers的Trainer还是自己写训练循环?后者的话记得关掉model.half(),让DeepSpeed自己处理精度。
单卡A100 80G跑7B微调其实ZeRO-2就够了,ZeRO-3主要是为多卡跨节点设计的,单卡上反而会引入大量通信和碎片化开销,起步阶段就爆显存很常见。你试试把offload全关掉,只开ZeRO-2,batch size调成1,应该能稳过第一步。另外检查下你是不是把模型直接加载到GPU再转成ZeRO-3的,正确做法是先加载到CPU,再让DeepSpeed自己调度,不然初始占用的显存直接炸。我之前也是卡在这步,后来改用ZeRO-2加activation checkpointing,7B照样能塞进80G,还留了余量调参。
之前跑13B也遇到过这坑,ZeRO-3默认会把参数也分片,你加载权重时得用from_pretrained里的zero_init配合deepspeed.initialize,直接load_state_dict会瞬间爆显存。另外offload参数别全开,param offload其实可以关掉,光开optimizer offload对7B来说就够省了,A100 80G单卡跑7B全参数微调本来就挺极限的。还有个小技巧,把zero_force_ds_cpu_optimizer设成false,有时候能避开一些兼容性问题。我最后是换成ZeRO-2加offload跑通的,速度还比ZeRO-3快不少,你可以先试试。
我猜你大概率是卡在ZeRO-3的partition逻辑上了,它会把每层参数都切片到所有卡上,但单卡场景下反而会因为通信和内存碎片化额外吃显存。你试过把zero_optimization下的stage改成2,然后开offload_optimizer的pin_memory吗?我之前跑13B就是靠这个组合在80G上勉强塞下的。另外你确认过模型加载时是不是用了meta device?如果用普通from_pretrained加载,光初始权重就占满显存了,根本轮不到ZeRO接管。还有个坑是transformers版本和deepspeed的兼容性,有些老版本会在step前预分配全量梯度buffer,换个新点的版本能省不少。最后建议你开一下zero_force_ds_cpu_offload和zero_offload_optimizer的cpu_offload_use_pin_memory,这俩参数能明显减少CPU侧的压力,但记得把CPU内存给够,不然会反过来拖慢速度。如果还是崩,直接看日志里是哪个tensor超了,八成是attention mask或者position id被重复复制到每张卡上了,手工切一下输入shape就行。
试试把zero_optimization里的reduce_bucket_size调小点,再关掉overlap_comm,我之前这么弄就好了。
说实话你这个情况我太熟了,之前用ZeRO-3跑13B的时候也栽过一模一样的跟头。单卡A100 80G跑7B按理说ZeRO-2就够了,ZeRO-3的通信开销反而大,而且它把参数切到多卡上,单卡场景下根本发挥不了优势,纯属给自己找麻烦。你先试试把zero_optimization改成stage 2,offload还是全开,但记得把pin_memory设成true,这玩意儿能省不少显存碎片。另外检查一下你的模型加载是不是用了from_pretrained的默认dtype,强烈建议加载时直接torch_dtype=torch.bfloat16,不然光是fp32的权重就占掉14G,加上优化器状态不死才怪。还有个小坑,如果你用了gradient_checkpointing,记得要在model.gradient_checkpointing_enable()之后再去配置DeepSpeed,顺序反了会让CPU offload失效。我猜你八成是没设置zero_force_ds_cpu_optimizer=false,这个参数不关的话,就算offload到CPU也会走GPU的混合精度优化器,照样爆显存。最后实在不行就换个思路,用QLoRA加4bit量化,7B模型微调显存能压到10G以内,速度还比ZeRO-3快,别死磕一个方案。
试试把cpu_offload的pin_memory关掉,A100上ZeRO-3经常被这玩意儿坑。另外确认下你加载模型是不是用的from_pretrained带device_map=auto。
我上次也这样,后来发现是tie_weights没设false,导致embedding重复占显存,改成false直接跑起来了。
之前也在A100上踩过这个坑,ZeRO-3默认会按层切分参数,但如果你用from_pretrained直接加载权重,它会先完整载入再分片,那一步就爆了。可以先试试zero_force_opt_offload或者把stage3_gather_16bit_weights_on_model_save关掉,另外确认下你是不是忘设了stage3_prefetch_bucket_size,这个不调小也会吃显存。我后来换了ZeRO-2加offload,7B跑起来反而稳,速度还快不少,你可以先拿ZeRO-2跑通再回头调3。
offload都开了还崩,八成是模型加载时把权重全塞显存了,试试用from_pretrained带low_cpu_mem_usage=True。
说个可能的原因,ZeRO-3默认会吃掉比ZeRO-2多得多的显存用于管理参数分片和通信缓冲区,你光开offload可能不够,得把stage3_gather_16bit_weights_on_model_save和reduce_scatter这些参数也调一下,尤其是stage3_prefetch_bucket_size,默认值在7B上经常爆。另外你把offload的pin_memory开了没?不开的话CPU传输会卡住显存释放节奏,第一步崩很可能是这个。我之前用8卡跑13B也遇到过,后来把zero_force_ds_cpu_offload设成true才稳。实在不行就退回ZeRO-2加offload,7B在单卡A100上其实够用,别迷信ZeRO-3。