mudler / mudler/vllm.cpp

ROCm gfx1200: Qwen3-0.6B produces wrong greedy output despite all-native execution

Open
#269 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
423
Forks
53
Avg merge
20h 26m
Merged PRs (30d)
310

Description

Row: BACKEND-ROCM

ROCm gfx1200 (RX 9060 XT): Qwen3-0.6B produces wrong greedy output despite all-native execution — embedding gather cleared

Board: AMD Radeon RX 9060 XT, gfx1200 (Navi 44, RDNA4, discrete). ROCm
7.2.3, hipClang/Clang 22.0.0. M0/M1 independently verified on this board (see
my earlier comment).

Repro:

./build-hip/examples/vllm-cli --model <Qwen3-0.6B, bf16 safetensors> \
  --prompt 'The capital of france is' --max-tokens 8 --temperature 0
  • CPU (--device cpu): Paris. The capital of the United States — correct.
  • ROCm (default auto, picks kROCM): 1000000 — garbage.

No crash, no missing-kernel throw, no reference-tier fallback (discrete board,
none available). VT_OP_PROVIDER_STATS=1 shows every exercised op resolving
selected=vt-native: kEmbedding, kRopeCosSinCache, kCastBf16, kRmsNorm,
kMatmulBT, kQkvSplit, kRopeFromCache, kReshapeAndCache,
kPagedAttention, kSiluAndMul, kGreedyArgmax. All of these have
cross-device coverage in test_backend_cross_device.cpp and pass there against
synthetic data — so this is either a real-shape/real-value edge case none of
that synthetic coverage hits, or a bug outside the op kernels themselves.

Isolated to one token. Capitalizing the prompt ('...of France is') gets
the correct answer ( Paris. The capital of Italy is Rome). Both prompts
tokenize to 5 tokens, identical except position 3: 47587 ("france") vs
9625 ("France"). Same shape, same op sequence — one input token id differs
and the output goes from coherent to garbage.

Ruled out:

  • The is_cuda()-vs-is_cpu() host-pointer-aliasing defect at
    dense_attn_block.h:181 — already fixed generically, confirmed correct for
    kROCM in current source.
  • The embedding gather itself. Pulled model.embed_tokens.weight directly
    from the safetensors file and ran vt::Embedding on CPU and ROCm at the
    real row indices 47587 and 9625 (not a repacked small table — same offset
    arithmetic as production). Both rows are bit-exact against the CPU
    oracle. The table bytes and the gather kernel are correct for this row; the
    bug is downstream, in the per-layer forward.

Not yet root-caused. Candidates: kRmsNorm (cross-lane reduction),
merged-QKV kMatmulBT (hipBLASLt GEMM), RoPE, kPagedAttention (hand-written,
least test coverage), or kGreedyArgmax (its ROCm ArgmaxK NaN handling looks
suspect by inspection — a NaN never satisfies v > best, so a fully-NaN row
would leave arg at a sentinel 0x7fffffff rather than behaving like the CPU
path; unconfirmed as the cause here, but cheap to check first since it's the
last op before the wrong token is picked).

Full writeup, evidence, and next steps: .agents/specs/rocm-gfx1200-m2-correctness.md
(this PR/branch — will link once posted).

Distinct from #201 and #132 — neither reproduced on this board/toolchain.
Does not touch the in-flight Qwen3.5 GDN kernel work (disjoint op set, disjoint
board).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with .agents/specs/rocm-gfx1200-m2-correctness.md and reproduce the vllm-cli command on the reported ROCm gfx1200 setup. Trace the listed operations, beginning with ROCm ArgmaxK and then the per-layer candidates, using test_backend_cross_device.cpp and dense_attn_block.h:181 as context. Done means identifying the downstream cause and restoring the expected greedy output for both prompt variants.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend, machine-learning
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.