最近在折腾本地部署,用vLLM跑一个微调过的7B模型(Qwen2.5),显存占用大概14GB,但吞吐量一直上不去。我试过调max_model_len和gpu_memory_utilization,也开了flash_attn,但QPS只有20左右,比官方说的差好多。我看网上有人用同样的卡跑13B都能到50+,不知道是哪里配置有问题?还是说我的模型量化没做好?另外,我是用docker部署的,会不会有额外的性能损耗?求大佬指点一下排查方向,谢谢!
用vLLM部署7B模型,单卡A100推理速度只有20tokens/s正常吗?
全部回复
共 169 条20 tokens/s确实偏低了,我怀疑你max_model_len设太大导致显存碎片化,vLLM对连续显存要求很高。另外docker本身性能损耗很小,但记得加--shm-size参数,默认64M会限制内存带宽。量化的话除非用AWQ或GPTQ,否则FP16其实不影响吞吐。建议先跑一下vLLM官方benchmark脚本,把batch size拉高到32再对比,单序列请求很容易被调度开销拖垮。
20 tokens/s确实有点离谱,我拿A100跑Qwen2.5-7B不开量化,vLLM默认配置都能到35-40。你试试把--max-num-seqs调大点,比如64或128,有时候并发太低会严重限制吞吐。另外docker本身损耗可以忽略,但记得检查一下是不是CPU绑核或者内存带宽被限制了,用nvidia-smi看下GPU利用率是不是一直很低。
量化那块反而可能拖后腿,AWQ或GPTQ在A100上对7B这种小模型收益不大,甚至因为反量化开销掉速。建议你直接换FP16跑一下对比,如果速度上去了那就跟量化有关。还有个小坑,vLLM版本太旧的话对Qwen2.5的支持有bug,升到0.6.3+试试。
20 tokens/s确实偏低,但先别急着怀疑量化,Qwen2.5的7B在A100上跑40-60是常态。你检查过输入输出长度吗?如果生成长度很长或者并发请求多,吞吐掉到20也正常,官方benchmark一般用的是短序列+高并发。另外docker跑vLLM基本没有性能损耗,除非你用了默认的shm-size限制,建议加--shm-size=10g试试。还有个小坑,微调过的模型如果tokenizer和base版本不一致,vLLM会反复rehash,也会拖慢速度。
这速度确实不太对劲,我之前跑同尺寸的Qwen2.5在A100上随便都能到40+。你检查下是不是docker里没开共享内存,或者vLLM版本太旧,另外确认下微调时有没有混入padding之类的垃圾数据影响prefill效率。还有个小细节,如果输入长度普遍很长,QPS低也正常,你可以把平均输入/输出tokens数发出来对比下。
先确认下是不是开了--enable-prefix-caching,另外查下实际batch size,QPS卡20大概率是并发没打满。
docker跑vllm基本没损耗,重点查下是否走对了continuous batching,20确实偏低,试试把max_num_seqs调大点。
20 tokens/s确实有点不对劲,我怀疑你那个微调模型是不是带上了什么自定义算子或者动态图分支,vLLM对这类结构支持不好会直接掉速。建议先跑个官方原版Qwen2.5-7B对比下,如果原版能到40+那就是你模型的问题。另外docker跑vLLM其实损耗很小,但记得别加--ipc=host这类参数,有时候反而会干扰显存分配。量化的话你试过AWQ或GPTQ吗?4bit下A100能轻松翻倍,不过要确认下微调时的embedding层有没有被量化弄坏。
我遇到过类似情况,vLLM对微调模型的兼容性有时比基座模型差,尤其Qwen2.5系列有自定义module时容易踩坑。你可以先确认下是不是用了paged attention的旧版本,或者试试把tensor parallel设为1再对比。另外20 tps如果生成长度短的话可能正常,长文本吞吐会明显上去,官方benchmark通常是长序列的。docker确实有网络和共享内存开销,但影响不至于翻倍,建议先排除是模型本身embedding或lm_head没量化导致的显存带宽瓶颈。
20的QPS确实不对劲,我同样配置跑7B都能到60+,先查下是不是docker的共享内存和CPU绑核没设好。
20 tok/s确实偏低,我自己的经验是7B在A100上至少能到40+。你检查过vLLM版本没?旧版对Qwen2.5的优化差挺多的,升到0.6.x试试。另外docker本身损耗很小,但记得别把CPU和内存限制得太死,显存分配倒是其次。还有一个坑,如果微调时加了特殊token但没在vLLM里同步配置,也会拖慢生成。建议先跑个官方原版模型对比下,排除掉模型本身的问题。
20 tokens/s确实偏低了,我怀疑你docker网络或CPU绑核有问题,试试加--num-cpu-threads和--pipeline-parallel-size看看。
检查下是不是微调后权重没合并回原模型,或者KV cache没跑满,把--max-num-seqs调高到256再对比下。
20 tokens/s确实不太对劲,我怀疑你可能没走对vLLM的continuous batching路子,先确认下是不是用了--enable-prefix-caching或者开了--max-num-seqs,默认并发太低会卡在等待上。另外Qwen2.5的7B用A100跑,除非你micro-batch设得特别小,不然怎么也该翻倍。docker倒是影响不大,主要是共享内存和GPU直通配置,你检查下--ipc=host或者--shm-size有没有设。还有你那个量化是AWQ还是GPTQ?如果只是FP16那吞吐差距可能就来自这里。
20 tokens/s对于7B来说确实偏低了,但你先别急着怀疑量化,我怀疑问题出在vLLM的版本和模型配置的匹配上。Qwen2.5本身对vLLM的兼容性要求比较高,特别是如果你用的vLLM版本低于0.6.0,很多针对性的优化没生效,吞吐量上不去很正常。我之前跑Llama 3 8B的时候也遇到过类似情况,后来把vLLM更新到最新版,并把模型重新用官方脚本转换了一遍格式,速度直接翻倍。另外你说开了flash_attn,但我建议你确认一下编译时是否真的启用了,有时候docker镜像里默认是阉割版的,你得自己pip安装flash-attn源码包,否则只是参数开了但底层没生效。还有一点,max_model_len如果设得太大,比如超过2048,而实际输入很短,KVCache的预分配会浪费大量显存带宽,反而拖慢生成速度,你可以尝试把它降到1024再测。docker本身不会有太大性能损耗,但要注意共享内存和CPU绑核的问题,特别是如果宿主CPU核数不多,vLLM的调度线程会跟GPU传输争抢资源。最后建议你跑一下vllm自带的benchmark脚本,看看纯文本生成和并发条件下的tokens/s差异,如果单并发能到40+,那问题就出在你的请求预处理或服务端超时设置上,而不是模型本身。你先按这个思路排查,大概率能找到瓶颈。
20 tokens/s对7B来说确实偏低了,我怀疑问题不在vLLM本身,而是你微调后的模型有没有做weight-only量化?另外docker跑vLLM确实会有个位数百分比的损耗,但不会差这么多。你试试用--enable-chunked-prefill和--max-num-seqs调大并发,还有检查下是不是CPU bottleneck了,比如看下nvidia-smi的GPU利用率是不是跑不满。我之前也遇到过类似情况,最后发现是磁盘IO卡了加载权重的瓶颈。
20的QPS确实低了,我同配置7B能到40+,建议查下是不是docker没开共享内存或者CPU绑核问题。
20 tokens/s这个数字确实偏低,但先别急着怀疑vLLM本身,我怀疑你最大的瓶颈可能不在推理引擎,而在数据预处理或者batch策略上。我遇到过类似情况,单看吞吐量没意义,得看是不是真的把并发请求打满了,vLLM的continuous batching对并发很敏感,你如果只是单条请求循环压测,那它可能根本没发挥出优势,试试用脚本同时发几十个请求看下总QPS。
另外你说的量化问题,Qwen2.5的7B用FP16本来就不该这么慢,A100跑7B理论上应该能到100+,除非你微调后的模型结构有改动导致vLLM无法完全优化,或者你的docker镜像里CUDA版本和vLLM编译的版本不匹配,这个很容易被忽略但影响特别大,建议在容器里跑一下vllm自带的benchmark脚本排除环境因素。
还有个小细节,你max_model_len调的多少?如果设得过大,比如超过4K,vLLM会预分配大量KV cache,虽然显存占用高但实际计算效率反而下降,尤其你才用14GB,说明显存利用率可能没平衡好,试试把max_model_len压到2K再看看。至于docker损耗,理论上GPU直通后差别很小,但你得确认是不是用了nvidia-container-toolkit,而不是老式的nvidia-docker2,这个差异能导致几倍的性能差距。
最后建议你开下vLLM的日志看下prefill和decode的耗时分布,如果prefill特别慢那可能是输入长度太长,如果decode慢那就是batch没起来,方向完全不同。先别动量化,7B模型在A100上完全没必要量化,反而可能因为量化配置不当拖慢速度。
20tokens/s确实有点不对劲,不过得先看你测的是decode阶段还是包含prefill的整体吞吐。我之前用vLLM跑Qwen2.5-7B(非量化)在A100上,单并发情况下大概能到35-40tokens/s,如果是多并发(比如8路请求)吞吐能翻好几倍。你QPS只有20,很可能瓶颈不在显存或flash_attn,而是你测试时用的并发数太低了,vLLM的优势本来就在于高并发下的continuous batching,单条流式请求反而发挥不出效率。另外,你说的“量化没做好”这个方向我建议先放一放,FP16跑7B根本不需要量化,A100的显存带宽足够喂饱这个模型,问题大概率出在别处。docker确实会有一些网络和系统调用的开销,但通常不会导致性能减半,除非你用了奇怪的存储驱动或者CPU绑核没做。你可以先用官方benchmark脚本(比如benchmark_throughput.py)跑一下默认参数,对比下是不是自己业务代码里有什么串行逻辑把吞吐拖下来了。还有一个细节:检查下vLLM版本,有些老版本对Qwen2.5的支持有bug,建议升级到最新版并确认--enable-prefix-caching选项没误开,那个在长上下文场景下反而会拖慢速度。最后,如果方便的话把max_num_seqs调大到64或128试试,我怀疑你默认值太低导致GPU利用率上不去。
20的吞吐确实不太对劲,我拿A100跑Qwen2.5-7B不量化,max_model_len设4096,开flash_attn,单卡能稳在45-55之间。你试试把gpu_memory_utilization调到0.9以上,然后确认下是不是微调后tokenizer加了特殊token导致序列变长,这会影响实际生成速度。docker基本没损耗,除非你网络模式或者共享内存配得有问题。另外建议用vllm的benchmark脚本跑一下原版7B,排除模型本身的影响。
20 tokens/s对7B来说确实偏低了,但先别急着怀疑量化,你微调过的模型如果加了自定义op或者padding结构,vLLM的continuous batching可能没吃到红利。我之前遇到类似情况,最后发现是docker的shm-size太小,页表换页导致GPU利用率上不去,试试--shm-size=8g。另外你确认下是不是跑在greedy decoding,beam search会直接砍半吞吐,官方benchmark基本都是greedy。还有个小坑,Qwen2.5的tokenizer里有特殊token,如果pad_token没设对,vLLM会疯狂recompute,检查下generation_config。先按这几个方向查,比调max_model_len管用。
先看看是不是输入输出长度设置太保守,vLLM对短序列优化一般,长文本吞吐会掉很多。