最近在折腾本地部署Qwen2.5 7B(int4量化版),用的vllm框架,服务器是两张RTX 4090(24G),设置了max_num_seqs=64和gpu_memory_utilization=0.9。刚开始跑几个请求还挺正常,但连续处理几十个prompt之后,显存就慢慢涨到46G然后直接OOM了。查了vllm的文档说是有动态显存管理的,但感觉没生效。我试过调低max_num_batched_tokens到2048,也没用。是不是我哪里设置不对?还是7B模型本身在长文本多并发下就是容易爆显存?求大佬们指点一下排查思路或者有没有其他轻量部署方案推荐。
用vllm部署Qwen2.5 7B,显存一直涨到OOM,是代码有问题吗?
全部回复
共 159 条之前跑7B也遇到过类似情况,后来发现是vllm的prefix caching没关,长文本重复前缀会把KVCache占满,加上int4量化后显存碎片化严重,试试加--disable-prefix-caching,再把gpu_memory_utilization降到0.8留点余量。另外两张卡最好用tensor-parallel-size=2,单卡跑7B本来就容易在连续请求时触发显存抖动,我这么调完基本稳住了。
我之前也踩过类似的坑,一开始还以为是量化模型的问题,后来发现vllm的显存增长其实跟前缀缓存和KV cache的分配策略关系很大。你设了gpu_memory_utilization=0.9,但两张卡加起来45G左右,这个比例其实已经把剩余显存全吃进去了,一旦并发稍微上来或者某个prompt特别长,预分配的缓存块就会把所有空闲空间填满,然后新请求进来就只能挤占别的块,最后触发OOM。建议先试试把gpu_memory_utilization降到0.7左右,给pytorch和CUDA context留点余量,同时把max_num_seqs调小到16或32,看看曲线是不是平缓一些。另外你用的是int4量化,但vllm对AWQ或GPTQ这类量化格式的显存优化跟原版FP16不一样,有时候反而会因为反量化操作多占一块临时显存,可以换成llama.cpp的server跑一下对比,那个对单卡和显存控制更激进。还有个排查技巧,开vllm的时候加--enable-prefix-caching,如果业务里有大量重复前缀,能显著减少KV cache重复分配,但如果你prompt都是独立的,那这功能反而会多占内存。最后怀疑是不是Qwen2.5的attention实现里对长序列有额外buffer,比如位置编码或RoPE缓存,试试把max_model_len限制到4096,毕竟7B模型在24G下全量上下文本身就危险,短一点能保命。
有没有更详细的教程推荐?
我之前也踩过类似的坑,int4量化版其实显存占用波动比想象中大,尤其长文本下KV cache会疯涨。你试试把gpu_memory_utilization降到0.7,同时把max_num_seqs调成16,让vllm的paged attention有点余量,别让它觉得空间够就拼命预分配。另外确认下是不是用了--enable-prefix-caching,这个在连续相似prompt时能省不少显存。如果还不行,换TGI或者llama.cpp的server模式,配合flash-attention也挺稳,就是并发低点。我这边跑7B用单卡24G,max_len设4096,基本能撑住百来轮对话不爆。
int4其实不吃显存,你这更像vllm的prefix cache没关或者paged attention没生效,试试--disable-prefix-cache。
也可能是max_num_seqs开太大导致预分配,降到16或32再观察下曲线。
我之前也遇到过类似情况,后来发现大概率是int4量化版的KV cache在vllm里没被正确压缩,导致显存计算偏差。你试试把gpu_memory_utilization降到0.8,再配合--kv-cache-dtype fp8_e5m2,能省不少。另外max_num_seqs别设那么高,24G双卡跑7B其实32就够用了。你那个长文本场景下,其实可以考虑用llama.cpp的server模式,虽然吞吐低点但显存控制稳定得多。
我怀疑不是代码问题,是vllm对量化模型的显存预估本身就偏保守,实际分配会超出你设的比例。你可以看下nvidia-smi,确认是不是只有单卡在涨,双卡负载不均也会导致其中一张先爆。实在不行就换AWQ或者GPTQ的4bit试试,有时候不同量化格式对vllm的显存管理差异挺大。
说实话这个现象我上个月也遇到过,后来定位到是vllm的prefix caching和连续批处理叠加的问题,你试试把enable_prefix_caching显式设成false,或者干脆开一下--disable-log-stats看看显存曲线是不是锯齿状暴涨。7B int4理论显存占用应该在6G上下,46G明显不对劲,更像是paged attention的block管理没生效,建议你检查下vllm版本,0.6.x之后这块改过不少,老版本特别容易在长上下文的场景下疯狂预分配物理块。另外max_num_seqs=64在这种显存下有点激进,建议先降到16跑压测,排除并发数导致的KV cache溢出。如果还不行,换个路子试试llama.cpp的server模式,虽然吞吐低点但显存控制是真的稳,尤其对量化模型友好。最后提醒下别忽略nvidia-smi里看下是不是有其他进程占了显存,我之前就是被一个残留的torch进程坑了半宿。
遇到过类似的坑,问题大概率不在max_num_seqs,而是int4量化配合vllm的paged attention时,显存碎片化比fp16更严重,尤其长文本下KV cache增长会超出预期。建议先开--enable-prefix-caching,再把gpu_memory_utilization降到0.8试试,给显存留点余量。另外可以监控一下nvidia-smi看是不是单卡先爆,两张卡负载不均也可能导致某张卡先OOM。实在不行就换llama.cpp跑Q4_K_M,虽然吞吐低点但稳如老狗。
遇到过类似的坑,大概率不是代码问题,而是vllm的显存管理在长上下文场景下的已知短板。你设的gpu_memory_utilization=0.9加上max_num_seqs=64,等于把可用显存全押在动态分配上,但连续请求时KV cache会持续累积,碎片化导致回收不及时。可以试试把max_num_seqs降到16,同时显存利用率调到0.85,给碎片留点余量。另外int4量化用vllm其实优势不大,建议直接换llama.cpp的server跑,显存占用能再低30%。
同款4090双卡配置,之前跑7B也遇到过类似问题,最后发现是vllm版本和CUDA版本不匹配导致的显存泄漏,你试试升级到最新的vllm版本或者回退到0.4.2看看。另外int4量化在vllm里其实支持得不算特别好,尤其是动态显存管理对量化模型有时会失效,建议直接上FP16版本对比一下显存曲线。你提到max_num_seqs=64,这个值对于7B来说确实偏大了,尤其长文本场景下KV cache会撑得很快,可以先降到16或者32观察一下。还有个坑是gpu_memory_utilization=0.9会给每个卡都预留,但vllm的显存分配是全局的,两张卡之间的负载均衡可能没你想的那么好,试试单卡部署跑同样的请求量,看是不是还OOM。如果只是测试的话,可以先用TGI或者llama.cpp的server模式顶着,它们对显存控制更保守,虽然吞吐低点但稳定。最后建议你开一下vllm的日志看具体是哪一步显存涨得最快,是prefill还是decode阶段,能更精准定位问题。
我之前也用vllm跑过类似的量化模型,你这情况我太熟了。int4虽然省显存,但vllm的paged attention在长上下文+多并发下,KV cache的碎片化问题会特别明显,而且它那个动态显存管理主要针对的是预分配,不是实时回收,所以连续请求时显存只涨不跌很正常。你试试把gpu_memory_utilization降到0.7,给torch和CUDA留点余量,另外max_num_seqs别设64,改到16看看,这参数直接决定了同时激活的序列数,太高了KV cache会爆炸。还有个坑是量化模型本身,Qwen2.5的int4在vllm里如果用的是AWQ或GPTQ,有时候和它的continuous batching配合不好,会额外缓存中间结果。我建议你开一下--enable-prefix-caching,并且把--max-model-len设成4096,别让它默认拉到32k,那样每个请求的KV cache都是满配。要是还不行,换SGLang试试,它对动态显存做得好很多,或者干脆用llama.cpp的server模式,7B int4在4090上单卡就能跑,虽然并发差点但稳。你先跑个长一点的压测脚本,观察显存是不是阶梯式上涨,如果是,基本就是缓存没释放的问题,跟代码关系不大。
vllm的prefix caching记得关掉,长文本多轮对话下这个超吃显存,我上次就是被这个坑的。
int4量化下gpu_memory_utilization别拉太高,0.7试试,留点余量给碎片化内存。
同款配置踩过一样的坑,最后发现大概率不是代码问题,而是vllm的显存预留机制和量化模型不兼容。你设的gpu_memory_utilization=0.9其实已经很高了,但int4量化后的权重虽然小,KV cache的显存分配逻辑是按fp16精度来算的,所以实际预留空间会超出预期,加上连续请求多的时候page扩充不回收,就会慢慢涨满。我后来把gpu_memory_utilization降到0.8,同时把max_num_seqs改成32,反而跑得更稳,OOM没再出现。另外你可以试试最新版的vllm,早期版本对Qwen2.5的prefix caching支持有bug,会重复分配cache。如果还想更省显存,建议换llama.cpp的server模式,用mmap方式加载权重,显存占用能压到12G以内,不过吞吐会低不少。还有个排查技巧,用nvidia-smi盯着看,如果显存是阶梯式上涨而不是瞬间爆掉,基本就是cache没回收,可以在代码里手动调一下max_model_len,别让它默认取4096,改成2048试试。
我之前也踩过类似的坑,vllm那个动态显存其实对连续长prompt的释放没那么及时,尤其int4量化后反而容易碎片化。你可以试试把gpu_memory_utilization降到0.8,同时给两张卡分别指定max_num_seqs=32,别让调度器跨卡乱窜。另外确认下是不是prompt里带了超长历史对话,有时候上下文长度比模型本身还吃显存,可以考虑用OpenAI兼容接口的max_tokens参数硬性截断。如果还不行,换llama.cpp的server模式跑int4,显存控制会直观很多。
说实话我之前也踩过类似的坑,vllm那个动态显存管理不是万能的,它主要管KV cache的复用,但int4量化版Qwen2.5 7B在长上下文场景下,prefill阶段的内存峰值会特别猛,尤其是你max_num_seqs拉到64,并发一上来,中间激活值直接爆炸。你可以试试把gpu_memory_utilization降到0.8,同时限制max_model_len到4096或者更短,这比调max_num_batched_tokens管用得多。另外我怀疑你两张卡是不是没开tensor parallel,vllm默认可能只用了单卡,检查下启动命令有没有加--tensor-parallel-size 2,否则24G单卡跑7B再叠长文本确实容易崩。如果还不行,可以换一下量化格式,比如AWQ或者GPTQ的4bit,比官方int4在vllm上优化更彻底,我之前用AWQ版本连续跑几百个请求显存都很稳。最后实在不行就考虑用llama.cpp的server模式,虽然吞吐低些,但内存控制是真的稳,适合调试阶段先跑通逻辑。你方便贴一下完整的启动参数吗,我帮你看看是不是哪里漏了。
显存涨到OOM大概率是vllm的prefix caching没关,加上prompt太长把KV cache撑爆了,试试--disable-prefix-caching。
我之前也遇到过类似的情况,最后发现是vllm的显存预留策略和paged attention的块分配在长上下文场景下会有点激进,尤其是你设了gpu_memory_utilization=0.9,它会把剩余显存基本都吃满,但实际释放又没那么及时。你试过把max_num_seqs调小到32或者16吗?我之前从64降到32,OOM出现的频率明显低了很多,代价就是吞吐量下降一些,但稳定多了。另外int4量化版本身在vllm里支持得不算完美,有些算子在量化路径上会额外开辟临时buffer,如果连续prompt长短不一,这些碎片累计起来也挺吓人的。建议你开一下vllm的日志,看OOM前有没有明显的“GPU cache eviction”警告,如果有,那基本就是缓存管理的问题而不是代码bug。还有个土办法,就是每处理完一批请求手动调一下torch.cuda.empty_cache(),虽然治标不治本,但能帮你确认是不是内存碎片化。实在不行就换TGI或者llama.cpp的server模式,7B int4在TGI上显存控制更稳,不过并发能力会弱一些。
我之前也踩过类似的坑,vllm那个动态显存管理其实对量化模型支持没那么好,int4的权重和KV cache分配逻辑有时候会打架。你试试把gpu_memory_utilization降到0.7以下,同时限制max_model_len到4096,这样能给cache留出余量。另外你两个卡是tensor parallel还是单独各跑一个实例?后者可能更稳,因为TP跨卡通信有时候也会触发显存碎片累积。
看到你这个问题我第一反应是vllm的显存管理其实没那么“动态”,它只是把paged attention那套KV cache做了分块,但模型权重和激活值还是实打实占着的,int4量化版在4090上跑7B按理说单卡应该够,但46G爆掉更像是跨卡通信或者张量并行配置出了问题,你有没有确认过两张卡是不是真的都参与计算了,有时候默认只在单卡上跑反而会撞到24G上限。另外max_num_seqs=64配合长prompt会让prefill阶段一次性申请大量临时显存,这个比decode阶段更吃内存,你可以试试把max_num_batched_tokens调得更低,同时限制一下输入长度,比如max_model_len设成4096,别让某些极端长的prompt把预留空间全占死。还有个小细节,gpu_memory_utilization=0.9对双卡来说意味着每张卡要预留10%给torch和CUDA context,实际可用可能比你想的小,建议先降到0.85观察一下监控曲线。如果实在排查不出来,可以换个思路用llama.cpp的server模式,虽然吞吐低点但显存占用是硬上限,跑7B int4单卡16G都稳,而且支持多卡分片,调试起来更直观。我上次遇到类似情况是vllm版本和CUDA版本不匹配导致的碎片化严重,升级到最新版就好了,你也可以看看日志里有没有相关warning。
vllm的prefix caching默认开着,长文本重复前缀也会占显存,试试关掉再加个--enable-chunked-prefill看看。