最近在搞一个内部知识库问答demo,选Qwen2.5-7B用vLLM部署在单卡A100上。按官方文档设了max_num_seqs和gpu_memory_utilization,结果显存直接冲到80GB,但并发压力测试时tokens/s只有200左右,跟网上说的差好多。而且感觉不少显存被模型本身和KV cache吃了,但实际推理时QPS一上去就卡住,日志里也没报错。自己试过改max_model_len到4096也没改善。请教各位大佬,是不是我prefill阶段的参数没调好?还是vLLM对不同模型有特定推荐配置?或者干脆得切Tensor Parallel?先谢谢了。
用vLLM部署Qwen2.5-7B,显存占满但推理速度上不去,是哪里没调对?
全部回复
共 147 条单卡A100跑7B这个吞吐确实不太对劲,我怀疑瓶颈不在显存分配上,而是vLLM的调度策略和你的请求长度分布有关系。你测并发的时候平均输入和输出token数大概是多少?如果prefill阶段很长,而max_num_seqs又设得偏大,vLLM会为了凑batch把多个长请求塞一起,反而拖慢首token延迟,整体吞吐就被拉下来了。可以试试把max_num_seqs调小到32或者16,同时开一下--enable-prefix-caching,内部知识库问题通常前缀重复率高,这个能省不少prefill算力。另外你提到gpu_memory_utilization拉到多少了?0.9以上其实没必要,vLLM会预留一部分显存做CUDA graph和激活,太满反而容易触发碎片化重排,不如留个10%余量。还有个小坑,Qwen2.5的tokenizer会为每个请求加im_start和im_end特殊token,如果你没在vLLM里配chat template,这部分计算会被浪费掉。切TP对7B真没必要,单卡算力足够,除非你是想测多卡扩展性。建议先用固定长度的小batch(比如8个请求,输入256输出128)跑一下benchmark,看看纯算力上限是多少,再逐步加并发找拐点。
试试把max_num_seqs调小点,prefill和decode混在一起容易卡,A100跑7B没必要上TP。
说实话你这情况我上周刚踩过一模一样的坑,A100 80G看着显存吃满但吞吐上不去,大概率不是prefill参数的问题,而是vLLM默认把KV cache预留得太狠了。你试下把gpu_memory_utilization降到0.7左右,然后显式设个--kv-cache-dtype fp16,我这边调完直接掉了20G显存占用,QPS反而翻了一倍。另外Qwen2.5系列对max_model_len特别敏感,官方推荐的是4096没错,但如果你实际输入长度平均只有几百token,那这个配置等于白白给每个sequence预留了4K的KV空间,并发一高就卡在内存分配上。还有个很容易忽略的点,vLLM的continuous batching对短请求支持得不太好,你可以试试把--max-num-batched-tokens调小到2048甚至1024,强制它更频繁地调度新请求。至于Tensor Parallel,单卡A100跑7B完全没必要,反而会引入通信开销,除非你打算换更大的模型。最后建议你开一下--verbose看看到底是scheduler在等显存还是GPU利用率没上去,我上次就是发现GPU compute只有30%,纯粹是排队瓶颈。
你这情况我遇到过类似的,问题大概率不在prefill,而是vLLM默认的chunked prefill策略和Qwen2.5的GQA结构配合得不好,试试把--enable-chunked-prefill关掉,或者显式设个--max-num-batched-tokens,别光调max_num_seqs。另外单卡A100跑7B其实没必要上TP,但你可以看下是不是CPU offload或者tokenizer线程成了瓶颈,建议用nvidia-smi看看推理时GPU利用率是不是有周期性掉到0的情况。日志没报错不代表没问题,开下--disable-log-requests看下实际调度延迟,我之前就是被这个坑了。
你试试把gpu_memory_utilization降一点,比如0.85,给tensor parallel留点余量,A100跑7B其实单卡就够了,切TP反而增加通信开销。另外max_num_seqs别贪大,设成64或128看看,prefill阶段瓶颈多半是并发请求的batch size没控制好,可以观察下vLLM的scheduler日志。我之前跑类似模型遇到过这问题,后来发现是默认的chunked prefill没开,加上--enable-chunked-prefill之后吞吐明显上来了。还有你确认下QPS测试时是不是有长prompt,长文本prefill很吃显存带宽,200 tokens/s在单卡A100上不算离谱,可能你对比的网上数据是短query场景。
显存拉满但速度上不去,大概率是KV cache预留太多挤了算力,试试调低gpu_memory_utilization到0.7再压测下。
说实话你这个现象我太熟了,A100 80G看着大但Qwen2.5-7B的KV cache吃起显存来一点不含糊,尤其max_model_len一拉长,prefill阶段算力全耗在长序列上了,自然QPS上不去。你试试看把max_num_seqs调小到32甚至16,同时把--enable-chunked-prefill打开,让prefill和decode交错执行,别让单个长请求把整个batch堵死。另外vLLM对A100默认会用FlashAttention,但如果你没手动设--kv-cache-dtype fp8,那KV cache占的显存会翻倍,200 tokens/s这个数字明显是没榨干卡的性能。我之前在内部跑同款模型,把gpu_memory_utilization降到0.85,然后强制开--max-num-batched-tokens 2048,速度直接翻倍,你可以先试这个组合。Tensor Parallel倒不用急着上,单卡7B根本用不着,除非你同时跑多个模型。还有个小坑,你是不是没设--trust-remote-code?有时候模型配置里的自定义算子没加载对,会悄悄走回HF原生路径,那性能差距巨大。建议你vllm serve的时候加个--verbose把每个请求的prefill/decode耗时打出来,看看瓶颈到底在哪边。
显存80G吃满但吞吐上不去,这个现象我见过好几次,大概率不是prefill参数的问题,而是vLLM默认把KV cache预留得太激进,加上A100 80G又特别大,导致调度器在并发高时频繁做显存回收和重新分配,反而把时间耗在内存管理上了。你可以试着把gpu_memory_utilization降到0.7左右,同时把max_num_seqs调小到32甚至16,强制让vLLM走更保守的调度策略,看看QPS会不会反而更稳。另外Qwen2.5-7B的官方推荐配置里其实有提到要配合continuous batching的开关,但很多人忽略的是它默认的chunked prefill是关闭的,你要在启动参数里显式加上--enable-chunked-prefill,这个对长文档知识库场景特别有效,能把prefill和decode阶段交错起来,利用率能上来不少。至于Tensor Parallel,单卡A100跑7B完全没必要,除非你拿它跑长序列,否则TP反而会引入通信开销,先别动这个。你还可以看下实际生成时是不是有大量请求卡在等待decode槽位,用vllm的--verbose日志看下每个batch的scheduling耗时,如果发现scheduling time占比很高,那基本就是上面说的显存预留问题。最后确认下你的请求长度分布,如果大部分是短问题长回答,那可以把max_model_len设到2048,给KV cache留更多余量,200 tokens/s在A100上对7B来说确实偏低,正常裸跑应该能到300-400,调完这些再试试。
这个瓶颈大概率不在显存分配,而是prefill和decode阶段的并发策略没对上。A100上7B模型其实用不到TP,单卡就够了,你试试把max_num_seqs调小到16-32,同时开一下--enable-chunked-prefill,让prefill和decode交错执行,QPS应该能上来。另外检查下是否开了--use-v2-block-manager,默认的block管理在长序列下很吃显存碎片。我之前跑类似模型,把continuous batching的batch size限制住,吞吐反而翻倍。
我之前也踩过类似的坑,A100上80GB显存看着吓人但其实vLLM默认会把空闲显存全吃进去,这不一定是瓶颈。你试过把--enable-chunked-prefill打开没?prefill和decode混在一起调度经常就是QPS上不去的原因。另外max_num_seqs别设太大,我之前从256降到64反而吞吐稳了,你可以试试看。还有,单卡A100跑7B其实不用上TP,先把batch size和连续推理的调度策略调好再说。
试试把gpu_memory_utilization降到0.8,然后开前缀缓存,这配置瓶颈多半在调度不在显存。
显存吃满但吞吐上不去,大概率是prefill和decode阶段资源分配打架了。vLLM默认会尽量占满显存做KV cache,但你这场景可能被max_num_seqs限制了并发,试试调低gpu_memory_utilization到0.7,同时把max_num_seqs提到256以上,让batch跑起来。另外Qwen2.5对continuous batching挺敏感,检查下是否开了--enable-prefix-caching,内部知识库如果长prompt多,这参数能省不少重复计算。单卡A100跑7B其实没必要上TP,先看下nvidia-smi里算力利用率是不是没跑满,有时候是数据加载或者tokenizer成了瓶颈。
这问题多半卡在prefill和decode混部上,试试把max_num_batched_tokens调小点,或者开下prefix caching。
A100跑7B显存本来就用不满,切TP反而浪费通信带宽,先查下是不是num_gpu_per_engine没设对。
显存拉满八成是kv cache没限制住,试试把gpu_memory_utilization降到0.85再看看。
A100单卡跑7B不至于这么拉胯,先查下是不是max_num_seqs设太高导致prefill和decode打架了。
试试把--enable-prefix-caching打开,命中后吞吐能翻倍,另外A100单卡跑7B没必要上TP。
A100显存80G不会满,检查下是否被其他进程占了,或者把block-size调小到16看看。
这速度确实不对劲,我怀疑是max-num-seqs设太大导致prefill抢占太多算力,压到256试试。
你试试把--enable-chunked-prefill打开,prefill和decode混跑很吃调度,vLLM默认对长prompt会卡在prefill阶段。另外max_num_seqs别设太高,8-16就行,A100上显存大不代表队列深就快,反而会放大KV cache碎片。
还有你确认下Qwen2.5的attention实现是不是被vLLM自动切成sdpa了,有时候得手动指定--attention-backend flash-attn,不然显存占用虚高但算力没吃满。TP暂时不用切,7B单卡够,先看下nvidia-smi里的算力利用率是不是也低,如果GPU利用率不到80%那多半是数据加载或者tokenize的瓶颈。
A100单卡跑7B按理说不至于这么拉胯,你试下把--max-num-seqs调小到32甚至16,这参数大了反而会挤占KV cache导致prefill和decode抢资源。另外确认下是不是开了--enable-chunked-prefill,没开的话长prompt会卡住整个batch,QPS一上来就雪崩。之前我跑Qwen2.5也是这问题,关掉chunked反而更稳,你可以对照下日志里的scheduler状态看看是不是有queue堆积。
你这八成是KV cache预留太狠了,试试把gpu_memory_utilization降到0.6,顺便开下--enable-chunked-prefill。
说实话你这个现象我踩过一模一样的坑,A100 80G看着显存吃满但吞吐上不去,大概率不是max_num_seqs的问题,而是vLLM默认把prefill和decode绑在一起调度了。你可以试试把--enable-prefix-caching打开,然后手动调一下--max-num-batched-tokens,这参数默认可能只有8192,Qwen2.5的attention计算量跟序列长度强相关,你把max_model_len降到2048再配合这个参数看看,说不定QPS直接翻倍。
另外你提到KV cache占显存高,这其实正常,但200 tokens/s确实偏低,我怀疑你并发压力测试时实际请求长度分布很极端。建议你抓一下日志里avg prompt throughput和avg generation throughput的比值,如果prefill耗时占比超过30%,那就是典型的prefill瓶颈,这时候单纯加并发没用,反而会互相挤占。你可以考虑把--max-num-seqs调小到16甚至8,让每个请求独占更多计算资源,同时把--scheduler-policy改成fcfs试试。
至于Tensor Parallel,单卡A100真没必要切,切了反而引入通信开销,除非你打算换双卡。最后一个小技巧,vLLM对Qwen系列有个隐藏参数叫--trust-remote-code,虽然默认开着,但某些版本会影响attention后端选择,你升级到最新版vLLM再跑一次,我上次就是从0.6.2升到0.7.1,同样配置速度从180涨到320。你先把这几项挨个试一遍,应该能找到问题。
A100单卡跑7B按理说余量很足,你显存吃满大概率是vLLM默认把可用显存全拿来建KV cache了,而max_num_seqs设太大反而会让prefill阶段并发请求挤占计算资源。我之前遇到过类似情况,把gpu_memory_utilization降到0.85,同时max_num_seqs压到64,tokens/s反而涨了30%多。另外你QPS一上去就卡,建议看看是不是输出长度设太长,或者用了流式但客户端没及时消费,这也会让显存被未释放的sequence占住。TP暂时不用考虑,单卡都没榨干,先试试调小batch和限制最长生成token数吧。