Skip to content

metal/oracle: scope token-exact claim to decode + implement DEBUG_LOGITS top-5 dump (#622)#624

Merged
JustVugg merged 1 commit into
devfrom
fix/622-metal-prefill-docs-debug-logits
Jul 26, 2026
Merged

metal/oracle: scope token-exact claim to decode + implement DEBUG_LOGITS top-5 dump (#622)#624
JustVugg merged 1 commit into
devfrom
fix/622-metal-prefill-docs-debug-logits

Conversation

@JustVugg

Copy link
Copy Markdown
Owner

Fixes #622 (@lBroth's report).

The bug

Metal prefill GEMM (matmul_qt on GPU, S β‰₯ COLI_METAL_GEMM_MIN, default 16) is not token-exact vs CPU on near-tie logits β€” a teacher-forced prefill on 4-bit toy fixtures disagrees at 2/32 positions, deterministically. Decode is unaffected (S=1; short prompts stay below the GEMM threshold). The GEMM kernel is numerically fine (make metal-test passes at ~3e-6 vs a 1e-4 tolerance); it's a GPU-vs-CPU accumulation-order difference that only flips the argmax when two logits sit inside that drift. COLI_METAL_GEMM_MIN=100000 (all GEMMs on CPU) makes it bit-identical. So the concrete defect is a docs overclaim, not a kernel bug.

Changes

  1. docs/metal.md β€” scope the claim: decode is token-exact; prefill's GPU GEMM can diverge on near-tie logits by accumulation order (not a kernel bug), with COLI_METAL_GEMM_MIN=100000 as the bit-exact escape hatch for teacher-forced comparisons.
  2. Implement DEBUG_LOGITS β€” the oracle mismatch message told users to run TF=1 DEBUG_LOGITS=1 for top-5 logit dump, but the flag didn't exist (a dead string, also flagged in [Bug]: Metal prefill GEMM is not token-exact vs CPU on near-tie logits (S >= GEMM_MIN); decode unaffectedΒ #622). It now works: on a teacher-forcing mismatch it dumps the top-5 logits, the top1–top2 margin, and the expected/got tokens' logits β€” so a near-tie divergence reads as the tiny gap it is. Opt-in, stderr, fires only on a mismatch; normal runs are byte-for-byte unchanged (forward_all gains a nullable ref arg; its one caller is updated).

Verified locally

  • Oracle stays 32/32 with DEBUG_LOGITS=1 on a clean run (no dump β€” fires only on mismatch).
  • A forced mismatch prints, e.g.:
    [LOGITS] pos=5 top1-top2 gap=2.449e-03 | expected=35 (-0.23799)  got=34 (1.73265) | top5: 34:1.73265 197:1.73020 244:1.40506 193:1.36190 226:1.30650
    
    (top1=34, top2=197 are 0.00245 apart β€” exactly the near-tie the report is about).

Note for #457 / #587

This pre-existing prefill drift is the confound in verifying Metal fmt=4 token-exactness on tiny fixtures β€” a mismatch there could be this GEMM, not the new kernel. Run those correctness checks with COLI_METAL_GEMM_MIN=100000 (or on a real container) to isolate the fmt=4 kernel.

Deferred (per the reporter): making the prefill GEMM's accumulation order CPU-stable β€” worth it only if real containers cross the margin often; the top-2 logit-gap instrumentation on #587 will quantify that.

…_LOGITS top-5 dump (#622)

@lBroth reported that Metal prefill GEMM (matmul_qt on GPU, S >= COLI_METAL_GEMM_MIN,
default 16) is not token-exact vs CPU on NEAR-TIE logits: on 4-bit toy fixtures a
teacher-forced prefill disagrees at 2/32 positions, deterministically. Decode is
unaffected (S=1, and short prompts stay below the GEMM threshold). The GEMM kernel is
numerically fine (make metal-test passes at ~3e-6 vs a 1e-4 tolerance); it is a GPU-vs-CPU
accumulation-order difference that only flips the argmax when two logits sit inside that
drift. Confirmed: COLI_METAL_GEMM_MIN=100000 (keep every GEMM on the CPU) makes it
bit-identical. So the concrete defect is a docs overclaim, not a kernel bug.

- docs/metal.md: "Token-exact vs the CPU path" -> decode is token-exact; prefill's GPU
  GEMM can diverge on near-tie logits by accumulation order (not a kernel bug, #622), with
  COLI_METAL_GEMM_MIN=100000 as the bit-exact escape hatch for teacher-forced comparisons.

- Implement DEBUG_LOGITS: the oracle mismatch message pointed at "TF=1 DEBUG_LOGITS=1 for
  top-5 logit dump", but no such flag existed (a dead string, also flagged in #622). It
  now works: on a teacher-forcing mismatch it dumps the top-5 logits, the top1-top2 margin,
  and the expected/got tokens' logits, so a near-tie divergence reads as the tiny gap it is
  instead of a bare token mismatch. Opt-in, stderr, fires only on a mismatch β€” normal runs
  are byte-for-byte unchanged (forward_all gains a nullable ref arg; its one caller updated).

Verified: oracle stays 32/32 with DEBUG_LOGITS=1 on a clean run (no dump); a forced
mismatch prints e.g. "[LOGITS] pos=5 top1-top2 gap=2.449e-03 | expected=35 (-0.23799)
got=34 (1.73265) | top5: 34:1.73265 197:1.73020 ...". Also relevant to #457/#587: verify
Metal fmt=4 token-exactness with COLI_METAL_GEMM_MIN=100000 to isolate the new kernel
from this pre-existing prefill drift.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@JustVugg
JustVugg merged commit 6fcc555 into dev Jul 26, 2026
10 checks passed
@JustVugg
JustVugg deleted the fix/622-metal-prefill-docs-debug-logits branch July 26, 2026 22:44
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.

1 participant