最近在试着用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,是我显存不够还是代码有问题?
全部回复
共 33 条7B模型用LoRA按理说两张3090是够的,batch size设4确实偏大,可以先降到1或者2试试,另外检查下是不是per_device_train_batch_size和gradient_accumulation_steps没配合好。gradient checkpointing直接在Trainer里设gradient_checkpointing_enabled=True就行,能省不少显存。bitsandbytes的4bit量化如果还炸,可能是加载时load_in_4bit=True没配合bnb_4bit_compute_dtype设置对,或者模型没正确卸载到CPU。建议先单卡跑小batch排查,别急着上多卡,有时候反而是分布式通信吃掉额外显存。
说实话,7B模型在两张3090上跑LoRA按理说真不该直接爆,我猜大概率是加载权重时默认用了float32,光模型本身就得占28G左右,两张卡单张肯定扛不住。试下在加载模型时直接加一句.to(torch.bfloat16)或者用load_in_8bit=True,bitsandbytes的4bit其实对LoRA微调来说有点太狠了,8bit完全够用而且显存友好很多。
batch size设4对于7B模型确实偏大了,尤其是序列长度如果超过1024,单卡24G可能连一个样本都塞不下,建议先调到1或者2试试,同时把gradient accumulation steps设成4或者8,这样效果差不多但显存压力小很多。gradient checkpointing在Trainer里直接传gradient_checkpointing=True就行,但注意得配合model.gradient_checkpointing_enable()一起用,不然有时候不生效。
另外,Hugging Face Trainer默认会开mixed precision吗?你可以在TrainingArguments里显式设fp16=True或者bf16=True,这能直接砍掉一半显存。多卡的话用device_map="auto"配合accelerate库,会自动把模型切到两张卡上,但LoRA本身适配多卡有时候会有点小坑,建议先单卡调通再上分布。
最后检查下dataloader的pin_memory=True是不是开着,有时候这个会额外占用一些显存缓存,关了试试。如果还炸,可能是你用的那个GitHub仓库代码里有什么隐藏的显存泄漏,换个更轻量的实现比如PEFT库自带的例子跑跑看。
7B模型用LoRA在两张3090上跑batch size设4确实有点激进了,试试调到1或者2,配合gradient accumulation把有效batch size堆上去。bitsandbytes的4bit量化对显存帮助很大,但要注意加载模型时得用load_in_4bit=True并指定bnb_4bit_compute_dtype=torch.float16,不然计算精度不匹配反而容易炸。gradient checkpointing直接在Trainer里设gradient_checkpointing=True就行,能省不少显存,代价就是慢一点。另外检查下是不是Hugging Face的Trainer默认开了eval_accumulation_steps或者save_steps太频繁,这些临时缓存也会吃显存。
7B模型用两张3090跑LoRA按理说是够的,但batch size设4确实偏大了,尤其没开gradient checkpointing的话很容易爆。你可以试试把batch size降到1,然后梯度累积步数调高,比如设8,这样等效batch size还是4但显存占用会小很多。gradient checkpointing直接在Trainer里加个--gradient_checkpointing参数就行,或者用model.gradient_checkpointing_enable()手动开。另外bitsandbytes的4bit量化得确保加载模型时传对参数,比如load_in_4bit=True,如果还炸可以检查下是不是dataloader的num_workers设太高了。
同款配置踩过一模一样的坑,3070都撑不住batch size=4的7B模型。你试试把batch size降到1,然后开gradient checkpointing——在Trainer里设gradient_checkpointing_enabled=True就能省下好几G。另外bitsandbytes记得用8bit而不是4bit,4bit有时候反而会多占一些临时显存,我换成8bit+LoRA直接稳了。
7B模型用LoRA按理说两张3090确实够了,你batch size设4其实不算大,问题可能出在模型加载时默认用了float32,显存直接翻倍。试试在加载模型时加一句torch_dtype=torch.float16,再配合bitsandbytes的4bit量化,应该能省不少。gradient checkpointing在Trainer里直接设gradient_checkpointing_enabled=True就行,不过记得同时把model.gradient_checkpointing_enable()也调用一下。还有,Hugging Face的Trainer默认会缓存所有中间激活值,建议把per_device_train_batch_size降到1先跑通,再慢慢往上调。
老实讲,我也是这么一路踩坑过来的。两张3090跑7B LoRA按理说完全够,但你batch size设4确实有点莽了,我一般7B模型用LoRA都只敢设1或2,gradient accumulation开个4到8步,效果差不多但显存压力小很多。另外bitsandbytes的4bit量化确实能省不少,但你得确认是加载模型的时候就直接用load_in_4bit=True,并且把bnb_4bit_compute_dtype设成torch.float16,不然默认float32还是会爆。gradient checkpointing这个必须开,就在TrainingArguments里设gradient_checkpointing=True就行,能省差不多30%的显存,但会慢一点。还有一个容易忽略的点,Hugging Face的Trainer默认会把optimizer states也占一大块显存,你可以试试用adafactor或者paged_adamw_8bit来替代默认的AdamW,效果挺明显的。如果还不行,那就考虑用device_map="auto"配合accelerate把模型切到两张卡上,虽然通信开销大了点,但至少能跑起来。别太怀疑自己,这玩意儿坑就是多,调参调多了就有体感了。
两张3090跑7B按理说是够的,我怀疑你主要卡在模型加载阶段没做内存预清理。PyTorch有时候会缓存之前的显存碎片,试试在加载模型前加个torch.cuda.empty_cache(),或者用os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'max_split_size_mb:128'来限制碎片。batch size设4对于7B模型确实偏大了,尤其LoRA虽然省了部分参数但前向传播依然吃显存,建议先降到1或2试试。gradient checkpointing是必开的,在Trainer里设gradient_checkpointing=True就行,但注意它只节省中间激活的显存,对模型参数本身没影响。量化方面,bitsandbytes的4bit如果配合load_in_4bit=True和bnb_4bit_compute_dtype=float16应该能压到12G以内,你炸了可能是dataloader的num_workers设太多导致CPU内存爆了间接影响显存分配。另外Hugging Face的Trainer默认会计算eval损失,你可以关掉evaluation_strategy="no"或者用prediction_loss_only=True来省点空间。如果还不行,试试用device_map="auto"把模型切到两张卡上,配合accelerate库的dispatch_model,不过要注意LoRA的适配器得手动复制到每张卡。
7B模型用两张3090理论上够的,但batch size设4确实有点冒险,尤其没开gradient checkpointing的话,建议先降到1试试。bitsandbytes的4bit量化确实能省显存,但加载时如果没把模型先移到CPU再量化,中间态也会爆。Trainer默认会开eval和梯度累积,建议手动关掉不必要的采样器,再配合deepspeed stage2应该就能跑起来了。
7B模型用两张3090跑LoRA按理说完全够,问题大概率出在batch size和加载方式上。batch size设4对于7B模型确实偏大了,可以先降到1试试,同时确认一下有没有把模型完全加载到显存里。gradient checkpointing在Trainer里直接设gradient_checkpointing_enabled=True就行,能省不少显存,但会慢一些。另外bitsandbytes的4bit量化如果还炸,可以检查下是不是安装的版本跟CUDA不兼容,或者试试用load_in_4bit=True配合bnb_4bit_compute_dtype=torch.float16。
24G单卡跑7B全参数肯定不够,LoRA+4bit量化本身没问题,但batch size设4确实太大了,先降到1试试。gradient checkpointing直接在Trainer里设args.gradient_checkpointing=True就行,能省不少显存。另外检查下是不是加载模型时默认用了float32,手动设成torch.float16或bfloat16能缓解很多。多卡的话用device_map="auto"让transformers自动分配,两张3090应该能撑住。
老实讲,两张3090跑7B模型微调,理论上确实是够的,但你这个问题我太熟悉了,大概率不是显存不够,而是代码里有些默认设置没调好。batch size设4对7B来说其实还好,但关键是你有没有把per_device_train_batch_size和gradient_accumulation_steps配合好?很多时候Hugging Face的Trainer默认会开ddp_find_unused_parameters之类的检查,反而多占显存。
我自己的经验是,就算用了4bit量化,也得先确认一下bitsandbytes的配置是不是真的生效了,比如load_in_4bit=True和bnb_4bit_compute_dtype=torch.float16这些参数一个都不能少。另外gradient checkpointing确实有用,直接在Trainer里设gradient_checkpointing=True就行,但注意它会让训练变慢,相当于用时间换空间。
还有一个容易忽略的点:你的数据加载器里如果用了num_workers,有时候多进程开太多也会导致显存碎片化。建议先设成0试试看,排除这个干扰。实在不行,就把模型用device_map="auto"自动分配到两张卡上,加上max_memory参数限制每张卡的显存使用量。别怀疑人生,7B模型优化起来就是一堆坑要踩,调参调配置的过程也算是一种修行吧。
batch size 4对7B模型确实偏大了,先降到1试试,梯度累积开起来也能等效大batch。