Skip to content

fix(speculative): Qwen 3.5 MTP output is not byte-identical to classic decode, and the exactness probe does not catch it #1201

Description

@inureyes

Problem

MTP's temperature-0 contract is that speculative output is byte-identical to classic decode. It is not, on qwen3.8-27b-4bit on an M5 Max, even with the #1189 exactness probe passing and #1199's qmv_wide switch engaged.

--temp 0 -n 120 --show-reasoning, main at 0199be00, generated span compared directly:

classic:  ... normalization, and training." Need produce final detailed explanation. Need include architect...
mtp:      ... normalization, and training." Need provide detailed explanation. Need final only. Need likely...
                                                 ^ diverges at char 159 of 630

One token flips ("produce" / "provide") and the continuation is a different generation from there.

What it is not

control result
classic run twice identical
MTP run twice identical
classic with and without MLXCEL_QMV_WIDE=0 identical
MTP with #1199's switch vs qmv_wide forced on identical
MTP at --draft-block-size 2 vs 3 identical

Why the probe misses it

models::speculative_exactness's module docs already say a passing probe is evidence rather than proof, and this is that caveat cashing out. The probe compares one verify block against one single-token chain from one synthetic state, three draws deep. The contract is a claim about a whole generation from the real sequence of states the decode actually visits. The first is passing here; the second is not.

That gap is the real defect. A gate whose green light does not imply the property it gates is worse than one that is merely conservative, because #1199 now ships MTP on generation 15+ on the strength of it.

Suspects not yet examined

Width independence is the strongest clue: the difference survives when the block is as narrow as it can be, so look at what the MTP path does that classic does not do at all rather than what it does per block.

  • The seed prefill (prefill_seed_ms is ~160 ms in the round-loop diagnostics), which runs a target forward classic decode never runs.
  • Cache state after a partial-accept rollback, versus a cache that only ever grew by one.
  • The accept hook's target-hidden read, if it forces an evaluation ordering the classic path does not.

Acceptance criteria

  • The mechanism is identified with evidence, not inferred from where the divergence lands.
  • Either MTP output is byte-identical to classic decode at temperature 0 on this pairing, or the contract is restated to what actually holds and the gate is changed to test that instead.
  • The probe is extended, or paired with an end-to-end check, so a passing gate implies the contract it is named after. A generation-level diff on a small checkpoint is cheap and would have caught this.
  • Checked on Gemma 4 MTP as well as Qwen 3.5, and on an M1 Ultra, so the answer is not scoped to one family on one generation.

Refs #1189, #1186, #1199

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:coremlxcel-core: MLX FFI, primitives, KV cache, layersarea:inferenceGeneration, sampling, decoding (incl. speculative, DRY)platform:macosmacOS (Apple Silicon) specificpriority:highHigh prioritystatus:readyReady to be worked ontype:bugBug fixes, error corrections, or issue resolutions

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions