最近在试着用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模型上LoRA,两张24G卡按理说够用,问题大概率出在dataloader和Trainer默认参数上。batch size设4确实偏大,可以先降到1试试,同时确认一下per_device_train_batch_size有没有覆盖到。gradient checkpointing在Hugging Face的Trainer里直接设gradient_checkpointing_enabled=True就行,能省不少显存。4bit量化如果还炸,检查下bitsandbytes版本和bnb_4bit_compute_dtype是不是设成float16了。
7B用两张3090按理说够,batch size 4不大,试试gradient checkpointing和4bit量化一起开,别用Trainer默认的fp32。
3090 24G跑7B LoRA按理说是够的,但batch size设4确实偏大了,尤其没开gradient checkpointing的话很容易爆。建议先把batch size降到1,然后加上model.gradient_checkpointing_enable(),再配合4bit量化试试,显存占用能降不少。另外Hugging Face Trainer默认会加载全精度,记得在TrainingArguments里设fp16=True或者bf16=True,不然光模型权重就吃掉14G多了。
说实话这个配置跑7B LoRA完全够,问题大概率出在加载方式上。你先确认下模型加载时有没有设torch_dtype=torch.float16,没设的话光权重就占28G,两张卡都塞不下。另外batch size 4对7B来说确实偏大,先降到1试试,配合gradient_accumulation_steps=8效果一样。
bitsandbytes那个4bit如果你用的是最新版,记得在加载模型时传device_map="auto",不然它会默认全塞进第一张卡。Trainer里有个predict_with_generate选项默认False,但如果你开了它,生成阶段显存会翻倍,这个要留意。
gradient checkpointing直接在TrainingArguments里设gradient_checkpointing=True就行,但注意要同时设model.gradient_checkpointing_enable(),两个都写才生效。另外dataloader的num_workers设成0或4都行,这个影响不大。
7B模型光fp16权重就要14G,两张3090单卡跑batch size 4确实勉强,但OOM大概率不是显存不够,是transformers默认会加载optimizer states和gradients,这部分开销比模型本身还大。你试试gradient checkpointing加gradient accumulation,batch size先降到1,再把模型用bnb的4bit量化,我这样跑13B都能稳。另外Trainer里有个per_device_train_batch_size要显式设小,有些版本默认会按总batch size分配,很坑。
gradient checkpointing开起来,batch size先砍到1试试,两张卡用device_map=auto自动分卡就行。
说实话你这配置跑7B LoRA肯定是够的,问题大概率出在加载和训练策略上。两张3090单卡24G,如果直接加载FP16的7B模型权重就要占14G左右,再加上LoRA的梯度和优化器状态,batch size 4确实容易爆,但更关键的是你得先确认是不是把模型完整复制到了单卡上——很多人忽略了这个,Hugging Face的device_map="auto"其实会自动分卡,但如果你手动.to("cuda:0")就会把两张卡都塞满第一张。
bitsandbytes 4bit加载后模型本身会降到4G左右,理论上单卡能跑batch size 4,但你炸可能是因为没开gradient_checkpointing,这个在Trainer里直接设gradient_checkpointing=True就行,代价是训练慢10%-20%,但显存能砍掉一半。另外,per_device_train_batch_size建议先降到1或2,用梯度累积gradient_accumulation_steps凑等效batch,别一上来就4。
还有个小坑是dataloader的num_workers设太高会额外占显存,改成0或2试试。至于Trainer的默认参数,fp16要显式开,bf16在3090上其实更稳(但得看驱动),还有optimizer默认的AdamW会额外吃两倍参数量的显存,换成paged_adamw_8bit能省不少。
最后,你试过accelerate的init_empty_weights配合load_checkpoint_and_dispatch没?这个能真正把权重均匀分到两卡,比单纯device_map更可控。我自己的经验是,7B模型用两卡3090,batch 2 + 梯度累积8 + 4bit + checkpointing,稳定跑完微调没问题,你先从最保守的配置试,一步步往上调,别一上来就追求大batch。
先别怀疑人生,两张3090跑7B LoRA绝对够用,问题多半出在加载时没走4bit或没开gradient checkpointing。
7B模型就算4bit量化,光权重也得要6G左右,但3090的24G显存跑batch size 4应该不至于直接炸,你是不是把max_seq_length设太长了?LoRA训练时序列长度对显存影响特别大,512和2048完全两个量级。建议先把batch size降到1,开gradient_accumulation_steps补回来,同时记得在TrainingArguments里设gradient_checkpointing=True,这俩配合能省一半以上显存。另外bitsandbytes的4bit要配合bnb_4bit_compute_dtype=torch.float16用,不然计算精度是32位照样爆。你试试看还不行的话,把模型用device_map='auto'加载,让accelerate自动分配两卡,但注意3090之间NVLink带宽一般,跨卡训练速度会慢不少。
说实话7B模型在两张3090上跑LoRA是完全可以的,问题大概率不是显存不够,而是加载和训练时的冗余开销没处理好。你试了4bit还炸,我猜是模型加载时用了fp16或者bf16的默认精度,加上LoRA本身也占一部分激活内存,batch size=4对7B来说确实偏激进,建议先调到1或者2,配合gradient accumulation把有效batch撑起来。gradient checkpointing肯定要开,在Trainer里直接传gradient_checkpointing=True就行,但注意开了之后要记得model.gradient_checkpointing_enable(),否则有时候不生效。另外你提到bitsandbytes,确认一下是不是真的把模型load_in_4bit=True传进去了,而且要用torch_dtype=torch.float16,不然量化不生效照样爆。还有个坑是Hugging Face Trainer默认会计算eval loss,如果没关掉预测,验证阶段会额外占显存,可以设置prediction_loss_only=True。多卡的话,用device_map="auto"或者accelerate launch跑,但3090之间没有NVLink,通信慢,反而可能拖慢速度,不如单卡+offload。最后建议你把显存占用打出来看看,pytorch的torch.cuda.memory_summary()能告诉你具体哪一步爆的,我之前就是靠这个发现是优化器状态没被LoRA过滤掉才炸的。
说实话两张3090跑7B LoRA完全够用,问题大概率不是显存而是加载方式。你试试在加载模型时直接传device_map="auto",让accelerate自动分配层到两张卡,别手动.to("cuda")。batch size 4确实偏大,调到1或2,配合gradient accumulation照样能等效大batch。gradient checkpointing就在TrainingArguments里设gradient_checkpointing=True,能省一半左右激活内存。还有个小坑,Hugging Face的Trainer默认会计算eval loss,如果你没关prediction_loss_only,评估阶段会额外吃显存。最后检查下bitsandbytes是不是只量化了线性层,有些仓库会漏掉embedding和lm_head,那两个也占不少。
先开gradient checkpointing,batch size降到1试试,3090跑7B LoRA没问题。
说实话你这配置跑7B LoRA完全够用,问题大概率不是显存大小,而是你加载模型时没做足量化准备。4bit bitsandbytes如果还OOM,你检查下是不是加载时忘了把模型放到GPU之前先from_pretrained里加device_map="auto",或者没设置load_in_4bit=True但忘了传quantization_config。另外batch size=4对7B来说确实偏大了,尤其序列长度如果超过512,两个3090的显存会被激活值和梯度撑爆,建议先降到1或2试试。
gradient checkpointing是必须开的,直接在Trainer里设gradient_checkpointing_enabled=True就行,它用计算换显存,能省30%左右。但注意开了之后要配合model.gradient_checkpointing_enable(),不然有些仓库的写法不生效。
还有你提到Hugging Face Trainer的默认参数,确实有个坑——它默认会计算评估集损失,如果你的验证集batch size没单独调小,爆显存很正常。可以试试per_device_eval_batch_size单独设成1,或者直接用TrainingArguments里的fp16=True,混合精度对显存帮助很大。
多卡的话,其实两张3090用device_map="auto"加parallelize能分载,但LoRA本身参数少,分卡收益不大,反而通信开销可能拖慢训练。我建议先单卡把所有优化项开满,跑通了再考虑多卡。
你要是还炸,把模型加载时的max_memory参数显式设成{0: "20GiB", 1: "20GiB"},给CUDA context留点余量。最后检查下dataloader有没有num_workers开太高,CPU内存溢出也会伪装成显存报错。
3090双卡跑7B LoRA应该够,但batch size=4确实偏大,先降到1试试,gradient checkpointing也要开。
用Trainer的话记得关掉gradient_accumulation_steps默认值,还有fp16要开,不然显存直接翻倍。
说实话你这情况我太懂了,7B模型在24G卡上跑LoRA按理说是够的,但问题往往出在“加载”这个动作上。模型权重本身就要占14G左右,再加上优化器状态、梯度、激活值,你dataloader的batch size哪怕设成1,都可能直接爆,更别说4了。我怀疑你八成是把模型直接.to('cuda')了,但没启用device_map="auto",导致两张卡根本没利用起来,全挤在一张卡上。建议你先试试model = AutoModelForCausalLM.from_pretrained(..., load_in_4bit=True, device_map="auto"),这样bitsandbytes才能自动分卡,而且4bit下单卡就能吃下,但注意要装对版本的bitsandbytes和transformers,不然会静默失败。gradient checkpointing这个必须开,就一行model.gradient_checkpointing_enable(),能省掉大概一半的激活显存,但会慢个20%左右,对你这个场景绝对值得。另外Hugging Face的Trainer里有个坑,默认会计算eval时的loss,如果你没设evaluation_strategy="no",它会额外缓存激活值,那显存很容易就炸了。你试试把batch size降到1,加上gradient accumulation步数凑够4,同时把per_device_eval_batch_size也设成1,应该就能跑起来了。如果还不行,建议你打印一下torch.cuda.max_memory_allocated()看看峰值到底在哪一步爆的,我赌八成是dataloader的collate_fn里padding方式不对,把所有样本都pad到最长序列了。
gradient checkpointing开了没?4bit加lora还炸大概率是batch size和seq len没调,两张卡用zero3分下模型试试。
说实话7B模型在两张3090上跑LoRA,理论上是完全够的,问题大概率不是显存容量而是显存管理方式。你batch size设4确实有点猛,LoRA虽然只训练少量参数,但前向传播和反向传播的激活值还是按全量模型算的,7B的激活显存开销非常大,建议先降到1或者2试试。另外你说的bitsandbytes 4bit加载,很多人忽略了一个关键点:你得同时把model的torch_dtype设成torch.float16,而且加载时要把device_map="auto"加上,否则它默认还是把模型全部塞进第一张卡。gradient checkpointing确实是必开的,在Trainer里直接传gradient_checkpointing=True就行,但开了之后要把model.gradient_checkpointing_enable()也手动调一下,有时候Hugging Face的版本会漏掉这一步。还有个容易踩的坑是Trainer默认会计算eval loss,如果你没设置evaluation_strategy="no",它会在验证时候额外占一份显存。多卡的话别用DataParallel,直接用accelerate或者deepspeed把模型分到两卡,这样每卡只占一半参数,能腾出很多空间。最后建议你用torch.cuda.max_memory_allocated打印一下实际峰值,看看是不是某个环节突然爆了,我怀疑你可能是模型加载阶段就已经OOM了,压根没到dataloader那步。
LoRA加4bit按理说24G两张够用,试试把batchsize降到1开梯度检查点,大概率能跑。
之前跑13B也遇到过这种情况,batch size 4确实大了,LoRA的话先调成1试试,同时把gradient checkpointing打开,能省不少显存。另外4bit量化后记得把模型放到GPU上再加载LoRA权重,顺序不对也容易炸。Trainer里有个gradient_accumulation_steps,多攒几步再更新,等效batch size不变但显存压力小很多。你用的是单卡跑还是两张卡都用了?如果是单卡,另一张空闲着挺浪费的。
我最近也在折腾类似的问题,两张3090跑7B LoRA按理说真不至于这么惨,但你这个batch size=4确实有点猛,LoRA虽然省了梯度,但激活值还是按全量模型算的,24G卡单卡塞4batch基本必炸。你试试batch size=1加上梯度累积,效果差不多但显存能降一大截。另外bitsandbytes那个4bit不是万能的,它跟某些版本的transformers或peft有兼容问题,报错经常是莫名其妙的,你确认一下是不是所有依赖都对齐了,尤其是accelerate和peft的版本。gradient checkpointing这个一定要开,一行代码的事,代价是慢个20%但显存能省一半,transformer里直接model.gradient_checkpointing_enable()就行。至于多卡,你两张卡其实可以试试zero3,但3090之间是PCIe通信,速度会拖后腿,不如先把单卡优化到极致再说。还有个容易被忽略的点,就是dataloader的num_workers如果设太高,内存会爆然后连带显存出问题,我上次就是栽在这上面。最后说一句,别全信那些GitHub的issue,有些人的环境跟你完全不一样。