最近在尝试用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配置问题还是我显存真不够?
全部回复
共 83 条显存没满但OOM多半是碎片化或通信峰值,试试开offload_param,单卡batch再砍半看稳定不。
offload_param也得开,不然优化器状态还是占满显存,试试stage3吧。
显存没满但报OOM大概率是碎片化或者缓存没清,试试关掉eval缓存和pinned memory。
offload_param其实很关键,尤其你batch已经压这么低了,不开它两张卡跑7B确实悬。
3090两张跑7B其实挺极限的,你那个nvidia-smi看着没满但报OOM,很可能是碎片化显存或者激活值峰值爆了,不一定就是ZeRO没生效。offload_param确实建议也开一下,尤其你把optimizer offload之后,参数不offload的话内存压力还是很大。另外可以看看transformers那边的gradient_checkpointing开没开,这个对峰值显存影响特别大,比调batch_size管用多了。我上次跑13B也是类似情况,把checkpointing开了直接省了快一半显存,你可以试试再报错的话贴下完整配置,大家帮你看看。
说下我的经验哈,7B在24G*2上跑Stage 2理论上能跑,但你这报错时机挺可疑的,十几个step才炸,感觉像activation慢慢累积出来的问题。你试试加上--gradient_checkpointing,还有把max_seq_len调短点,很多OOM其实卡在长序列的attention上。至于offload_param,Stage 2默认是不开参数offload的,你手动加上看看,但注意会影响速度。另外确认下是不是用了flash-attention,这玩意儿能省不少显存,没装的话赶紧装一个。
显存没满但OOM大概率是碎片化问题,试试开--split_batches和--memory_efficient,或者换个思路直接上QLoRA。
offload_param也得开,不然优化器状态省了但模型参数还在卡上,两张24G确实紧巴巴的。
说实话你这个现象我太熟了,nvidia-smi看着没满但报OOM,大概率是显存碎片化或者CUDA context占了一部分预留空间,不是单纯看总量就能判断的。ZeRO Stage 2开了offload_optimizer其实已经够用了,但7B模型光参数就要14G,加上梯度、优化器状态和激活值,两张3090确实很吃紧,尤其你把batch size降到1之后,单卡要同时扛住模型分片+激活值缓存,反而可能触发某些算子的临时显存峰值。offload_param我倒觉得不是关键,你更该查一下是不是activation checkpointing没开,这玩意儿能省掉一大截激活内存。另外试着把offload_optimizer改成offload_optimizer+offload_param全offload到CPU,虽然慢点但能稳定跑起来,或者干脆改成ZeRO Stage 3加offload,把参数也分片出去,两张卡还能匀出不少空间。我之前用双卡跑13B就是靠Stage 3硬撑下来的,速度虽然感人但不爆。还有个细节,检查一下你是不是在保存checkpoint时触发了全量参数聚合,那个瞬间会临时多占一份显存。如果还不行,就把max_seq_len调短一点,7B模型在24G卡上留个2-3G余量是必须的。
我之前也遇到过类似情况,显存没满但报OOM,多半是碎片化或者临时峰值导致的。你试试把gradient_checkpointing打开,能省不少激活内存,代价是慢一点。另外Stage 2确实一般只offload优化器,参数还在显存里,7B全精度光参数就28G,两张卡裸跑本身就悬,建议offload_param也开了,或者干脆换Stage 3。还有个排查办法,先用单卡bs=1不加任何优化跑通,确认基线能过,再逐步加配置,这样能定位到底是哪个环节爆的。
我上次用deepspeed跑13B也遇到过类似情况,后来发现是gradient checkpointing没开,这玩意儿能省不少显存,你可以先试试这个。还有你nvidia-smi看显存没满但报OOM,很可能是碎片化问题,或者某个中间变量瞬间爆了。另外offload_param确实值得开,但开完速度会慢不少,两张3090跑7B理论上应该能塞下,重点还是看你的seq_len和batch_size是不是太大,建议先小规模跑通再慢慢加。
说实话我之前也卡在这过,3090跑7B全参数微调本来就紧,两张卡拼起来ZeRO-2理论够但实际很吃通信和显存碎片。你nvidia-smi没满但OOM,大概率是PyTorch缓存碎片或者activation峰值顶爆了,试试开activation checkpointing,能省一大截。offload_param在Stage 2确实不是必须的,但如果你optimizer states已经offload了,param不offload反而容易不均衡,建议两个都开,然后看一眼DeepSpeed的日志确认partition真的是2卡都在用。还有个土办法,把max_seq_len砍到512或以下,很多OOM都是序列长度惹的祸,先跑通再慢慢加回去。
你这情况我熟,先别急着怀疑显存,两张3090跑7B理论上够用,问题多半出在ZeRO的配置上。你开了offload_optimizer但没开offload_param,那模型参数还是全员驻留显存,Stage 2只切了优化器状态,参数照样占地方,建议把offload_param也打开试试。另外,如果用了gradient_checkpointing,记得和DeepSpeed的activation offloading配合,不然激活值照样爆,我上次就是这么解决的。还有个坑是nvidia-smi看的是占用峰值,不一定反映OOM瞬间的动态分配,你可以把日志里的显存曲线打出来看看是不是有突刺。
3090是24G不假,但7B模型光参数就要14G,加上梯度、优化器状态和激活值,两张卡跑ZeRO2其实很极限。你offload了optimizer但没offload param,显存碎片化也会导致OOM,建议把offload_param也打开试试。另外你确认一下是不是用了flash attention,这玩意儿能省不少激活显存。我之前用类似配置跑13B,得开ZeRO3加offload才能稳,7B的话Stage2应该能撑住,但得把seq_len压到512左右。
说实话这配置跑7B微调确实有点极限,但我觉得问题可能不在显存容量本身。你nvidia-smi看着没满大概率是碎片化或者内存分配没及时释放,试试在dataloader里加个torch.cuda.empty_cache(),或者看看是不是activation checkpointing忘开了。另外offload_param在stage2里确实不是必须的,但如果你把optimizer offload到CPU后显存还爆,那多半是通信开销导致显存峰值异常,可以看一眼DeepSpeed的日志里partitioned buffers的占用情况。我之前用双卡跑6.7B时是把zero stage提到3才稳住的,但速度会慢不少,你可以权衡下。
3090两张24G跑7B微调,理论上其实够用,但你这个情况我太熟了——显存看着没满,实际是碎片化或者峰值爆了。nvidia-smi看的是当前占用,但OOM往往发生在forward/backward中间某个临时张量分配的时候,尤其开了offload_optimizer之后,通信和CPU-GPU传输会有延迟,显存瞬间峰值可能顶破。你试试在DeepSpeed配置里把zero_force_opt_step改成false,有时候优化器更新那一步会集体申请显存,容易炸。另外,offload_param确实值得开,特别是Stage 2的时候,虽然会慢一点,但能腾出不少空间,我之前跑13B就是这么救回来的。还有个坑是activation checkpointing,你查下有没有开,没开的话7B模型光中间激活值就能吃掉好几个G,开了之后显存占用能降30%以上。最后,train_batch_size降到1还不够,你看看是不是dataloader那边num_workers开太多,或者max_seq_len设太长,这些都容易让显存分配变得很诡异。要是还不行,就开个--gradient_checkpointing配合ZeRO Stage 3,两张卡勉强能啃下来,但得做好速度慢一半的心理准备。
说实话你这个现象我太熟了,之前用双卡跑13B也踩过一模一样的坑。显存没满但报OOM,大概率不是partition策略的问题,而是DeepSpeed的显存预留机制和CUDA缓存之间的冲突,有时候它预分配了虚拟内存但没实际占用,nvidia-smi看着没满,实际一申请就炸了。你把offload_optimizer开了,但ZeRO Stage 2本身只切optimizer和gradient,不切模型参数,7B光是fp16权重就要14G,两张卡平均下来每张7G,加上激活值和临时buffer,24G确实很紧,但理论上不该这么快崩。我建议你先把offload_param也打开试试,虽然它主要是给Stage 3用的,但在Stage 2下强行把参数也offload到CPU能省出一大块,代价是慢不少。另外检查一下你用的attention实现,如果是flash attention或者xformers,有时候会额外申请一块很大的临时张量,跟ZeRO的通信buffer撞一起就OOM了。还有就是gradient_accumulation设8虽然降低了单步显存峰值,但每个micro-step的显存释放并不干净,PyTorch的缓存分配器有时会保留碎片,你可以试试在训练循环里手动调一下empty_cache的时机。最后实在不行就换LoRA或者QLoRA吧,7B全参微调两张3090确实勉强,除非你愿意把seq_len砍到512以下。
之前我也在双卡上跑7B遇到过一模一样的情况,显存看着没满但就是OOM,后来发现是activation memory在作怪。你试试把gradient_checkpointing打开,这玩意儿能省掉一大块激活显存,代价就是慢一点。另外offload_param确实建议也开上,虽然stage2理论上不强制,但开了能明显缓解碎片化问题。还有个小技巧,把torch.cuda.empty_cache()加在每N个step里,有时候碎片积压也会触发假性OOM。
同款配置踩过坑,3090两张跑7B其实有希望但特别吃细节。你光开offload_optimizer不够,把offload_param也打开试试,尤其attention层权重很占显存。另外检查下你是不是忘了开activation checkpointing,这个不开的话激活值能吃掉一大半显存。还有个偏方,把模型切成4bit加载再微调,效果损失不大但能省出好几个G。实在不行就试试ZeRO stage 3+offload全开,虽然慢点但至少不崩。
我最近也拿两张3090跑过13B,感觉你这情况大概率不是显存不够,而是碎片化的问题。DeepSpeed的ZeRO Stage 2理论上7B+gradient+optimizer states应该能挤进48G,但如果你用了CPU offload,反而可能因为频繁搬运导致显存峰值暴涨。建议试试不开offload_optimizer,直接把ZeRO Stage开到3,让参数、梯度、优化器状态全部分片,然后看下nvidia-smi里每张卡的memory-usage是不是有波动,我怀疑是某个瞬时峰值触发了OOM。另外检查下你是不是把max_seq_len设太长了,这个东西对激活内存的影响比想象中大得多。我之前调小seq_len后同样配置就稳定跑完了几千步。
3090的24G跑7B全参微调本来就紧,你开stage2还offload optimizer,瓶颈大概率在通信和显存碎片上,nvidia-smi看着没满但CUDA context可能已经爆了。建议试试stage3加offload_param,或者干脆用LoRA/QLoRA,7B全参微调两张卡真不是人干的事。另外你check一下zero_force_opt_optimization和zero_allgather_partitions这几个参数,有时候默认值会坑人。
试试把cpu training打开,offload_param也得开,Stage2只offload优化器不够。
ZeRO Stage3配NVMe offload,两张3090跑7B没问题,但速度会慢不少。