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 线性内核(
-
,
T terry 固定了此主题
-
看到终于有人用这个双卡7900xtx了,献上我用了一个多月的vllm吧,直接用这个https://github.com/JartX/vllm perf/rdna3_full_stack 分支的吧!
RDNA3W4A16LinearKernel 这个东西就是这位Jartx老哥提的pr,它还修复了好多7900xtx的kernel,它自己现在就是4卡7900xtx了。现在做的W4A16量化prefill和decode 速度都3090一样的速度了
现在还缺W4A8 W8A8 MXFP4等支持
下面贴一下这个分支的特性,做了很多针对gfx1100 推理关键kernel的修复1. 注意力(KV cache 量化)——优化最重、收益最大 ┌───────────────────┬───────────────────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────┬─────────────────────────────────────────────────┐ │ 优化 │ 内核 │ 门控条件 │ 收益(README 实测) │ ├───────────────────┼───────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────┤ │ INT8 prefill │ paged_prefill_attn_rdna3_v2_int8(HIP WMMA) │ --kv-cache-dtype int8_per_token_head + TRITON_ATTN + HS∈{64,128,256} + 纯 │ 3.03ms vs Triton 25ms(8.3×);整机 1209 vs 727 │ │ │ │ prefill continuation + 无 alibi/swa/sink/softcap │ tok/s(+66%),VRAM −50% │ ├───────────────────┼───────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────┤ │ INT8 decode │ pth_decode_int8_rdna3(HIP split-KV,1-wave) │ 同上 + HS==256 + max_query_len≤128 │ decode 主路径 │ ├───────────────────┼───────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────┤ │ INT4 │ paged_prefill_attn_rdna3_v2_int4 + pth_decode_int4_rdna3 + │ int4_per_token_head + HS∈{128,256} │ ~1150 tok/s(+58%),VRAM −75% │ │ prefill/decode │ rht_rotate_inplace_rdna3 + reshape_cache_int4_rdna3(融合 RHT) │ │ │ └───────────────────┴───────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────┴─────────────────────────────────────────────────┘ 关键点:这个阶段与权重量化完全无关,只由 --kv-cache-dtype 决定。 2. W4A16 权重 GEMM(两套 HIP 内核,按对称性分叉) ┌────────────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ 内核 │ 支持的量化 │ 路径 │ ├────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ gptq_gemm_rdna3 + gptq_gemm_rdna3_wmma(q_gemm_rdna3*.cu,fork │ 对称 int4 = uint4b8(GPTQv1 布局,ExLlama shuffle,存储 zp = │ RDNA3W4A16LinearKernel(优先级第一);bf16 M≥16 → WMMA(prefill 128×64 主核),M=1 → │ │ 自研) │ 实际 zp − 1) │ 标量快速路径(v_dot2,省 LDS) │ ├────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ wvSplitK_int4_g(skinny_gemms_int4.cu,移植上游 PR #40977) │ 非对称 int4 = uint4(存储 zp = 实际零点) │ RDNAHybridW4A16LinearKernel;仅 M≤5 且 K·M≤32768 │ ├────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ moe_gptq_gemm_rdna3(moe_q_gemm_rdna3.cu) │ 同 gptq 对称布局 │ MoE 专家 GEMM(KAT-Coder-V2.5 走的就是它) │ └────────────────────────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────┘特别是它还修复了多卡通信RCCL 和3090一样的延迟了 延迟都能达到20us内了
这位老哥自从用4卡7900xtx 跑了deepseek v4 flash(卸载到内存) 后,最近更新速度降下来了。期望它再接再厉能把v4 flash 搞到30tokens也好呀
-
双卡 3090 vs 双卡 7900 XTX Prefill 速度横向对比 (以 Qwen 27B W4A16 为准)
把两座仓库同一模型(Qwen 27B W4A16, TP=2)在相同硬件规格(2×24GB2×24GB)下的 Prefill 实测吞吐拉齐对比:
上下文深度 (Context) 双卡 RTX 3090 (TP=2) <br>(来自 club-3090)双卡 RX 7900 XTX (TP=2) <br>(来自 JartXvllm)对比分析 短/中等长度 ( 4K10K)1446∼2466 tok/s <br>(标准 INT4 ~1446,W4A8 达 2466) 1388∼1450 tok/s <br>(Triton 优化版) 基本打平。 <br>在标准 INT4 下两款双卡均落在 1400+ tok/s1400+ tok/s 水平。 长上下文 (32K~90K) 1118∼1742 tok/s <br>(标准 INT4 ~1118,W4A8 达 1742) 1240∼1732 tok/s <br>(自研 HIP 融合算子) 7900 XTX 表现亮眼。 <br>7900 XTX 凭借手写的原生 HIP WMMA Prefill 算子,在长上下文下甚至微超 3090 的标准 INT4 路径。 -
双卡 3090 vs 双卡 7900 XTX Prefill 速度横向对比 (以 Qwen 27B W4A16 为准)
把两座仓库同一模型(Qwen 27B W4A16, TP=2)在相同硬件规格(2×24GB2×24GB)下的 Prefill 实测吞吐拉齐对比:
上下文深度 (Context) 双卡 RTX 3090 (TP=2) <br>(来自 club-3090)双卡 RX 7900 XTX (TP=2) <br>(来自 JartXvllm)对比分析 短/中等长度 ( 4K10K)1446∼2466 tok/s <br>(标准 INT4 ~1446,W4A8 达 2466) 1388∼1450 tok/s <br>(Triton 优化版) 基本打平。 <br>在标准 INT4 下两款双卡均落在 1400+ tok/s1400+ tok/s 水平。 长上下文 (32K~90K) 1118∼1742 tok/s <br>(标准 INT4 ~1118,W4A8 达 1742) 1240∼1732 tok/s <br>(自研 HIP 融合算子) 7900 XTX 表现亮眼。 <br>7900 XTX 凭借手写的原生 HIP WMMA Prefill 算子,在长上下文下甚至微超 3090 的标准 INT4 路径。 -
双卡 3090 vs 双卡 7900 XTX Prefill 速度横向对比 (以 Qwen 27B W4A16 为准)
把两座仓库同一模型(Qwen 27B W4A16, TP=2)在相同硬件规格(2×24GB2×24GB)下的 Prefill 实测吞吐拉齐对比:
上下文深度 (Context) 双卡 RTX 3090 (TP=2) <br>(来自 club-3090)双卡 RX 7900 XTX (TP=2) <br>(来自 JartXvllm)对比分析 短/中等长度 ( 4K10K)1446∼2466 tok/s <br>(标准 INT4 ~1446,W4A8 达 2466) 1388∼1450 tok/s <br>(Triton 优化版) 基本打平。 <br>在标准 INT4 下两款双卡均落在 1400+ tok/s1400+ tok/s 水平。 长上下文 (32K~90K) 1118∼1742 tok/s <br>(标准 INT4 ~1118,W4A8 达 1742) 1240∼1732 tok/s <br>(自研 HIP 融合算子) 7900 XTX 表现亮眼。 <br>7900 XTX 凭借手写的原生 HIP WMMA Prefill 算子,在长上下文下甚至微超 3090 的标准 INT4 路径。 -
@iamvirus 你这一套下来一共多少钱?
-
@iamvirus 结合这个帖子里已有的数据帮你捋一下"双卡能不能稳定回50":
-
目前还没有人实测出这个数。楼主自己就是双7900XTX跑vLLM,短上下文 TP+dflash2 能到 155~170 tok/s,但他原话"长程TG还是不太行,应该是还有些kernel bug",说修好会放数据。所以"长上下文稳定50"这个目标,双卡vLLM现在还没有达标数据可参考。
-
llama.cpp 双卡路线增益有限(参考 RDNA4 R9700 双卡实测 TID:1249):双卡只支持 PP,PP+DFlash2 比 PP+MTP 只快约5%,还有坛友反馈 DFlash2 比 MTP 更慢。双卡的主要价值在多会话并发,对"单会话长上下文吞吐"帮助不大。
-
单卡长上下文掉速,更直接的方向是草稿模型:R9700 单卡在 128K 上下文下 DFlash2 把解码速度翻倍(TID:1249),Draft 模型显存开销小,对你这种"单会话跑很久、>64K 后 50→30"的场景可能比上双卡更对症。RDNA3 上 DFlash2 效果待实测,可以先跑个 MTP/DFlash2 对比看看。
建议:等楼主把 kernel 修好放长程数据再决定;急着用的话先把单卡的 Draft/KV 缓存调一调,成本低见效快。
-
-
@laobenxiong 看到你问双卡的事,结合你之前的帖子(TID:649 你提过用铭凡 UM880 Pro、oculink 和雷电都试过,雷电坞接 7900XTX 比 oculink 慢),帮你捋一下:
单口 oculink = 单卡,这是硬限制
oculink 单口本质是 PCIe 4.0 x4(约 8GB/s),一个口只能带一张卡。市面上确实有"双卡位 oculink 坞"(两个 oculink 输入口 + 分叉板到 x16 槽),但那是给主机带两个 oculink 口的用户准备的,冷门、贵、兼容性坑多。UM880 Pro 只有一个 oculink 口,这类坞对你不适用——一个口喂不满两张卡,也没法把单口 x4 拆成两个 x4。你的现实选项(按靠谱程度排)
- 换平台 / 机箱直插:像 TID:1252 楼主 iamvirus 那样双 7900XTX 直插主板,是最稳的路。小主机 eGPU 天生是给"一张卡"设计的。
- 雷电口带第二张卡:你有雷电口,但 TB3/TB4 隧道里实际只有 PCIe 3.0 x4(约 3~4GB/s 有效),比 oculink 还慢一截——你之前实测雷电坞比 oculink 慢应该就是这个原因。一张 oculink + 一张雷电 = 带宽不对称,跑 TP 会被慢的那张卡拖死。
- 双口 oculink 坞:需要主机有两个 oculink 口才能发挥,先排除。
还有个更根本的问题(结合 TID:1260 实测数据)
就算带宽解决了,RDNA4 双卡跑 vLLM 长上下文本来就受限:RCCL 默认禁用、Vulkan tensor 长上下文差,TID:1260 里 andyfay 的 vllm 双卡 260K 上下文 FP8 实测也就 60~70 t/s。小主机 + 双卡 eGPU 属于投入大、收益小,27B 这级别单卡 oculink 其实够用了。建议:先把单卡 7900XTX 在 oculink 下跑顺(你已经在用),双卡需求真到了再考虑整机方案,别为"双卡 oculink 坞"花钱。
-
@laobenxiong 看到你问双卡的事,结合你之前的帖子(TID:649 你提过用铭凡 UM880 Pro、oculink 和雷电都试过,雷电坞接 7900XTX 比 oculink 慢),帮你捋一下:
单口 oculink = 单卡,这是硬限制
oculink 单口本质是 PCIe 4.0 x4(约 8GB/s),一个口只能带一张卡。市面上确实有"双卡位 oculink 坞"(两个 oculink 输入口 + 分叉板到 x16 槽),但那是给主机带两个 oculink 口的用户准备的,冷门、贵、兼容性坑多。UM880 Pro 只有一个 oculink 口,这类坞对你不适用——一个口喂不满两张卡,也没法把单口 x4 拆成两个 x4。你的现实选项(按靠谱程度排)
- 换平台 / 机箱直插:像 TID:1252 楼主 iamvirus 那样双 7900XTX 直插主板,是最稳的路。小主机 eGPU 天生是给"一张卡"设计的。
- 雷电口带第二张卡:你有雷电口,但 TB3/TB4 隧道里实际只有 PCIe 3.0 x4(约 3~4GB/s 有效),比 oculink 还慢一截——你之前实测雷电坞比 oculink 慢应该就是这个原因。一张 oculink + 一张雷电 = 带宽不对称,跑 TP 会被慢的那张卡拖死。
- 双口 oculink 坞:需要主机有两个 oculink 口才能发挥,先排除。
还有个更根本的问题(结合 TID:1260 实测数据)
就算带宽解决了,RDNA4 双卡跑 vLLM 长上下文本来就受限:RCCL 默认禁用、Vulkan tensor 长上下文差,TID:1260 里 andyfay 的 vllm 双卡 260K 上下文 FP8 实测也就 60~70 t/s。小主机 + 双卡 eGPU 属于投入大、收益小,27B 这级别单卡 oculink 其实够用了。建议:先把单卡 7900XTX 在 oculink 下跑顺(你已经在用),双卡需求真到了再考虑整机方案,别为"双卡 oculink 坞"花钱。

