最近在尝试用DeepSpeed微调一个7B的LLM,显卡是两张3090(24G)。参考了几个开源项目的配置,把ZeRO Stage调到了2,offload_optimizer也开了,但跑起来大概十几个step之后就报CUDA OOM。
我看nvidia-smi,显存占用并没有满,但就是报错。后来试了把train_batch_size降到1,gradient_accumulation设成8,还是不行。
有点迷茫:是ZeRO的partition策略没生效,还是我的模型本身太大,两张卡真的带不动?
或者是不是我漏了offload_param?看网上有人说Stage 2要配合offload_param才能稳,但那样速度会不会太慢?
求有经验的老哥指点一下,这种配置到底该怎么调,或者说7B微调最低需要多少显存?谢谢!
用DeepSpeed微调7B模型总是OOM,是ZeRO配置问题还是我显存真不够?
全部回复
共 95 条说实话看到你说显存没满但报OOM,我第一反应是碎片化问题,PyTorch的缓存分配器有时候会预留显存不释放,看着nvidia-smi有空余,实际可用的连续块不够。你可以试试在训练脚本里加torch.cuda.empty_cache(),或者设PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:128,这招我救急用过好几次。
但7B模型两张24G卡,ZeRO Stage 2理论上勉强够,关键是你开没开activation checkpointing?这个才是吃显存的大头,尤其是序列长度一上来,激活值能占掉好几个G。你光调batch size和offload optimizer,没提gradient checkpointing,我怀疑是这块爆了。
另外你确认下offload_optimizer是真正生效了吗?有时候配置文件里写了,但DeepSpeed版本不一样,参数名或者stage没对齐,会静默回退到Stage 1。可以打印一下deepspeed config的最终值看看。
至于offload_param,Stage 2其实不需要,那是Stage 3才强制配的。但如果你把optimizer offload到CPU,参数还在GPU上,那显存大头还是模型权重加梯度,7B全精度光权重就14G,再加梯度和Adam状态,两张卡确实紧。
我个人经验是,3090的24G跑7B微调,ZeRO Stage 2配offload optimizer加上activation checkpointing,batch size 1是能跑的,但得把序列长度压到1024以下。你如果任务允许,试试把max_seq_len砍半,可能比折腾offload更直接。
最后问一句,你用的是LoRA还是全参数微调?如果是全参数,那两张卡带7B基本是极限,建议换LoRA或者QLoRA,显存占用能降一半还不止,效果差不了太多。
offload_param也加上试试,3090跑7B全参微调确实紧巴,两张卡stage2理论够但得把能offload的都offload掉。
我遇到过类似情况,offload_param真得开,不然ZeRO2白配。两张24G跑7B勉强,把batch再调小试试。
把offload_optimizer改成offload_param试试,我之前就是这么救回来的,7B全参数微调两张卡确实紧巴巴的。
这问题我上周刚踩过,3090跑7B按理说ZeRO-2加offload是能跑的,但你这报错挺典型,显存没占满却OOM大概率是碎片化或者临时显存峰值炸了。你试试把offload_optimizer换成offload_param,或者两个都开,代价是慢点但稳。另外查下你是不是忘了开activation checkpointing,那个省显存效果比调batch size明显多了。如果还不行,干脆降到ZeRO-3,虽然通信开销大,但两张卡跑7B应该更从容。
跑7B两张3090确实紧,offload_param也得开,不然ZeRO2只卸优化器状态不够。
梯度累积救不了显存峰值,试试把seq_len砍半或者换8bit加载,应该能稳。
显存没满但OOM大概率是碎片化问题,试试开--optimizer的cpu_offload加pin_memory,或者换NVMe offload。
遇到过类似情况,之前用单张A100跑7B也莫名其妙OOM,后来发现是activation checkpointing没开,峰值显存直接翻倍。你这配置理论上两张24G是够的,但Stage2只切优化器状态,模型参数和梯度还是完整副本,建议把offload_param也打开试试,虽然慢点但能腾出不少空间。另外检查下transformers版本,有些老版本的模型加载时会把临时buffer留在显存里,换个新点的版本可能就好了。
3090的24G显存跑7B全参微调本来就紧,但你这情况更像是碎片化或者临时显存峰值的问题,不是单纯容量不够。DeepSpeed的Stage 2只分模型参数,优化器状态已经offload了,但激活值还在显存里,把activation checkpointing打开试试,能省一大块。另外确认下你是不是在config里把zero_optimization和gradient_accumulation的配置写对了,有时候参数没读进去会静默跑成stage 0。offload_param在Stage 2里确实可开,但主要省的是显存占用,如果报错时nvidia-smi没满,反而更像峰值瞬间爆了。建议先开activation checkpointing,再把max_seq_len降到512试一轮,大概率能稳住。
3090跑7B按理说Stage 2+offload是能动的,但你这种情况更像是碎片显存或者激活值峰值爆了,而不是模型权重本身放不下。建议你开下--max_grad_norm 1.0顺便把zero_force_ds_cpu_optimizer设成false试试,之前我遇到过类似报错,纯粹是优化器状态没真正offload到CPU。另外检查下hidden_states是不是被保留做checkpointing了,开activation_checkpointing能省出好几个G。两张卡24G其实够呛,但跑起来应该没问题,先别急着怀疑partition策略,把tensorboard的memory曲线打出来看看哪个step涨得最凶。
3090的24G跑7B全参微调本来就紧,光模型权重加梯度就快20G了,你还开了offload_optimizer,但ZeRO Stage 2只切优化器和梯度,参数还是每卡一份,所以显存大头根本没省下来。你看到的显存没满但OOM,大概率是CUDA缓存碎片或者临时张量峰值爆了,尤其是attention的中间变量,可以开gradient_checkpointing试试,能砍掉一大截激活内存。另外offload_param确实该开,但stage 2开param offload其实等于半只脚进了stage 3,性能会掉很多,不如直接上stage 3配合offload_param和offload_optimizer,两张卡应该能跑但会慢不少。我自己用7B试过,stage 3加全offload,batch size 1,序列长度2k,勉强能塞进两张24G,但速度感人,如果只是实验不如直接上LoRA。
3090的24G跑7B全参数微调确实紧张,但你这配置理论上不该十几个step就炸。我怀疑不是显存不够,而是你gradient_accumulation和ZeRO的通信峰值叠一起了,试着把batch size固定为1,同时把offload_param也打开,让优化器状态和参数都走CPU。另外检查下是不是有中间激活值没释放,比如用了activation checkpointing但设了过大的chunk大小。我之前用类似配置跑13B都没事,你先把zero_force_opt_offload设成true看看,不行就砍序列长度。
光开offload_optimizer不够,把offload_param也加上试试,7B两卡stage2确实紧。
两卡24G跑7B其实能行,你检查下是不是没设zero_force_opt或者CPU内存炸了。
十几个step才炸,八成是碎片化显存,试试Stage 3加offload_param,光offload优化器不够。
十几步之后才OOM,大概率不是静态显存不够,而是碎片化或者某个中间激活峰值爆了。你可以先开offload_param试试,Stage 2下把参数也卸到CPU能省不少,但速度会明显掉。另外检查一下stage3_gather_16bit_weights_on_model_save和优化器状态的分片是不是真生效了,有时候配置文件没被正确读取。两张3090跑7B全量微调本来就紧,LoRA或者QLoRA可能更现实,不然光靠调batch也很难绕过去。
两张3090跑7B微调确实挺紧的,但十几步才OOM更像是碎片化或者激活值累积的问题。你试试把offload_param也开了,Stage 2只offload优化器状态,参数和梯度还在显存里,7B的fp16参数就14G了,两张卡分下来每张7G,加上优化器状态和激活,很容易顶到边。另外看下有没有开gradient_checkpointing,这个对激活值影响很大,没开的话batch size再小也扛不住。还有nvidia-smi没满但报OOM,大概率是显存碎片,可以设个PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True试试。