Skip to content

fix(ROCM): AttnQkNormRopeGate output-dtype dispatch -- the 0.8B GDN forward divergence root-caused and fixed (RED anchor turns GREEN) - #570

Closed
VikashLoomba wants to merge 2 commits into
mudler:mainfrom
VikashLoomba:row/ROCM-GDN-08B-FIX
Closed

fix(ROCM): AttnQkNormRopeGate output-dtype dispatch -- the 0.8B GDN forward divergence root-caused and fixed (RED anchor turns GREEN)#570
VikashLoomba wants to merge 2 commits into
mudler:mainfrom
VikashLoomba:row/ROCM-GDN-08B-FIX

Conversation

@VikashLoomba

@VikashLoomba VikashLoomba commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

fix(ROCM): AttnQkNormRopeGate dispatch keyed on the OUTPUT dtype — the 0.8B GDN forward divergence, root-caused and fixed (issue #41)

Restructured after review: this PR now carries ONLY the kernel fix + its teeth + the debug instrumentation, and lands BELOW the 0.8B gate (#559) so every commit is individually green on the gate host.

Root cause

The ROCm dispatcher for the fused full-attention preamble templated the kernel on the source dtype (qgate.dtype) where the CUDA lane (LaunchAttnPreambleOut) switches on the output dtype (q_out.dtype). The 0.8B bf16 model runs bf16 QKV-projection output + f32 q/k/gate outs (the f32-attention path; no FA-2 on ROCm) — silently mis-launched as all-bf16, writing bf16 bits through f32 out pointers.

Evidence chain (gfx1100, GPU-locked)

  1. CPU backend == pinned oracle token-for-token; ROCm diverges at tok0 → ROCm-kernel-specific
  2. Per-layer residual dumps (new VT_DUMP_ACT): layers 0–2 clean (≤9.6e-3 rms-rel), layer 3 (first full-attn) ignites to 2.1e-1
  3. Sub-stage dumps (VT_DUMP_ACT_SUB): block_out 4.4e-1 with post_input_norm clean → inside FullAttnBlockPaged
  4. Op dumps (VT_DUMP_ATTN): fa0_q rms-rel 1.196 with fa0_qkv/fa0_gate clean → the preamble's q/k path
  5. VT_ROCM_ATTN_CPU_REF=1 unchanged → attention core exonerated

Fix + teeth

Dispatch on q_out.dtype; VT_CHECK bf16-out requires bf16-src. The cross-device case gains the bf16-src → f32-out combo at the real 0.8B dims (Hq=8, Hkv=2, Dh=256, rot=64) — mutation-proven: fails with the fix reverted, passes with it.

Gates (gfx1100, flock)

  • test_backend_cross_device 19/19 (346 assertions)
  • test_qwen3_paged_engine 16/16 unchanged
  • e2e The capital of France is Paris.\nThe capital of France is == pinned oracle == our CPU
  • Full HIP ctest zero-delta vs base (box-baseline failures identical)

Also in this PR: three pre-existing hipcc/clang-only build breaks that blocked any full HIP build (same-line double CAPTURE ×2; -Wunused-const-variable on a CUDA-gated constant), and the env-gated dump instrumentation that found the bug (VT_DUMP_ACT/VT_DUMP_ACT_SUB/VT_DUMP_ATTN, off by default, allowlisted).

Current-main integration cutoff (2026-08-18)

Rebased from 053a18a42346e2610a8b56418ebd387c5e74a5c6 to fd836638d7a92bdbd755a7b73b9493f1ff9f6a0d on recorded current-main cutoff 65d6cdaed3e20e9bc70b4f9374fccafefefa7bd0. Exact output-dtype-fix commit replay. Fresh cutoff-head builds, focused gates, full repository preflight, and independent mutation review all pass.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: pi:kimi-k3 [pi]
Assisted-by: codex:gpt-5.6-sol [codex]
Assisted-by: pi:gpt-5.6-sol [pi]

@VikashLoomba

Copy link
Copy Markdown
Contributor Author

Current-main rebase and fresh review

Rebased from c5b0b118 to ab41b731 on current-main pin f22c6cc8 and force-updated with an explicit lease.

@VikashLoomba
VikashLoomba marked this pull request as ready for review August 18, 2026 06:43
…lden lane in the Qwen3-0.6B near-tie gate

Issue mudler#41 M4 milestone. The oracle is upstream vLLM AT THE PIN (555967922,
runtime 0.23.1rc1.dev1511+g555967922 -- verified == the parity-pin block) built
from source as a ROCm wheel for gfx1100 in rocm/vllm-dev:base and committed as
the image vllm-rocm-oracle:555967922-gfx1100 (recipe: .agents/specs/rocm-m4-oracle.md).

Gate result on this box (4x RX 7900 XTX, ROCm 7.14, enforce_eager, batch=1,
flock ~/gpu.lock): oracle K=10 per-prompt greedy deterministic in every cell;
our ROCm engine 16/16 prompts PASS -- 11/16 strict token-exact vs base greedy,
5/16 near-tie band, max teacher-forced gap 0.125 nats, 0 forward-divergent,
125/125 assertions, backend proof all 8 Qwen3-dense ops selections>0 and
declines==0 on device 5. The p0 France/Italy flip is a literal 0.0000-nat tie
in the oracle's own logits (the Metal M3b signature, reproduced on ROCm).

Change shape: the parity gate's Metal/Tenstorrent device-golden lane gains the
kROCM arm (identical anchor+band logic, ROCm's own oracle-backed golden pair);
dgx base goldens byte-untouched; the *_rocm goldens are additive.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: pi:kimi-k3 [pi]
…he 0.8B GDN forward divergence, root-caused and fixed

Issue mudler#41. The ROCm dispatcher for the fused full-attention preamble keyed its
template on the SOURCE dtype (qgate.dtype) instead of the OUTPUT dtype like the
CUDA lane (LaunchAttnPreambleOut switches on q_out.dtype). The 0.8B bf16 model
runs bf16 QKV-projection output + f32 q/k/gate outs (the f32-attention path; no
FA-2 on ROCm), which the src-keyed dispatch mis-launched as all-bf16 -- writing
bf16 bits through the f32 out pointers. Evidence chain (gfx1100, flock):
CPU==pinned-oracle token-exact / ROCm diverges at tok0; VT_DUMP_ACT per-layer
residual dumps: layers 0-2 clean (<=9.6e-3), layer 3 (first full-attn) 2.1e-1;
sub-stage dumps: block_out 4.4e-1 with post_input_norm clean; VT_DUMP_ATTN op
dumps: fa0_q rms-rel 1.196 with qkv/gate clean; VT_ROCM_ATTN_CPU_REF=1 unchanged.

Fix: dispatch on q_out.dtype; bf16-out requires bf16-src (VT_CHECK).

Teeth: the cross-device AttnQkNormRopeGate case gains the bf16-src -> f32-out
combo at the real 0.8B dims (Hq=8, Hkv=2, Dh=256, rot=64); mutation-proven
(fails with the fix reverted, passes with it).

Gates on this branch (gfx1100, flock ~/gpu.lock): test_backend_cross_device
19/19 (346 assertions, incl. the new combo); test_qwen3_paged_engine 16/16
unchanged; e2e 0.8B 'The capital of France is' -> ' Paris.\nThe capital of
France is' == pinned oracle == our CPU. The M4 0.8B gate with the re-derived
GREEN goldens lands in the stacked sibling on row/ROCM-M4-GDN-GATE; full HIP
ctest zero-delta vs base measured there.

Also: three pre-existing hipcc/clang-only build breaks that block ANY full HIP
build on this toolchain: same-line double CAPTURE in
test_qwen3_5_gdn_spec_routing.cpp and test_ops_quant_repack.cpp, and
-Wunused-const-variable on kGdnLayers (uses compile out on HIP). Debug
instrumentation env-gated and off by default (VT_DUMP_ACT / VT_DUMP_ACT_SUB /
VT_DUMP_ATTN; deepseek_v4 VT_DUMP_ACT precedent; env-doc-allowlist updated).

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: pi:kimi-k3 [pi]
@VikashLoomba

Copy link
Copy Markdown
Contributor Author

Final integration cutoff

Final head: fd836638d7a92bdbd755a7b73b9493f1ff9f6a0d, exact replay on cutoff 65d6cdae.

  • Cross-device: 20/20 cases, 352 assertions.
  • Fresh source-dtype mutation RED: Q/K NMSE 1.51127/1.53128 versus 0.0005; restored focused arm 53/53 GREEN.
  • New main Qwen3.5/runner changes remain intact; dispatch still keys on output dtype.
  • Full preflight and independent cutoff review: PASS.

localai-bot pushed a commit that referenced this pull request Aug 18, 2026
… gate (#559)

## M4 for Qwen3.5-0.8B (GDN) — the oracle-backed gate, landed green-shaped (issue #41)

Stacked: #549 (0.6B lane + oracle) ← **the dispatch fix** (#570) ← this gate. The fix lands *below* the gate, so every commit in the stack is individually green on the gate host and the committed goldens are ones the tree can actually reproduce.

### Gate

`test_qwen35_paged_engine.cpp` — the GDN sibling of the Qwen3-dense SACRED gate: standard 16-prompt battery through the full paged engine, hard anchor + ≤0.5-nat near-tie band, backend proof over the 15-op GDN set. Goldens captured from the pinned vLLM-ROCm oracle on this box (K=10 per-prompt, **deterministic in every cell**) with `manifest.json` recording the oracle identity; the checkpoint resolves via `parity::HfSnapshot` at the pinned HF revision `2fc06364` (check-snapshot-pins clean).

**Verdict: 16/16 PASS** (15/16 strict token-exact vs the oracle, 1/16 near-tie band, max gap 0.125 nats, 0 forward-divergent).

### Review-sweep rework (all three findings accepted)

1. **CI-red manifest fixed**: `qwen35_0_8b_greedy` is in `PendingRunnerOps()` (the `qwen36_gguf_greedy` precedent) — the manifest itself stays; its oracle identity is the point.
2. **Fail-safe by device**: the gate exits 77 (CTest Skipped) on any non-ROCm device and when the pinned checkpoint is absent — never a false green, never a foreign engine compared against ROCm-derived goldens.
3. **Green-shaped landing**: the committed goldens are the FIXED engine's oracle-re-derived pair. The pre-fix capture (13/16 forward-divergent; first-token divergences on 6 prompts at 0.375–1.062 nats, 5 of 6 over band) is kept as evidence in the spec + parity ledger, not as goldens no code can pass. The anchor-drift REQUIRE now reads "REGRESSION SUSPECTED — bisect first"; golden re-derivation is the last step of a justified re-capture, not the response to a failure.

### Prose corrections from review

First-divergence maximum is 1.062 nats (not 1.188), 5 of the 6 token-0 divergences are over the band (not all), and the headline gap is at the first over-band position rather than a post-divergence maximum.

## In-flow gate repair

Issue #1222 found three missing-artifact paths that returned normally and let doctest report false success. The gate now routes absent greedy, anchor, and gap artifacts through exit 77. A no-GPU subprocess regression drives the real executable and asserts `77/77/77`; its complete-artifact control requires hard sentinel exit 86 so probe mode can never bypass snapshot/model/device checks as zero-assertion success. Bootstrap writes its token IDs and then exits skipped until correctness artifacts exist. Malformed present arrays remain hard failures.

Fixes #1222.

## Current-main integration cutoff (2026-08-18)

Rebased from `5b31bc30349d527ef0b4c1c8fcd7c86749b4cfa3` to `4673a35dd47087cae3f6f9808e4fcf64667bcbcf` on recorded current-main cutoff `65d6cdaed3e20e9bc70b4f9374fccafefefa7bd0`. Exact six-commit replay of #549#570 → the green 0.8B gate → the three #1222 spec/repair commits. Fresh cutoff-head builds, focused gates, full repository preflight, and independent mutation review all pass.

## Landing note (maintainer)

This branch is the tip of the 0.6B/0.8B ROCm stack and carries six commits: the
#549 M4 oracle and 0.6B gate lane, the #570 `AttnQkNormRopeGate` output-dtype
dispatch fix, the green 0.8B GDN gate, and the three #1222 gate repairs. Landing
it lands that whole stack, so #549 and #570 are closed against this merge rather
than squashed separately. Merging the tip is deliberate: squash-merging a stack
in order rewrites each ancestor's history and destroys the merge base of the
branches above it.

`agent-record` is red on the pull request and the merge result is green. The
branch predates the #1229 gate-commands repair now on `main`, so it ran the
41-test version of `tests/scripts/test_check_gate_commands.py` against its own
tree. The actual merge was constructed locally and gated: 42 tests OK, and
`check-agent-record`, `check-doc-checkpoint`, `check-issue-index-append-only`
and `check-readme-structure` all pass on the merged tree. `windows-msvc-cpu` and
`windows-msvc-vulkan` are red as they are on every pull request here and carry
no verdict. The remaining 17 gates passed.

The ROCm correctness evidence is the contributor's and was not re-run by the
maintainer: it needs the gfx1100 board, which this session did not hold.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: pi:kimi-k3 [pi]
Assisted-by: codex:gpt-5.6-sol [codex]
Assisted-by: pi:gpt-5.6-sol [pi]
@localai-bot

Copy link
Copy Markdown
Collaborator

Landed via #559 as 7b89cf307, not superseded.

#559 is the tip of this stack and carried this branch's commit fd836638d (the AttnQkNormRopeGate output-dtype dispatch fix) verbatim. Verified on main: src/vt/rocm/rocm_gdn_fused.hip dispatches on q_out.dtype rather than the source dtype.

The tip was merged rather than each branch in turn because this repository is squash-only, and squash-merging a stack in order rewrites each ancestor and destroys the merge base of the branches above it. Authorship is preserved on the landed commit.

This one deserves a note: the evidence chain here, CPU backend matching the pinned oracle token-for-token, per-layer residual dumps localising the ignition to layer 3, then sub-stage and op dumps narrowing to fa0_q, then VT_ROCM_ATTN_CPU_REF=1 exonerating the attention core, is the kind of root-cause work that makes a fix reviewable. The bf16-src to f32-out cross-device case is mutation-proven, which is what the protocol asks for and rarely gets.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants