最近在试着把Qwen2.5-7B部署到一台双卡3090的机器上,用的vLLM框架,打算做点小规模对话服务。我参考官方文档选了AWQ 4bit量化,结果跑起来发现显存占用快18GB,比官方说的12-13GB大不少。而且首token延迟要3秒多,官方demo才0.5秒左右。我检查了模型路径、量化方式和batch size(设为1),感觉没毛病,是不是哪里参数写错了?或者是不是我显卡驱动版本太低(535),跟vLLM的paged attention有兼容问题?求大佬指点迷津,实在不想再瞎试了……
用vLLM部署Qwen2.5-7B,量化后显存占用和延迟对不上官方数据?
全部回复
共 3 条这个问题很有代表性,几乎每个刚上手vLLM的人都会碰到类似“官方数字看着很美,自己一跑直接裂开”的情况。我先说结论:你的显存18GB和首token延迟3秒多,大概率不是模型文件坏了,也不是显卡驱动535和vLLM有“不兼容”这种玄学问题,而是vLLM默认配置和官方测试环境之间存在几个非常隐蔽的差异点。我过去一年多在内部集群和边缘设备上反复折腾过Qwen系列的各种量化部署,踩过的坑比你还多,下面把几个最关键的排查方向拆开讲。
首先,显存18GB对AWQ 4bit Qwen2.5-7B来说,确实偏大,但并非不可能。官方说的12-13GB通常是指纯模型权重加载后的静态显存占用,也就是把模型参数从硬盘读到显存里,不做任何推理时的基础占用。7B模型FP16权重大约14GB,AWQ 4bit量化后理论权重只有约3.5GB,但vLLM为了支持paged attention和连续批处理,会预留大量额外显存用于KV cache、中间激活值、以及预分配的内存池。你设置了batch size为1,但vLLM有一个关键参数叫max_num_seqs(默认通常是256或更大),这个参数控制的是vLLM内部为同时处理的最大序列数预留的显存,即使你实际只发1个请求,它也会按256个序列的KV cache去分配显存。另外还有一个gpu_memory_utilization参数,默认是0.9,也就是说vLLM会尽量占用90%的可用显存来构建缓存池,而不是精确只加载模型权重。你的双卡3090单卡24GB,如果vLLM默认把所有显存都算进去(包括另一张卡?注意vLLM默认是单卡部署,除非你明确指定tensor parallel),那么18GB其实包含了大量预分配的KV cache空间。你可以试试在启动vLLM时加上--gpu-memory-utilization 0.5甚至更低,比如0.3,同时把max_num_seqs显式设为2或4,看看显存会不会立刻降下来。我做过实验,Qwen2.5-7B AWQ在单卡3090上,如果gpu_memory_utilization设为0.4,max_num_seqs=4,显存占用可以控制在12GB出头,首token延迟也会因为显存碎片减少而略有改善。
其次,首token延迟3秒多,这个差距比显存更让人抓狂。官方demo的0.5秒通常是在理想环境下测的,比如A100 80GB,CUDA 12.1,vLLM最新版本,并且可能用了FP8或者更激进的量化策略。你的环境是双卡3090,但vLLM默认并没有启用tensor parallel(需要加--tensor-parallel-size 2),如果你只用了单卡,那3090的显存带宽(约936GB/s)比A100(2TB/s)差了一倍多,加上AWQ量化后的计算效率对3090的Tensor Core并不友好(AWQ的packing格式在Ampere架构上需要额外的dequantize步骤,而H100有原生的FP8支持),所以首token延迟3秒其实并不离谱。但你可以在vLLM的启动参数里加几个优化:一是启用--enable-prefix-caching(如果对话有固定system prompt,能大幅减少首token计算量),二是把--max-model-len设小一点,比如2048或4096,而不是默认的32768(Qwen2.5-7B支持32K上下文,但如果你对话长度很短,预留太长的KV cache不仅浪费显存,还会导致attention计算量剧增)。另外,检查一下你的vLLM版本,0.4.x和0.5.x在AWQ推理上有较大的性能差异,0.5.x之后集成了FlashAttention 2的优化,对首token延迟有显著改善。如果你还在用0.4.x,升级到0.6.0或最新版(写回复时0.6.3已发布),通常能直接砍掉一半延迟。
还有一个容易忽略的点:你的模型路径是否正确加载了量化配置?AWQ量化后的模型文件通常会包含一个quantize_config.json,里面指定了group_size(一般是128)、zero_point、对称量化等参数。如果你是从HuggingFace直接下载的官方AWQ版本(比如Qwen/Qwen2.5-7B-Instruct-AWQ),那没问题。但如果你是自己用autoawq或者其他工具量化的,务必确认--quantization awq参数和模型内的config匹配。vLLM对AWQ的支持目前只认group_size=128且sym=False(非对称量化)的配置,如果你用了group_size=64或者sym=True,vLLM会fallback到FP16推理(这会导致显存和延迟都爆炸)。你可以用这个代码快速验证一下:
python
from transformers import AutoConfig
config = AutoConfig.from_pretrained("你的模型路径")
print(config.quantization_config)
如果返回None或者字段不全,那vLLM实际上是在跑FP16,显存18GB也就说得通了。
驱动版本535确实有点老,但不会导致这种级别的偏差。vLLM的paged attention依赖CUDA Graph和自定义kernel,535驱动搭配CUDA 11.8或12.1都能正常工作。你更应该检查的是CUDA runtime版本是否和vLLM编译时用的版本一致。如果你是用pip安装的vLLM,它默认绑定了CUDA 12.1的预编译包,而你的系统如果装的是CUDA 11.8,会触发动态库回退,性能下降20-30%。建议跑一下vLLM的benchmark脚本,或者直接在Python里打印torch.version.cuda,看看是不是12.1。如果不是,要么升级系统CUDA,要么用pip install vllm --no-deps然后手动安装对应版本的torch。
另外,双卡3090你打算怎么用?如果只是做简单的对话服务,单卡其实就够了,因为Qwen2.5-7B AWQ单卡延迟在1秒以内(经过上述优化后)。如果你为了吞吐量想用tensor parallel,那要注意3090之间是通过PCIe通信的(不像A100有NVLink),跨卡通信延迟会显著增加首token延迟。我建议你先把双卡拆开,部署两个独立的vLLM实例,分别监听不同端口,然后用nginx做负载均衡。这样每张卡单独处理请求,首token延迟反而比tensor parallel更低,尤其是当请求并发数不大时。如果你的使用场景是单用户连续对话,batch size=1,那tensor parallel带来的收益几乎为零,只有显存翻倍(两张卡能加载更大的模型),但延迟会因为是跨卡通信而变差。
最后,给你一个可复现的启动命令参考,假设你用的是Qwen2.5-7B-Instruct-AWQ官方版本,单卡3090,显存24GB,目标首token延迟1秒以内,显存占用12-13GB:
python -m vllm.entrypoints.openai.api_server \
--model Qwen/Qwen2.5-7B-Instruct-AWQ \
--quantization awq \
--gpu-memory-utilization 0.45 \
--max-model-len 4096 \
--max-num-seqs 4 \
--enable-prefix-caching \
--dtype auto \
--trust-remote-code
启动后,用vLLM自带的benchmark脚本测试:
python -m vllm.benchmarks.benchmark_latency \
--model Qwen/Qwen2.5-7B-Instruct-AWQ \
--quantization awq \
--input-len 128 \
--output-len 128 \
--batch-size 1
如果首token延迟还在2秒以上,那就要检查你的CUDA版本和vLLM版本了。另外,记得把系统里其他占用显存的服务关掉,比如nvidia-smi看看有没有别的进程在吃显存。
总的来说,官方数据是在特定硬件、特定软件栈、特定参数组合下的“最佳成绩”,而你实际部署时默认参数往往是为吞吐量设计的(预留大量显存和KV cache),直接套用自然对不上。只要把gpu_memory_utilization和max_num_seqs调低,确认AWQ加载成功,升级vLLM到最新,你的延迟和显存应该能回归到合理范围。如果还不行,欢迎把nvidia-smi输出、vLLM启动日志贴出来,可以再帮你细看。
这个情况我前两天刚遇到过类似的坑,可以分享点排查思路。首先AWQ 4bit显存18G确实偏高了,7B模型理论上4bit应该在4-5G左右,加上KV cache和中间激活值,单卡12-13G是合理的。你双卡3090跑18G,我怀疑是模型没有真正加载成4bit,或者vLLM默认用了FP16的KV cache。可以检查一下--quantization awq参数是否正确传递,以及用nvidia-smi看看实际显存分配,是不是有两份模型副本。
首token延迟3秒也很反常,3090单卡跑7B模型推理,首token应该秒级以内。你可以试下把--max-model-len设小一点,比如2048,vLLM默认可能会按4096甚至更长预分配显存和计算资源,这会导致首token延迟暴涨。另外驱动535确实有点老,vLLM的paged attention对CUDA版本比较敏感,建议升到545或550以上,我之前从535升到545后,同样配置下显存占用直接降了2-3G。
还有个细节:你检查下模型路径是不是真的指向了AWQ量化版本,有些人下的是原始BF16模型,然后手动传了--quantization awq,这样vLLM会先加载原始模型再运行时量化,反而更吃资源。最好用官方提供的已经量化好的模型文件,比如Qwen/Qwen2.5-7B-Instruct-AWQ这个路径。
最后确认下vLLM版本,0.6.0之后对Qwen2.5支持更好,老版本可能有bug。如果还不行,试下单卡跑,双卡通信开销在小batch下反而会拖慢延迟。
老实说,你这个显存占用快18GB确实有点离谱,我拿同样配置跑过Qwen2.5-7B的AWQ版本,大概在13.5GB左右,你那个是不是不小心加载了原始fp16模型?或者你检查下vLLM的--max-model-len参数,默认可能设得太高导致预留了过多KV cache空间,我上次就是调了这个从17GB降到14GB。延迟3秒多的话,首token慢大概率是预填充阶段的问题,可以试试把--gpu-memory-utilization设到0.9以上,或者检查下vLLM版本是不是0.6.x,老版本对AWQ的kernel优化确实不够。另外你提到的535驱动,我印象中vLLM的paged attention对535支持还行,但建议升到545或550,有些底层cuda算子效率会好不少。还有个小细节,你确认下模型文件里的config.json里quantization_config是不是写的"awq",有时候量化完路径不对会回退成bf16推理。如果这些都查过了,那可能得换个量化方式试试GPTQ,我在3090上跑延迟反而比AWQ稳。