最近在试着用LoRA微调7B的LLaMA模型,机器是两张3090(24G),按说应该能跑吧?但一加载模型就报CUDA out of memory。
我参考了几个GitHub仓库,有的说用bitsandbytes量化成4bit就行,但我试了还是炸。是不是我dataloader的batch size设太大了(设了4)?还是说需要把模型分到多卡?
另外,我看很多人直接用Hugging Face的Trainer,是不是里面有些默认参数会爆显存?有没有什么通用的显存优化trick,比如gradient checkpointing到底该咋开?
求各位大佬指点,真的有点怀疑人生了……
用PyTorch微调LLaMA,总是OOM,是我显存不够还是代码有问题?
全部回复
共 170 条说实话7B模型两张3090跑LoRA是肯定够的,问题大概率出在加载方式上。你试了4bit还炸,我怀疑是bitsandbytes没跟transformers版本对齐,或者你加载时没把device_map设成auto,这样模型还是全量塞进单卡显存,24G确实顶不住。建议你先用model.half()加gradient checkpointing试跑一个step,LoRA只冻结原权重,激活值才是大头,batch size先降到1,等通了再慢慢往上加。
Trainer那边确实有坑,默认的gradient_accumulation_steps是1,但更关键的是它默认会计算eval时的loss,如果同时加载了验证集,显存会直接翻倍。我自己的经验是,手动用peft包里的prepare_model_for_kbit_training加上torch.compile,能省不少显存,不过3090对compile支持一般,得看驱动版本。
另外你说的分多卡,其实用accelerate的device_map="auto"就能自动切分,但3090之间没有NVLink,通信效率会打折扣,反而可能更慢。我倒是好奇你dataloader的num_workers设了多少,有时候数据加载也会占显存,尤其是pin_memory开着的话。你可以先跑个空循环,只加载模型不喂数据,看看基线显存占用是多少,这样能快速定位是模型本身的问题还是数据管道的锅。
7B模型光权重加载就要14G,两张3090单卡跑确实紧,但报OOM多半不是显存不够,而是加载时默认把模型放到了单卡上。你先试试model = model.to('cuda:0')之前加model.half(),或者直接用device_map='auto'让accelerate自己分配,LoRA本身不省显存,省的是梯度。dataloader的batch size 4对于7B+LoRA确实偏大,先降到1,配合gradient_accumulation_steps=4,效果一样但显存能降一半。gradient checkpointing在Trainer里直接传gradient_checkpointing=True就行,但记得同时model.gradient_checkpointing_enable()。另外bitsandbytes的4bit要配合bnb_4bit_compute_dtype=torch.float16,不然计算还是fp32照样炸。
7B上3090绝对能跑,batch size先压到1,gradient checkpointing开一下,再不行就检查下是不是代码里把模型重复加载了。
一张3090跑7B LoRA其实够的,问题多半出在加载基座模型时没开4bit,或者quantization_config没传到from_pretrained里。你可以试试把batch size降到1,加上gradient checkpointing,再把model并行拆到两张卡上,显存应该能压到20G以内。另外Hugging Face Trainer默认会开warmup和eval,训练时把evaluation_strategy设成no,prediction_loss_only打开,能省不少显存。我之前用同样配置跑过,关键还是得把device_map设成auto,让accelerate自动分配层到两张卡。
7B模型加载时光权重fp16就要14G,两张3090单卡24G看着够,但你batch size=4加LoRA的梯度计算很容易冲爆,先降到1试试。gradient checkpointing在Trainer里直接设gradient_checkpointing=True就行,但记得同时把model.gradient_checkpointing_enable()调一下,不然不生效。还有bitsandbytes你八成是没设bnb_4bit_compute_dtype=torch.float16,默认fp32照样炸。多卡的话用device_map="auto"加peft的prepare_model_for_kbit_training,别手动分配。
说真的,两张3090跑7B LoRA理论上完全够用,问题大概率出在“加载”这个环节而不是训练本身。你试试在加载模型时直接传device_map="auto",配合torch_dtype=torch.float16,这样模型会先均匀分配到两张卡上,不会一上来就全塞进一张卡炸掉。至于4bit量化,bitsandbytes得配合bnb_4bit_compute_dtype=torch.float16和bnb_4bit_use_double_quant=True,很多人漏了这两个参数,效果天差地别。
Batch size=4确实有点激进,尤其输出序列长的话,激活值会瞬间堆满显存。建议先调到1或2,确认能跑通再逐步往上加。gradient checkpointing一定要开,就在TrainingArguments里设gradient_checkpointing=True,代价是慢30%左右,但能省下大量显存,对3090这种卡特别值。还有,Hugging Face Trainer默认会启用torch.compile或者自动混合精度,如果没配好反而可能多占显存,你可以在TrainingArguments里显式设fp16=True,同时把optim="adamw_torch"换成adamw_8bit,能再省几个G。
另外你提到dataloader,别忘了pin_memory=True和num_workers>0,这能减少CPU到GPU的传输压力,间接降低显存峰值。最后一个小技巧:如果还是爆,试试在训练前手动清一下CUDA缓存torch.cuda.empty_cache(),有时候碎片化也会导致OOM。先按这个顺序排查,大概率能跑起来,别怀疑人生,这坑大家都踩过。
7B模型用LoRA在24G双卡上绝对够,问题大概率出在加载基座模型时没开低精度,试试加载时直接指定torch_dtype=torch.float16,能省一半显存。batch size设4对7B来说不算大,但dataloader的num_workers和pin_memory有时候会占用额外显存,可以先调成0和False排除一下。gradient checkpointing肯定要开,Trainer里设gradient_checkpointing=True就行,代价是慢一点但显存能降不少。另外bitsandbytes如果直接用4bit加载,记得配一下bnb_4bit_compute_dtype=torch.float16,不然计算时还是会转回fp32导致爆掉。
7B模型光fp16权重就要14G,两张3090单卡24G按理说能塞下,但你batch size 4加上LoRA的梯度,activation一算就爆了。gradient checkpointing得在Trainer里设gradient_checkpointing=True,同时把batch size降到1,用梯度累积模拟大batch,显存能省一半。bitsandbytes那个4bit得配合load_in_4bit=True和bnb_4bit_compute_dtype=torch.float16,光改量化不动dataloader肯定还是炸。另外Trainer默认会计算eval loss,如果没关掉,评估时也会占一波显存,设个prediction_loss_only=True能缓解。建议先把batch size砍到1,开gradient checkpointing,再用4bit,基本就能稳了。
batch size真的得降到1或2,梯度累积开起来,另外gradient checkpointing在Trainer里直接设gradient_checkpointing=True就行。
7B模型用LoRA的话,两张3090其实完全够,但你batch size=4还开gradient checkpointing了吗?我猜你八成是没开,这个对显存影响特别大。另外bitsandbytes的4bit要配合bnb_4bit_compute_dtype=torch.float16用,不然照样炸。Trainer里per_device_train_batch_size记得调小到1或2,然后梯度累积开大点。还有个小坑,加载模型时记得用device_map="auto",不然两张卡利用率很低。
你那个batch size=4在7B模型上确实有点猛,我一般单卡跑都只敢设2,还得配合gradient checkpointing。显存不够的时候先别急着上量化,把torch.cuda.empty_cache()加在每次step之后,有时候碎片化也会造成OOM。另外你试过用accelerate库吗?它能自动帮你做多卡分配,比手动写DataParallel省心多了。反正LoRA本身只训练少量参数,真正吃显存的是前向传播的激活值,所以梯度检查点那个开关一定要打开。
我遇到过一模一样的情况,最后发现是Hugging Face的Trainer默认开了eval_accumulation_steps,这个在验证阶段会攒一堆batch的预测结果,直接把显存吃光。你把`evaluation
之前跑13B也遇到过这问题,7B双卡24G按理说LoRA完全够,但OOM八成不是batch size的锅,而是加载基座模型时峰值显存爆了。你试试先load模型到CPU,再用accelerate的device_map="auto",或者手动把模型切到两张卡上,这样比bitsandbytes更稳。gradient checkpointing在Trainer里直接设gradient_checkpointing=True就行,但记得配合model.gradient_checkpointing_enable(),不然有时不生效。另外dataloader的pin_memory和num_workers也会影响显存,可以先调到0试试。
7B模型用LoRA按理说24G是够的,你试试把batch size降到1,然后开gradient checkpointing,就在TrainingArguments里设gradient_checkpointing=True,显存能省不少。另外bitsandbytes加载时记得指定device_map="auto",不然它还是会把整个模型塞到单卡上。你两张3090其实可以试试张量并行,但先别急,先单卡跑通再说。dataloader的num_workers也别设太高,有时候内存爆了也会报OOM。
7B模型光fp16权重就要14G,两张3090单卡24G看着够,但LoRA训练时激活值、梯度和优化器状态才是大头,batch size=4在7B上确实太激进了,尤其序列长度一上来,激活值能吃掉好几G。你试试把batch size降到1,然后开gradient accumulation,凑到等效batch size 4,显存立刻能降下来。bitsandbytes 4bit加载模型确实能省权重内存,但训练时如果你还开了paged optimizer,注意它也会占用显存,而且4bit下LoRA的trainable参数精度和反传计算有时反而会更吃显存,不如直接用8bit加载加fp16训练省心。gradient checkpointing一定要开,就在TrainingArguments里设gradient_checkpointing=True,这会用计算换内存,激活值占用能降一个量级,代价是训练慢20%左右,但至少不OOM。另外Hugging Face Trainer默认会做几个事,比如eval时也计算loss,还有可能会在每step后保存checkpoint,这些都会临时撑高显存,建议把evaluation_strategy设成steps且eval_steps调大,或者干脆训练时关掉evaluation,save_strategy设成no或者只保存最后一步。还有个小技巧,用torch.cuda.empty_cache()在每轮epoch后清一下碎片,有时候显存碎片化也会导致明明够用却报OOM。最后,如果你一定要用双卡,记得用device_map="auto"加DeepSpeed stage 3,但3090之间是PCIe连接,通信开销很大,7B模型单卡其实能训,先把上面这些参数调好再上多卡吧。
把batch size调到1,再开gradient checkpointing和8bit,两张卡肯定够用的。
按说两张3090跑7B的LoRA是够的,问题大概率不在batch size,而是加载时基座模型直接占了全部显存。你可以先试试把模型用load_in_4bit=True加载,然后给prepare_model_for_kbit_training传参,这样能省出一大块空间。gradient checkpointing一定要开,Trainer里直接设gradient_checkpointing=True就行,但记得同时把input的requires_grad设为False。另外dataloader那边可以试试batch_size=1加梯度累积,效果比硬扛4要稳得多。
我也遇到过一模一样的情况,两张3090按理说够用,但问题大概率出在加载7B模型时默认用了fp32,光权重就占28G,两张卡还得算上通信开销。你试试在加载模型时直接指定torch_dtype=torch.float16,再把LoRA的target_modules确认一下,别把embedding层也算进去,能省不少。batch size=4确实有点大,尤其序列长度长的话,先砍到1或者2,配合gradient checkpointing开起来,基本能稳住。bitsandbytes那个4bit有时候会和某些版本的transformers冲突,建议先升级到最新版再试。
两张3090跑7B LoRA按理说完全够用,问题大概率不是显存本身,而是加载和训练时的峰值。你设batch size=4确实有点激进,7B模型即使LoRA,前向和反向的激活值也会吃掉大量显存,尤其序列长度一长,24G两张卡单卡放不下很正常。建议先把batch size降到1,用gradient accumulation把有效batch补回来,PyTorch里直接在Trainer设gradient_accumulation_steps就行,这个操作几乎不占额外显存。gradient checkpointing一定要开,在TrainingArguments里设gradient_checkpointing=True,它用计算换显存,能省接近一半,但注意开了之后要同时设model.gradient_checkpointing_enable(),别漏了。bitsandbytes的4bit量化确实有用,但如果你是用Hugging Face的transformers加载,记得load_in_4bit=True之外还要设bnb_4bit_compute_dtype=torch.float16,不然计算精度不匹配可能反而更吃显存。另外检查一下是不是把模型复制到了两张卡上而没有用device_map="auto",那样等于每张卡都放了一份完整权重,当然OOM。还有个容易忽略的点是Trainer默认会启用warmup和eval,如果eval的时候也跑了一遍全量数据,显存峰值会叠加,可以设evaluation_strategy="steps"并减少eval_steps,或者直接先关掉eval跑几步看看。最后实在不行就用ZeRO-3或者FSDP把优化器状态和梯度也分到多卡,但3090是24G,7B模型纯训练其实单卡4bit都能勉强跑,你先从batch=1+gradient_checkpointing+8bit开始试,大概率能跑起来。
7B用LoRA两张3090按理说完全够,你batch size4也不至于直接OOM,大概率是加载模型时没开4bit或者没把模型放到GPU上。建议先试试model.half()加上gradient checkpointing,能省不少显存,另外Trainer里per_device_train_batch_size和gradient_accumulation_steps配合一下,别让单卡峰值太高。还有个坑,bitsandbytes要确保版本跟transformers匹配,不然量化了也白搭。
我一开始也这样,3090单卡跑7B lora不加量化基本是极限了,你双卡反而容易踩到显存分配不均的坑。batch size 4确实大了,先降到1试试,然后gradient checkpointing直接在TrainingArguments里设gradient_checkpointing=True就行,但记得同时把model.gradient_checkpointing_enable()调一下。bitsandbytes那个4bit得配合bnb_4bit_compute_dtype=torch.float16用,不然还是按32bit算,你八成是漏了这个。另外Trainer默认会算eval loss,如果你没单独设eval_dataloader,它可能把验证集也塞进显存,直接关掉或者用更小的eval batch。
说实话两张3090跑7B LoRA完全够用,问题大概率出在加载基座模型时没开device_map="auto",导致模型全塞进单卡了。你试试加载时加上device_map="auto"和torch_dtype=torch.float16,然后LoRA层用4bit量化,batch size先降到1跑通再慢慢往上加。gradient checkpointing也要开,Trainer里直接传gradient_checkpointing=True就行,能省不少显存。另外确认下是不是dataloader的num_workers设太高了,有时候多进程会额外吃显存。