最近在试着把7B的模型部署到本地,显卡是3090(24G),按理说应该够用,但一加载就说CUDA out of memory。我试了加载时传low_cpu_mem_usage=True,也试了把max_memory分配给GPU,但好像没多大用。我看网上说用bitsandbytes做4bit量化,但装了之后又报错说找不到CUDA的setup.py,心态有点崩。就想问问大家,实际部署的时候一般怎么配参数?是不是需要把加载的模型分片到多卡或者用offload?另外,除了量化,还有哪些比较实用的显存优化思路?希望能给个可操作的步骤,谢谢了。
部署LLaMA模型一直OOM,大佬们都是怎么优化显存的?
全部回复
共 81 条24G跑7B按理说真够,你八成是加载时把float32的权重全塞进去了,试试load_in_4bit=True然后配个bnb_4bit_compute_dtype=torch.float16,能压到6G左右。bitsandbytes报错大概率是版本和CUDA不匹配,直接pip install bitsandbytes>=0.43.0或者从源码编译一下就行。另外可以开梯度检查点(gradient_checkpointing),推理时也能省不少显存,虽然会慢一点。要是还不行,就把tokenizer和模型分开加载,然后offload到CPU几层,但3090真没必要,多半是哪里配置没对上。
3090玩7B其实挺尴尬的,24G看着不小但FP16光权重就得14G,加上KV cache和激活值,加载时如果transformers默认把整个模型塞进显存,瞬间爆掉很正常。low_cpu_mem_usage那个参数只管CPU内存,跟显存没关系,max_memory你得配合device_map="auto"用才行,只设max_memory不指定映射策略,它还是会傻乎乎全放GPU上。bitsandbytes报setup.py那个错大概率是版本和CUDA不匹配,建议直接pip install bitsandbytes==0.43.0这种带预编译wheel的版本,或者用conda装,能省不少事。我自己实测最稳的路子是:先用4bit加载(load_in_4bit=True),同时把torch_dtype设成float16,再开gradient_checkpointing(推理时也能省点显存),基本能压到10G以内,还能留出余量跑长上下文。要是还觉得紧,就手动把模型分两层丢到CPU上,用device_map指定一下,速度损失其实能接受,毕竟比直接崩了强。另外你可以试试把attention的KV cache量化成8bit,很多库比如vLLM或者TRT-LLM都支持,但3090是Ampere架构,有些新优化不吃,别太指望。最后提一句,如果只是调试代码,可以先用GPTQ的4bit版本,加载速度比bitsandbytes快,但推理吞吐会低一点,看你要什么了。
3090跑7B按理说真够,问题多半出在加载瞬间的峰值显存上,试试先加载到CPU再逐步move到GPU,或者用accelerate的device_map="auto"让它自动分载。bitsandbytes报错大概率是版本和CUDA不匹配,去GitHub装对应的预编译wheel,别用pip默认源。另外offload到内存确实能救急,但速度会掉很多,日常推理建议还是4bit量化加flash-attention,显存能压到6G左右。你用的是transformers哪个版本?有些老版本对量化支持有坑。
24G跑7B其实挺尴尬的,FP16加载光权重就要14G,加上KV cache和中间激活值,稍微多点输入就爆了。你说的low_cpu_mem_usage那个参数只影响CPU端加载,真正吃显存的是forward时的临时张量,建议先试试把max_seq_len砍到512,batch_size强制设成1,很多情况下不量化也能跑起来。bitsandbytes那个报错大概率是版本和CUDA不匹配,你可以直接pip install bitsandbytes==0.41.1配CUDA11.8的wheel,或者干脆用transformers自带的load_in_4bit=True,内部会自己处理。另外强烈建议开torch.compile,虽然首次编译慢,但能省不少显存碎片,配合gradient_checkpointing(如果你只是推理不用)或者用model.forward的no_grad模式。实操里最稳的路径是:先试FP16+max_seq_len=512+flash-attention,不行再上4bit,4bit还不行就考虑把模型切一半到CPU,用accelerate的device_map="auto"自动offload,3090的PCIe带宽虽然慢点但至少能跑。最后提一句,检查一下你的CUDA版本是不是12.1以上,新版PyTorch对显存管理改进了很多,老版本有时候会多占2-3G的缓存不释放。
24G跑7B按理说真够,但你这OOM大概率不是显存不够,是加载时峰值爆了——transformer库默认会一次性把整个模型载入显存,所以low_cpu_mem_usage其实没解决根本问题。我之前也是3090,试过最稳的办法是先加载到CPU,再用accelerate的device_map="auto"让模型自动分配层到GPU,这样能省不少峰值显存。bitsandbytes报错那个setup.py问题,多半是版本和CUDA不匹配,你可以试试装源码版或者直接用pip install bitsandbytes==0.39.0这种老版本,跟transformers兼容性好一点。另外除了量化,你还可以把attention实现换成flash-attention-2,或者用torch.compile,能省10%到20%显存,推理速度也快。如果还是爆,就把max_memory设成{0: "20GiB"},剩下的层offload到CPU,虽然慢点但至少能跑。最后一个小技巧,加载完模型后调用model.half(),统一转半精度,别让参数类型混着,有时候这也能挤出一两G。
24G跑7B按理说真够,你大概率是加载时峰值爆了,试试加载完再move到cuda,或者用device_map="auto"让accelerate自动分配,别手动指定max_memory。bitsandbytes报错一般是版本和cuda不匹配,直接pip install bitsandbytes==0.43.0配合transformers最新版能省不少事。另外实在不行就上gptq的4bit,加载速度和显存占用都比bnb稳,3090跑7B大概只要6-8G,剩下空间还能塞长上下文。还有个小技巧,加载时把torch_dtype设成float16,默认float32会直接翻倍显存。
3090跑7B按理说真够,但OOM多半是加载时把权重全塞进显存了,HuggingFace的from_pretrained默认fp32,光权重就28G,直接爆。你先试一下加载时加torch_dtype=torch.float16,这步就能省一半,如果还不行就换load_in_8bit=True,用bitsandbytes的话注意版本要跟transformers匹配,报setup.py错大概率是CUDA版本没对上,重装对应cuda的bitsandbytes轮子就行。
4bit量化确实是最省显存的方案,但如果你只想快速跑通,其实8bit加device_map="auto"就足够,它会自动把部分层放到CPU上,速度慢点但不会崩。另外你提到的offload,其实可以手动指定max_memory={"cuda:0": "20GiB", "cpu": "16GiB"},这样能强制把超出部分放内存,但推理会慢不少,适合临时调试。
还有个思路是换模型,比如用LLaMA-2-7B的GGUF版本,配合llama.cpp跑CPU+GPU混合,显存占用能压到6G以下,速度比transformers快很多。如果你非要用transformers,建议把序列长度限制在512,并关闭gradient_checkpointing(虽然训练用,但有时加载也会触发额外显存),然后试试torch.compile。
bitsandbytes报错的话,可以直接pip install bitsandbytes==0.41.1这个老版本,对新卡支持反而更稳。我上次就是换了版本才解决。另外别忘了一个小技巧,加载前先跑torch.cuda.empty_cache(),有时候显存碎片也会导致误报OOM。最后实在不行就上多卡吧,3090收个二手也不贵,但单卡7B其实真不需要。
试试加载时加device_map="auto",配合bitsandbytes的4bit,24G跑7B绰绰有余,报错多半是版本没配对。
量化报错大概率是bitsandbytes和cuda版本不兼容,直接pip装最新版再配下环境变量就行。
24G跑7B其实挺宽裕的,问题大概率出在加载精度上。你试试加载时直接指定torch_dtype=torch.float16,默认float32的话光权重就要28G,直接爆很正常。bitsandbytes那个报错多半是版本和CUDA不匹配,建议用pip装最新版,或者干脆上int8,效果也够用。另外max_memory那个参数要配合device_map="auto"一起用,光设分配不指定映射策略等于白搭。offload到CPU是最后手段,速度会掉到没法看,除非你只做推理不交互。还有个冷门技巧,加载后清一下CUDA缓存,把不需要的中间变量del掉再gc.collect(),有时候能挤出几个G。你要是用transformers,试试把attn_implementation="flash_attention_2"传进去,显存能省不少。实在不行就换llama.cpp的GGUF量化版,Q4_K_M格式4G不到,3090跑起来跟玩似的,还能顺便用上flash attention。
看到你这个情况我太有同感了,3090跑7B按理说真不该这么狼狈,问题多半出在加载方式上。你试的low_cpu_mem_usage和max_memory只是让加载过程不爆内存,但推理时显存峰值还是会瞬间拉满,关键得看模型文件本身有没有被完整塞进显存。我建议你先别碰bitsandbytes,那个在Windows上装起来确实折腾,换个思路用accelerate库的device_map="auto"参数,它会自动帮你把层分配到GPU和CPU上,虽然慢点但至少不崩。另外你试试在加载前清一下CUDA缓存,torch.cuda.empty_pc()有时候能救急,我遇到过类似情况就是这么解决的。至于量化,其实4bit对7B来说损失精度有点大,如果要求不高可以先试8bit,用transformers的load_in_8bit=True配合bitsandbytes,但记得把环境变量BITSANDBYTES_NOWELCOME设成1绕过那个setup.py的报错。还有个冷门技巧是把max_new_tokens调小,或者用flash-attention替代标准attention,能省不少显存,不过安装有点麻烦。你现在的显卡驱动和CUDA版本是多少?有时候OOM纯粹是版本不匹配导致显存碎片化,更新到12.1以上可能会好很多。
3090跑7B按理说真不该OOM,你八成是卡在加载瞬间的峰值显存上。模型加载时默认会先创建FP32副本再转半精度,这一步就能把你24G吃穿,试试直接torch_dtype=torch.float16加载,顺便把device_map="auto"打开,让transformers自动分配。
bitsandbytes那个报错大概率是版本和CUDA不匹配,建议直接pip install bitsandbytes==0.43.0,别用最新版,然后加载时传quantization_config=BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.float16),这样基础占用能压到6G以内。
如果量化还是报错,先别纠结,用accelerate的cpu_offload兜底,把一半层丢到内存里,速度慢点但至少能跑。另外换用llama.cpp的GGUF格式也是个思路,Q4_K_M量化后只要5G显存,而且CPU也能算,3090跑起来比transformers流畅得多。
你那个low_cpu_mem_usage=True其实只影响CPU内存,对显存没帮助,别指望它。还有个冷门技巧,加载前先跑一遍torch.cuda.empty_cache(),把之前残留的缓存清掉,有时候能多出2-3G。
最后实在不行就上vLLM或者TGI这类推理框架,它们自带continuous batching和paged attention,显存利用率比原生transformers高一个量级,7B模型用vLLM在24G卡上能开很大并发还不爆。
24G跑7B按理说真够,你大概率是加载时峰值爆了,试试torch_dtype=torch.float16,别用默认float32,能省一半。bitsandbytes报错一般是版本和CUDA不匹配,直接pip install bitsandbytes==0.41.1配合transformers 4.36试试,实在不行就换llama.cpp走GGUF量化,CPU+GPU混合跑,3090上4bit能稳到40token/s。另外加载后马上调max_memory={0: "20GiB"},然后offload一部分层到CPU,别全塞显存,我这么干之后连13B都能勉强跑。
试试bitsandbytes换个版本装,或者直接上GPTQ量化,24G跑7B绰绰有余,ollama加载省心很多。
24G跑7B按理说是够的,但你得先搞清楚瓶颈在哪儿——大概率是加载时把权重和激活值都塞进了显存,而默认的torch dtype是fp32,光权重就快30G了。我建议你加载时直接指定torch_dtype=torch.float16,这能立刻省一半,然后别用max_memory硬分,改成device_map="auto"让transformers自己调度,它会自动把部分层扔到CPU内存里,虽然慢点但至少不会崩。bitsandbytes那个报错多半是版本和CUDA不匹配,你直接pip install bitsandbytes==0.41.0配合transformers 4.36以上版本,再不行就去GitHub下预编译wheel,别自己编译。除了量化,还有个更实用的思路是开梯度检查点(gradient_checkpointing),但那是训练用的,推理时真正吃显存的是KV cache,你可以把max_new_tokens调小,或者用flash-attention省内存。另外,如果只是跑demo,把输入序列长度设短一点,比如256,你会发现显存占用直接掉一大截。最后实在不行就上vLLM或llama.cpp,这两个专门为推理优化过内存分配,3090跑7B量化后能剩10G以上。你先试fp16加device_map="auto",大概率能跑起来。
3090跑7B按理说真够,但你这问题大概率出在加载时的峰值显存上——模型权重本身占14G左右,但transformers加载时会一次性把fp16的checkpoint全读进显存,再加上KV cache和激活值,24G就爆了。我建议你别直接用from_pretrained,先改成load_in_4bit=True配合bnb_4bit_compute_dtype=float16,这样权重直接压到4G左右,剩下的空间给推理留余量。bitsandbytes报错的话,检查下是不是CUDA版本和它不匹配,或者直接用pip install bitsandbytes --upgrade试试,有时候老版本对3090的sm_86支持有问题。另外,可以试试torch.compile或者把gradient_checkpointing打开(虽然推理时没用,但能确认是否误开了训练模式)。还有个笨办法,加载时先设max_memory={"cuda:0": "20GiB", "cpu": "20GiB"},让多余的权重自动offload到内存,虽然慢点但能跑通。如果还不行,看看是不是transformers版本太老,新版对device_map="auto"支持更好,会自己分配。最后实在不行就换GPTQ量化,比4bit的bitsandbytes稳定,而且推理速度快不少,就是需要先离线量好模型。别崩,这类问题基本是环境坑,调一调就能跑。
24G跑7B按理说真够,你八成是加载时峰值显存爆了,试试把model.to('cuda')改成先加载到CPU再逐步转移,或者用device_map='auto'让transformers自己分配。bitsandbytes报错大概率是版本和CUDA不匹配,换conda装或者直接上最新的release包能省不少事。另外除了4bit,你还可以开gradient_checkpointing(虽然推理时没啥用)或者把KV cache量化一下,不过最立竿见影的还是用flash-attention,显存能降三分之一。我自己的经验是,先确认有没有别的进程占显存,然后试试把batch_size设成1,实在不行再上offload,别一上来就搞多卡。
试试load_in_4bit=True,3090跑7B完全够,记得先升级bitsandbytes到最新版,老版本确实容易报错。
量化是最直接的,另外可以把tokenizer和模型分开加载,显存能省不少。
24G跑7B按理说真够,但OOM大概率是加载时峰值爆了,试试加载完再清一下缓存,torch.cuda.empty_cache()配合gc.collect(),能救不少。bitsandbytes那个报错一般是版本和CUDA不匹配,建议直接pip install bitsandbytes从源码装,或者用llama.cpp的GGUF格式,Q4_K_M量化后显存能压到5-6G,根本不用折腾offload。另外可以把max_seq_len调短点,比如512,KVCache占用会少很多,推理速度也快。你要是还想省显存,可以把attention改成flash-attn,但那个编译更头疼,建议先试GGUF,改个路径就能跑。
试试bitsandbytes的4bit加load_in_4bit=True,3090跑7B完全够,报错可能是版本不匹配换个conda环境装。
量化加gradient checkpointing双管齐下,显存能省一半,你这报错大概率是bitsandbytes没编译对。
24G跑7B按理说真够,问题大概率出在你加载时用了float32,默认就是16G起步,加上激活值直接爆。试试torch_dtype=torch.float16,能省一半。bitsandbytes报错一般是版本不匹配,建议直接pip install bitsandbytes--upgrade,或者换0.39.0老版本。另外你那个max_memory分配要配合device_map="auto",别手动全塞给GPU,让transformers自己调度,还能自动offload部分层到CPU。要是还不行,就先把max_new_tokens限制到256,生成时用low_memory模式跑。
24G跑7B按理说真够,问题大概率出在你加载时用了float32,默认就是16G起步,加上激活值直接爆。试试torch_dtype=torch.float16,能省一半。bitsandbytes报错一般是版本不匹配,建议直接pip install bitsandbytes--upgrade,或者换0.39.0老版本。另外你那个max_memory分配要配合device_map="auto",别手动全塞给GPU,让transformers自己调度,还能自动offload部分层到CPU。要是还不行,就先把max_new_tokens限制到256,生成时用low_memory模式跑。
说实话你第一步就错了,low_cpu_mem_usage只影响CPU端,和显存没半毛