你的经验我也有过,rdna只能用W4A16量化的模型,其他模型均无pre compiled kernel 奇慢无比。你可以和试试我这个量化模型
flyer666
-
7900XTX双卡跑VLLM跑 Qwen3.8 27b实录 -
7900XTX双卡跑VLLM跑 Qwen3.8 27b实录双 RX 7900 XTX(RDNA3)跑 vLLM + Qwen3.8-27B 实录
动机(为什么折腾这个)
今年四月左右看了lcz版主的视频,在家弄了双卡 vLLM 这套主机有一阵了。今天看到lcz视频里提到a卡双卡支持很差,有点小不服,所以贴一下这几天捣鼓的经验。首先说,能跑肯定是能跑,但是短上下文体验远远不如LLaMA.cpp (尤其是mtp聊胜于无),但是如果有agent多并发需求还是可以尝试一下。
起因是之前主力用 llama.cpp:
启动快、跑得稳,但多路并发的缓存重用很差——几个 agent / harness 同时
跑的时候,各自的上下文来回反复预填充,很容易陷入"refill 怪圈":看起来在
干活,实际大量时间耗在重复 prefill 上,实际体验一般。所以想试试 vLLM 的
前缀缓存(prefix caching)能不能把这摊事理顺。折腾下来发现 vLLM 在 RDNA3
上能跑,但坑是真不少,整理成这篇实录。先感谢 vLLM 社区这几个让 Qwen 系模型在 RDNA3 上真正能跑的 PR,没有它们
这个帖子不存在:- vllm-project/vllm#41394 — RDNA3 W4A16 原生 HIP 线性内核(
RDNA3W4A16LinearKernel)。
W4A16 GPTQ 模型在 gfx1100 上流畅推理的基石。没有它只能走 Triton JIT 回退,
冷启动编译一次能等到怀疑人生。 - vllm-project/vllm#48816 / #47828 — Qwen3.5 MTP drafter BF16 权重加载修复。
官方 AutoRound GPTQ 仓库把 MTP 张量存成纯 BF16,量化配置却声明 4-bit,
加载器直接报错。这两个 PR(配合本地把规则改成-:.*mtp.*排除)让 MTP
能正常加载运行。
顺便提了一下,有些大神已经开始搞sglang的7900xtx的支持了,过几天我也试一下:https://github.com/sgl-project/sglang/issues/30599
下面是完整实录。
硬件
应版主要求,先上图:

- 主板:ASRock X670E Taichi Carrara(AM5;双卡时 CPU 的 PCIe 4.0 x16 拆成
两个 PCIe 4.0 x8,每卡约 16 GB/s,对推理完全够用) - CPU:Ryzen 5 9600X(6C12T)
- 内存:32 GB DDR5
- GPU:2× RX 7900 XTX(gfx1100,24 GB 单卡)
- ROCm 7.14(HIP 7.14.60850)
安装
uv venv --python 3.12 --seed --managed-python uv pip install vllm --extra-index-url https://wheels.vllm.ai/rocm/ --upgrade装出来:vllm 0.27.1+rocm723、torch 2.11.0+rocm、triton 3.6.0、
transformers 5.15.1、Python 3.12.13。最大的坑:amdsmi 引导(不解决这个根本起不来)
ROCm 上如果 torch 是第一个 import amdsmi 的库,torch 的
_amdsmi_cdll_hook
会加载一份冲突的libamd_smi.so,结果torch.cuda.device_count()返回 0
(HIP 明明能看到两张卡),vLLM 直接报Failed to infer device type。解法:在 import torch 之前先 import amdsmi。我们写了
serve-bootstrap.py
做这件事,每次都通过它启动 vLLM,原样贴出来:#!/usr/bin/env python """Bootstrap for native vLLM serve on ROCm. Pre-imports `amdsmi` BEFORE torch so that torch's `_amdsmi_cdll_hook` (torch/cuda/__init__.py) reuses this already-loaded module instead of loading a second, conflicting copy of libamd_smi.so. Without the pre-import, amdsmi reports 0 GPUs after torch loads (ODR violation), torch.cuda.device_count() returns 0, and vLLM fails platform detection with "Failed to infer device type". Usage: serve-bootstrap.py <vllm-subcommand> [args...] e.g. serve-bootstrap.py serve --model ... --port 8080 """ import sys import amdsmi # noqa: F401 -- must be imported before torch from vllm.entrypoints.cli.main import main if __name__ == "__main__": sys.exit(main())用法:
python serve-bootstrap.py serve --model <model_dir> --port 8080 ...其它参数启动(当前生产:非 MTP,fp8 KV,TP2)
export HSA_OVERRIDE_GFX_VERSION=11.0.0 export HSA_ENABLE_IPC_MODE_LEGACY=0 export FLASH_ATTENTION_TRITON_AMD_ENABLE=TRUE export VLLM_ROCM_USE_AITER=1 export HSA_FORCE_FINE_GRAIN_AMDGPU=1 export VLLM_ENGINE_READY_TIMEOUT_S=1800 export VLLM_ENGINE_ITERATION_TIMEOUT_S=1800 export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=1800 python serve-bootstrap.py serve \ --model ~/Documents/vllm-serving/qwen3.8-27b-mtp-fixed \ --tensor-parallel-size 2 \ --host 0.0.0.0 --port 8080 \ --kv-cache-dtype fp8 \ --max-model-len 262144 \ --max-num-seqs 8 \ --max-num-batched-tokens 2048 \ --attention-backend TRITON_ATTN \ --enable-prefix-caching --enable-chunked-prefill \ --performance-mode interactivity几个为什么:
--kv-cache-dtype fp8:跑 MTP 时是必须的(模型 FP16,drafter 的
context_attention_fwd在 bf16 KV 下会报fp16 × bf16dot 断言)。但非
MTP + TRITON_ATTN 下 bf16 KV 实测完全可用(0/16k 上下文 64.7/50.8 tok/s,
与 fp8 相当甚至略好)。用 fp8 的实际理由是 KV 内存减半——--max-model-len 262144下 bf16 KV 会很吃显存。- **
--max-num-seqs 8单人使用 大部分harness都够了 - 超时别设超过 1800:设成 3600000 会撑爆 zmq int32,vLLM 陷入重启死循环。
- 启动后先 warmup:第一批请求会吃 Triton JIT 编译的卡顿,脚本里发个
"hi" 请求把 JIT 吃掉。
想开 MTP?怎么改、以及为什么我们没开
MTP(多 token 预测投机解码)在短上下文确实能白嫖提速(pp=32 时 +32%)。
想开的话,在上面那个命令基础上改三处:# 1) 加投机解码配置(spec=3 实测最优,1/2 不够摊成本,4 过犹不及) --speculative-config '{"method":"mtp","num_speculative_tokens":3}' \ # 2) performance-mode 必须换成 throughput(interactivity 会触发 # MTP drafter 的 inductor 编译 bug) --performance-mode throughput \ # 3) KV 缓存保持 fp8(MTP 下 bf16 KV 必崩:drafter 的 context_attention_fwd # 会报 fp16 x bf16 dot 断言) --kv-cache-dtype fp8 \前提是模型检查点已经打过 MTP 量化规则补丁(见"踩坑速览"第 1 条)。
但我们最终默认没开 MTP,原因就一句话:长上下文惨不忍睹。
- MTP 的 drafter 每步都要把整个 KV 缓存重新 attention 一遍,上下文越
长越慢:pp=2048 时已经变成负收益(46.2 vs 51.2 tok/s);到 16k 深度直接
崩到 13.8 tok/s,同期非 MTP 还有 45.7。 - 我们的主要场景是跑 agent / harness,上下文只会越滚越长,MTP 属于开局
猛、后面拖后腿,所以干脆默认关掉。短对话 / 数学 / 代码类任务想开就开,
收益 +32% ~ +13%。
所以当前生产是非 MTP + fp8 KV,深度表现反而更稳。
性能速览
场景 数字 非 MTP 并发 8 272 tok/s(ns=8) 非 MTP 单流短上下文 52–64 tok/s 16k 深度解码(非 MTP) ~48 tok/s 32k 深度解码(非 MTP) ~42 tok/s 冷 prefill 1k / 16k / 32k 1757 / 955 / 623 tok/s MTP 短上下文(pp=32) +32%(70.2 vs 53.2) MTP 16k 深度 13.8 tok/s(崩了,别用) 踩坑速览(详情都在这篇里的链接和注释里)
-
本地 model config 改动:MTP 的量化规则从
+:改成-:(可复现)。
HF 官方Vishva007/Qwen3.8-27B-W4A16-AutoRound-GPTQ的config.json/
quantization_config.json里dynamic有 98 条规则,其中 MTP 是两条
正向包含:+:.*mtp.*和+:.*mtp\.fc.*(按 4-bit 处理 MTP)。
我们本地(qwen3.8-27b-mtp-fixed/,连同 HF cache 快照里的 config)把它
改成 97 条:删掉两条+:,加一条-:.*mtp.*排除。其余 96 条
linear_attn 规则及所有字段零差异。为什么这么改:
model_extra_tensors.safetensors里 15 个 MTP 张量其实是
纯 BF16(实测 dtype 全为 bfloat16),不是 4-bit。+:规则会让 GPTQ
加载器要求 MTP 提供qweight,直接报
ValueError: no module or parameter named 'layers.0.mlp.down_proj.weight';
改成-:排除后,vLLM 的qwen3_5_mtp.py检测到排除规则自动让 MTP 走
非量化(BF16)加载(对应
#48816 /
#47828 的修复路径)。
注意mtp-fixed目录里 config 两件是实体文件,权重文件是软链指向
HF 缓存。 -
MTP 只适合短上下文:dense drafter 每步要整上下文 attention,深度一
上去直接崩。数学/代码类 +32%~+13%,创意写作是负收益。深度任务用非 MTP。 -
AITER attention 别选:
--attention-backend ROCM_AITER_UNIFIED_ATTN
在这套环境上(amd_aiter 0.1.19 + gfx1100)会无声卡死,import aiter
直接死锁,严重时把 amdgpu 驱动搞挂,只能重启机器。 -
为什么 llama.cpp MTP 深度给力而 vLLM 不行:内核效率问题。vLLM 的
Triton attention 在 16k 上下文每行 query 要 24–27 ms,llama.cpp 的 ggml
FA 只要 4–5 ms。MTP 就是把这整上下文的行数乘了倍,vLLM 自然崩。 -
#45916 的 split-KV 我们试过:它改的
kernel_paged_attention_2d在这
套栈上根本不会执行(dense 解码走 GDN 融合的kernel_unified_attention),
属于改了用不上,已回滚。 -
改过 wheel 后务必清编译缓存:
rm -rf ~/.cache/vllm/torch_compile_cache,
否则各种灵异现象(性能骤降、MTP inductor 报错)。
结语
双 7900 XTX 跑 vLLM 是完全可行的,当前非 MTP 配置在短上下文有 52–64 tok/s
单流、并发可到 270+ tok/s,深度解码也稳。MTP 想深度用就得上 llama.cpp。
有同样硬件配置的朋友欢迎交流。 - vllm-project/vllm#41394 — RDNA3 W4A16 原生 HIP 线性内核(