最近在搞一个内部知识库问答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,显存占满但推理速度上不去,是哪里没调对?
全部回复
共 148 条这问题我上周刚踩过类似的坑,A100跑7B其实不需要把gpu_memory_utilization拉满,留个10%给tensor并行和调度器会顺很多。另外vLLM对Qwen系列建议把--enable-prefix-caching打开,尤其你这种知识库场景重复前缀多,能省不少KV cache的显存占用。prefill阶段卡顿的话试试调低max_num_batched_tokens,默认值对长文档推理很吃亏,我改成2048后吞吐直接翻倍了。你那边QPS卡住的时候有没有看nvidia-smi的SM占用率?如果没跑满大概率是CPU喂数据跟不上,得配合异步数据加载。
遇到过类似的坑,A100跑7B其实完全不需要吃满80G,你试下把gpu_memory_utilization降到0.6左右,给KV cache留点余量,别让它跟模型抢显存。另外max_num_seqs别一次拉太高,先设32看看,prefill阶段瓶颈多半是并发请求长度参差不齐导致的,试试用--enable-chunked-prefill把长请求拆开,QPS应该能上来不少。TP就没必要切了,单卡7B本身就不吃紧,问题大概率在调度策略上。
A100上200 tokens/s确实不对劲,先查下是不是QPS高时prefill和decode争显存了,试试把max_num_seqs调小点。
我遇到过类似情况,多半是长上下文把KV cache撑爆了,换下chunked prefill试试,比调TP管用。
A100 80G跑7B其实很宽裕,你这显存占满是正常的,vLLM默认会把能用的显存全吃进去做KV cache,不是问题。QPS一高就卡住大概率是prefill和decode争资源,试试把--enable-chunked-prefill打开,或者调小--max-num-batched-tokens,别让它一次性塞太多请求进来。另外单卡A100跑7B真没必要上TP,先看下是不是输入长度太夸张,日志里没报错但实际请求超时也算卡住,监控下平均输入token数再判断。
单卡A100跑7B这个吞吐确实偏低了,我怀疑你并发打上去之后瓶颈不在显存而在CPU和GPU之间的数据传输,尤其是prefill阶段如果batch内序列长度差异大,padding浪费会很严重。你可以试试把--enable-chunked-prefill打开,或者手动调低--max-num-batched-tokens,让每次调度的小token数更贴合实际请求。另外Qwen2.5的官方vLLM配置里其实推荐用--rope-scaling配合长上下文,但你这4096根本用不上,反而可能因为默认的continuous batching策略没生效导致排队。我上次跑类似模型是把--block-size改成32,吞吐直接翻倍,你可以先看看是不是block管理太碎。最后别急着上TP,单卡先确认下是不是--swap-space设太大,把内存当显存用了。
我之前也遇到过类似情况,vLLM默认的continuous batching对prefill和decode的调度其实挺吃显存的,你试试把--enable-prefix-caching开开,或者手动限制一下KV cache的预留比例,别让gpu_memory_utilization顶到0.95,留点余量给碎片。
另外200 tokens/s在单卡A100上跑7B确实偏低,但如果你max_num_seqs调太大,prefill会排队堵住decode,QPS一高就卡死。可以先把max_num_seqs降到64左右,再观察下吞吐变化。
还有个小点,Qwen2.5的attention实现跟vLLM版本匹配度很关键,你确认下用的vLLM是不是0.6.2以上的,老版本对GQA支持不好,会白白多占显存。
真要追求高并发,TP=2在A100上效果很明显,但单卡的话先把prefill和decode的调度参数分开调,别一把梭。
你这个问题我前两天刚踩过类似的坑,先说结论:单卡A100上7B模型跑200 tokens/s其实不算离谱,但如果你看的是网上那些benchmark,多半是拿纯生成阶段测的,没算prefill。你说的显存吃满但QPS上不去,大概率是max_num_seqs设太大,导致并发请求同时挤进prefill阶段,计算全耗在长序列处理上,生成阶段反而饿死了。建议把max_num_seqs先压到32甚至16试试,同时把gpu_memory_utilization留到0.85以上,但别全给KV cache,给调度留点余量。另外vLLM对Qwen2.5系列其实没有特殊配置,不过你可以试试加--enable-chunked-prefill,把长prompt拆成块跟生成交错执行,对并发提升特别明显。还有个坑是max_model_len如果设4096但实际请求长度远小于这个值,KV cache预留会浪费,改成动态长度或者直接设成你数据集里最长样本的1.5倍。Tensor Parallel暂时别想,7B单卡完全够,切了反而增加通信开销。最后你查一下是不是开了--enforce-eager,有时候图编译模式反而在短请求下拖慢速度,关掉换默认模式试试。
这问题我踩过一模一样的坑,A100 80G跑7B模型显存看着吃满其实大头全在KV cache和预分配上。你设的gpu_memory_utilization如果超过0.9,vLLM会默认给KV cache预留大量空间,但实际并发没到那个量级,纯属浪费。建议先砍到0.7试试,同时把max_num_seqs调低到32左右,这俩参数对吞吐影响很大,不是越大越好。另外QPS卡住基本都是prefill和decode阶段资源竞争的问题,你试试加--enable-chunked-prefill,把长请求拆开,能明显缓解阻塞。还有别迷信Tensor Parallel,单卡7B根本不需要,切了反而多一层通信开销。最后确认下你的Qwen版本是不是官方推荐的AWQ或GPTQ量化版,FP16跑7B在A100上本来就不该只200 tokens/s,我怀疑你数据加载或tokenizer有瓶颈,试下直接跑内置的benchmark脚本对比下基线。
我之前也遇到过类似的坑,vLLM对Qwen系列其实有隐藏的默认配置,比如prefill chunk size和KV cache的量化策略会直接影响显存分配。你试试显存利用率别拉太高,留点给CPU offload,然后重点看下continuous batching的调度是否被长尾请求拖累。另外单卡A100上TP没必要切,但可以考虑把max_num_seqs调小到32左右,同时开下--enable-prefix-caching,长文档场景提升特别明显。日志没报错基本就是调度瓶颈,可以抓一下vLLM的metrics看下prefill和decode的耗时分布。
显存吃满但吞吐上不去,大概率是prefill和decode阶段资源分配打架了,vLLM默认策略有时候对7B这种小模型反而保守。你试试把max_num_batched_tokens调大点,或者直接限制一下max_num_seqs,别让并发请求全挤在prefill阶段。另外A100跑7B真没必要上TP,单卡就够了,先看看是不是CPU负载瓶颈或者数据加载卡IO。我上次遇到类似情况是tokenizer并行没开,你可以查下vllm的启动日志里有没有相关warning。
说实话你这个现象我太熟了,之前用vLLM跑Qwen2.5系列也踩过类似的坑。显存吃满但吞吐上不去,多半不是max_num_seqs的问题,而是你给prefill和decode分配的算力比例失衡了——vLLM默认会尽量塞满batch,但A100上如果连续请求的prompt长度差别很大,prefill阶段会占住大量SM,decode阶段反而在等显存带宽,QPS一高就卡住。建议你试着把--enable-prefix-caching打开,内部知识库问答的query往往有重复的系统提示词或历史上下文,命中前缀缓存能省掉不少重复计算。另外,max_model_len调到4096其实不一定有好处,如果实际输入没那么长,反而会让KV cache的预留空间变大,建议用--max-num-batched-tokens限制单次迭代的总token数,比如设成8192或16384,让调度器更平滑。还有一点,单卡A100跑7B其实没必要上Tensor Parallel,除非你打算上量化或者同时跑多个模型,否则光通信开销就够吃一壶了。最后可以看下服务端的scheduler日志,确认是不是有大量swapped blocks,如果有,说明你的KV cache管理策略需要调整,比如调低gpu_memory_utilization到0.85左右,留点余量给内存碎片。
这问题我上周刚踩过,大概率不是prefill的锅,你先看下是不是vLLM版本太老,升到0.6.3+对Qwen系列有专门的优化。另外max_num_seqs别拉太高,A100上8-16就够,太高会导致显存碎片化反而卡调度。还有个小坑,Qwen2.5的tokenizer会额外吃不少显存,试着把--enable-prefix-caching开开,长文档场景能省很多重复计算。实在不行再上TP,但单卡7B真没必要,先查下是不是你压力测试脚本里并发请求的输入长度差别太大,导致batch里最长的那个拖垮了整体速度。
说实话我之前也踩过这个坑,A100上单卡跑7B显存吃满是正常的,但速度上不去大概率不是显存问题。你试试把gpu_memory_utilization降到0.6以下,给KV cache留点余量,同时把max_num_seqs调小到64左右,有时候并发太高反而会触发碎片化调度。另外Qwen2.5的prefill和decode开销差异挺大,你可以用vllm的--enable-prefix-caching试试,对知识库场景的重复query提升很明显。还有就是别急着上TP,单卡A100对7B来说算力足够,先检查下是不是输入长度太长导致prefill占了大部分时间,把max_model_len设成2048再压测一轮看看。
看到你说显存直接80G占用但吞吐上不去,我第一反应是max_num_seqs可能设太大了,你试试把它降到32或者16看看。vLLM在prefill阶段是顺序处理的,并发高的时候每个sequence的prompt如果都很长,计算会集中在前面那几个batch上,后面全在排队等显存释放,QPS自然卡住。我上次跑Yi-34B也遇到过类似情况,后来发现是gpu_memory_utilization设到0.95导致KV cache预留太多,但实际并发的KV用量根本没到那个阈值,反而因为预分配了物理显存,导致CUDA内存碎片化,调度器频繁做内存交换。你可以打开vLLM的verbose日志,看看每个step的scheduler状态,尤其是等待队列长度和block manager的利用率,这比猜参数靠谱。另外7B模型在A100上完全不用切Tensor Parallel,单卡足够,切了反而因为通信开销拖慢小batch的延迟。还有个细节,Qwen2.5的attention是用GQA的,vLLM对GQA的优化在不同版本差异挺大,你升级到0.6.3以上的版本,然后试下--enable-prefix-caching,如果知识库的prompt有公共前缀,这个能大幅减少prefill计算量。最后建议你把max_model_len设回默认的32768,然后单独压测不同输入输出长度比,因为长prompt短response的场景和短prompt长response的瓶颈完全不一样,你现在4096反而可能让vLLM的连续batch策略更保守了。
试试把max_num_seqs调小点,prefill并发太高会卡计算,另外确认下是不是被CPU offload拖了后腿。
A100 80G跑7B按理说很宽裕,200 tokens/s确实不对劲。你试试把--enable-chunked-prefill打开,prefill和decode混着调度能救不少吞吐,另外max_num_seqs别拉太高,8-16就够,太高反而排队。还有确认下是不是被CPU offload拖了,看下nvidia-smi里GPU利用率是不是一直很低。之前我碰到类似情况是H20上的NVLink没生效,你单卡应该没这问题,但可以检查下vLLM版本,换0.6.3之后调度策略改过。
显存吃满但吞吐上不去,大概率是prefill和decode阶段资源没解耦,vLLM默认策略会把显存优先分给KV cache,但你max_num_seqs调太高反而让batch里长序列互相拖累。我之前跑Yi-34B也遇到过类似情况,把max_num_seqs砍到32,同时开--enable-prefix-caching,吞吐直接翻倍。另外A100单卡跑7B没必要上TP,先试试把--max-model-len降到2048,再把--gpu-memory-utilization留10%余量给碎片,看是不是调度器卡在显存分配上了。你QPS卡住的时候GPU利用率是多少?如果只有30%左右,那瓶颈可能在CPU的数据加载或者tokenizer上。
我之前也踩过类似的坑,建议先别急着上TP,单卡A100跑7B其实没必要。你试试把gpu_memory_utilization降到0.85左右,留点显存给CUDA context和pytorch缓存,另外max_num_seqs别设太大,16到32之间反而吞吐更稳。prefill阶段卡顿大概率是长请求导致的,可以开下prefix caching,或者把--enable-chunked-prefill加上,对并发提升挺明显的。还有,网上说的tokens/s很多是理想批大小下的数据,你拿200作为基准可能本身就偏高了,2000并发和20并发完全两个概念。
这问题我太有同感了,之前用7B模型在A100上也撞过类似的墙。你首先要确认下是不是vLLM的continuous batching没真正生效,因为很多坑是前置的,比如你的请求输入长度分布是不是特别不均,prefill和decode阶段混在一起调度会严重拖慢整体吞吐。我上次发现max_num_seqs设大了反而导致每个batch里长序列占住显存,短请求根本挤不进去,实际并发反而降了,建议你监控一下每秒实际处理的请求数,而不是光看tokens/s。另外,如果你用的是默认的chunked prefill策略,可能对长文档场景不友好,可以试试把--enable-chunked-prefill显式关掉,让每个请求完整算完再进decode,有时候反而快。还有,Qwen2.5的GQA机制在vLLM里需要配合--kv-transfer-config,如果你没动过这个,KV cache可能按MHA模式分配了,白白浪费一半显存。至于Tensor Parallel,单卡7B真没必要切,除非你同时跑多个模型,不然通信开销比收益大。最后,你日志里没报错不代表没瓶颈,建议开--verbose看下每个step的queue时间,如果queue一直满,那就是调度参数问题,不是显存问题。
大概率是并发时prefill和decode抢资源,试试把max_num_seqs调小点,或者开下chunked prefill。