Skip to content

test(mlx): guard MLX #3912 — fp_qmm_t misreads past K when K mod 32 == 16 - #315

Merged
glennneuber merged 1 commit into
mainfrom
test/fp-qmm-t-kmod32-guard
Sep 18, 2026
Merged

glennneuber merged 1 commit into
mainfrom
test/fp-qmm-t-kmod32-guard

Conversation

@glennneuber

Copy link
Copy Markdown

A 40-line, 0.3-second, model-free guard against the root cause found for the vision regression tracked in #310 / #312.

The bug

Upstream MLX ollama#3912 fixed a Metal kernel bug in fp_qmm_t that reads past the K dimension when K mod 32 == 16. Our v0.34.1 fold crossed that fix when the MLX pin moved ce916dbb → d9add9d1.

K=4304 is the vision tower's mlp.down_proj contraction dimension in the gemma4 26b/31b nvfp4 checkpoints — packed [1152, 538] at 8 values per word, cross-checked by the group-16 scale tensor at [1152, 269]. 12b carries no nvfp4 vision down_proj at all (its text ones are K = 15360 and 65536, both mod 32 == 0), which is why it was structurally immune and made such a good control.

Verified in both directions

A regression test that only passes proves nothing, so this was run against both libraries:

MLX K=4288 (control) K=4304 (trigger)
ce916dbb pre-fix max 0.000152588, 0/294912 max 24.0494, 232722/294912 FAIL
d9add9d1 post-fix max 0.000152588, 0/294912 max 0.137939, 0/294912 PASS

The control is bit-identical across both libraries, so a failure there means something other than this bug. The failure message names ollama#3912 and prints the loaded MLX pin.

Two warnings in the comment block, both earned

The production symptom was almost invisible. Not a crash, not an obviously wrong answer — one fine-text OCR tier moving 4 → 3, on one model, in one think mode. 79% of that matmul's outputs were wrong by more than 1.0 and the model still produced coherent text. Localising it from that symptom took a day of bisecting.

M must exceed get_qmv_batch_limit (quantized.cpp:1804), which is 13 for this K and N. A first attempt at M=8 dispatched to the matrix-vector kernel, never reached fp_qmm_t, came back clean on the buggy library, and read as a refutation of a correct diagnosis. If this test is ever "simplified" by shrinking M, it stops testing anything — so the comment says so explicitly.

Scope

Test only. gofmt applied, go vet clean, passes on current main.

🤖 Generated with Claude Code

…d 32 == 16

Upstream MLX ollama#3912 fixed a Metal kernel bug in fp_qmm_t that reads past the
K dimension when K mod 32 == 16. Our v0.34.1 fold crossed that fix when the
MLX pin moved ce916dbb -> d9add9d1, which is why gemma4 26b/31b vision
embeddings changed across #302 while 12b did not.

K=4304 is the vision tower's mlp.down_proj contraction dimension in the
gemma4 26b/31b nvfp4 checkpoints: stored packed as [1152, 538] at 8 values
per word, cross-checked by the group-16 scale tensor at [1152, 269]. 12b
carries no nvfp4 vision down_proj at all — its text ones are K = 15360 and
65536, both mod 32 == 0 — so it was structurally immune. K=4288 is the
nearest aligned K and is the control.

Verified in both directions rather than only passing:

  MLX ce916dbb (pre-fix)  K=4288  max 0.000152588   0/294912 over 1.0
                          K=4304  max 24.0494       232722/294912  -> FAIL
  MLX d9add9d1 (post-fix) K=4288  max 0.000152588   0/294912
                          K=4304  max 0.137939      0/294912       -> PASS

Two things the comment block records because they are what made this
expensive to find. First, the production symptom was not a crash or an
obviously wrong answer: one fine-text OCR tier moved from 4 to 3 on one
model in one think mode, and localising it from there took a day. Second, M
must exceed get_qmv_batch_limit (13 for this K and N) or the dispatch goes
to the matrix-vector kernel and fp_qmm_t is never reached — a first attempt
at M=8 came back clean on the buggy library and read as a refutation of a
correct diagnosis. Shrinking M silently voids this test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
glennneuber added a commit that referenced this pull request Sep 18, 2026
Root cause found by reading MLX's own upstream PR history, which this
investigation never did: ollama#3912 fixed a Metal kernel bug in fp_qmm_t that
reads past the K dimension when K mod 32 == 16. The v0.34.1 fold crossed
that fix when the MLX pin moved ce916dbb -> d9add9d1.

K = 4304 is the gemma4 26b/31b vision tower's mlp.down_proj contraction
dimension, stored packed [1152, 538] at 8 values per word and cross-checked
by the group-16 scale tensor at [1152, 269]. 12b carries no nvfp4 vision
down_proj at all, so it was structurally immune rather than a lucky control.

Confirmed at kernel level (guard test in #315): on ce916dbb, K=4304 puts
232722 of 294912 output elements more than 1.0 away from dequantize+matmul,
max error 24.05; on d9add9d1 it is zero and 0.138. The K=4288 control is
bit-identical across both libraries.

This inverts the document. The tier drop is a downstream consequence of
CORRECTING a kernel, not a defect to undo: the 9px score of 4 was measured
on a build corrupting most of that matmul, and 3 is what the correct kernel
produces. It also resolves what the document carried as an unexplained
paradox — a more faithful encoder scoring worse — which is exactly what a
correctness fix looks like from a probe that happened to favour the broken
output.

Prior gemma4 26b/31b vision baselines were measured through that kernel and
should be re-measured rather than compared against.

Renamed: the file is no longer about an open regression.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@glennneuber
glennneuber merged commit 2bea4b5 into main Sep 18, 2026
13 of 14 checks passed
@glennneuber
glennneuber deleted the test/fp-qmm-t-kmod32-guard branch September 18, 2026 11:45
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