feat(MODEL-MM-QWEN4-EXP): W2 — the hashed n-gram index and the PLE dilated conv, the two components with no vLLM op - #2024
Open
localai-bot wants to merge 4 commits into
Open
feat(MODEL-MM-QWEN4-EXP): W2 — the hashed n-gram index and the PLE dilated conv, the two components with no vLLM op#2024localai-bot wants to merge 4 commits into
localai-bot wants to merge 4 commits into
Conversation
…nv, the two components with no vLLM op (#1987) These are the only two parts of `Qwen4ExpForConditionalGeneration` that no vLLM op reaches, and the negative is confirmed rather than unfound: at vLLM `origin/main` = `6a5e8f5979`, `git grep -in dilat` returns zero lines in `layers/mamba/`, zero in `csrc/` and zero in `tests/`, and `layers/conv.py` defines only `Conv2dLayer` and `Conv3dLayer`. Upstream reached the same conclusion from the other side and hand-rolled it. transformers v5.16.0, this row's accepted lane pin, is therefore the sole oracle. They come first in the wave order because they carry the highest silent-wrongness risk in the port and because nothing downstream can localise an error in them. An n-gram id computed wrong does not crash and does not change a shape; it reads a different row of a 320-million-row table and the model emits plausible text. The spec's `## Gates` admits no token gate for this row until an arm runs, and nothing published fits any fleet device, so these component goldens are the whole instrument. Three divergence sites are silent and all three are now pinned by a test that goes red when the wrong spelling is used. `_splitmix64` is `uint64_t` throughout, because its `>> 30 / 27 / 31` are logical shifts on a non-negative Python int and an `int64_t` port makes them arithmetic — four of the eight probes return a value above 2^63, so it fires on the raw chain before any derived value. `% half_bound` is an unsigned modulo, because the dividend routinely exceeds 2^63 and a signed one yields a negative residue, hence an even and negative multiplier. And the int64 forward needs no bignum only while every token id is below `vocab_size`; upstream cannot be handed one that is not and so has no check, our loader can, and the failure is an overflow that diverges in silence, so `BuildNGramIds` refuses by name. The goldens were produced by executing upstream's own bytes — the named line ranges fetched from the `v5.16.0` tag and exec'd, never transcribed — so each one is an oracle observation. That yielded a fourth independent confirmation of the three published `layer_multipliers` beyond the three in #1987: `vocab_size = 248320`, read from the released `config.json`, is the unique preimage below 2e6 at the absent-`seed` default of 1234. `scripts/gen-qwen4-exp-ple-goldens.py` is that generator, committed beside the others under the same name convention, so the provenance is executable rather than asserted. It fetches the two upstream files at the tag and exec's the line ranges; only the config holder and the cache container around them are local, and they are the smallest thing that makes those ranges run. Re-running it reproduces the committed `.inc` byte for byte. On the PLE side the conv state is nine columns, `(kernel - 1) * dilation` and not `kernel - 1`, and it holds the normed conv input while the skip term added back is the un-normed copy. The signed-sqrt gate clamps before the square root, so the floor on the output magnitude is 1e-3 rather than 1e-6 and tiny scores are amplified; exactly zero still maps to zero, which makes the function discontinuous at an origin a fully masked row reaches. It is mirrored, not tidied. The n-gram history is padded with EOS because `update_conv_state` pads with 0, which is a valid token id. Every entry point is per sequence and takes its own state, so nothing loops over the batch and nothing needs a host round trip inside a decode step. That is deliberate: the gather is 16 uncoalesced random rows per token per sequence, so at batch B it is 16*B independent gathers, and a device arm replaces the loop bodies while keeping these signatures as the single-sequence fallback. W1 (#1981, PR #1986) owns the real config params and is not on `main` at this commit, so this wave declares the minimum surface it needs locally, under W1's helper names so the swap is mechanical. This slice LANDS UNREACHED, per AGENTS.md "Nothing lands dead". No production entry point calls it: `qwen4_exp` has no registry entry, no loader and no `ModelRegistry::Forward` arm until W5 assembles the model. The wiring is owned by row `MODEL-MM-QWEN4-EXP` and tracked by campaign issue #1978, and the spec now lists it under `## Owed` together with the batched device arm, the 128-shard numeric table reassembly, and the prefix-caching decision for a conv state written by a chunked prefill shorter than nine columns. No token claim and no speed claim. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: Claude:claude-opus-5 [Claude Code]
…am mix nothing checked A fresh review of 52d8df7 returned FAIL on one deciding finding and five smaller ones. It re-ran all 14 claimed mutations and added seven of its own, all red, and found three that read GREEN. This repairs every one of them. `eos_token_id` is the one token id in the hash that does not come from `input_ids`, and the range refusal covered `input_ids` only. `PleGeometry` defaults it to -1, `Reset` seeded the history with it unvalidated, and `ShiftRightIgnoreEos` emits it at every segment start, so it reached the `uint64_t` multiply on the first token of every sequence. Both sides were run on the same 12 tokens, reading the ids out of upstream's own `forward` with an invertible embedding: eos = -1 transformers v5.16.0 row 0 [2, 35, 67, 96] ours [8, 30, 67, 96] eos = 1000000 transformers v5.16.0 row 0 [9, 38, 65, 108] ours [9, 38, 81, 83] No exception either side, no shape change, a different row of a 320-million-row table. A negative product is normalised by `torch.remainder`; our `static_cast<uint64_t>` reinterprets the same bits near 2^64 and `%` returns a different residue. `RefuseBadEos` now refuses it by name in both `BuildNGramTableLayout` and `BuildNGramIds`, and the header no longer states the old refusal as the guarantee that makes the int64 forward safe. The `conv_mask` path had no coverage at all: every call site in the gate passed `nullptr`, so replacing the whole masking block with `if (false)` stayed green, and so did masking `gated_value` without `gated_value_normed`. A masked golden is regenerated from upstream — zeros at 3, 4 and 11, the first two interior so the dilation carries them into t = 6, 9 and 12 — and asserted single-shot and incrementally, which also pins the mask through the 9-column state. `kNgramExpectedIds` was the one golden produced by transcribing upstream's block-assembly loop rather than executing it, which is a method the generator and `BuildNGramIds` could fail together. `ngram_ids_for` now fills row i of the embedding with the scalar i and reads the ids straight off `forward`, with an assertion that the inversion holds. Every other golden regenerates byte for byte, so the values were right; the method was not. Also: `short_conv_state_len` cited `:1141-1142`, the `nn.Conv1d(` call, where the definition is at `:1135`; `_is_prime` is `:998-1006`, not `:998-1005`, which cut off its `return True`; `_find_nth_prime_after` starts at `:1009`. The 2.38419e-07 delta is one ULP for the conv and TWO for the forward, and the bounds sit 4x and 42x above it, not 4x for both. `IsPrime`'s parity arm is asserted, so `return false` there no longer passes. The spec's `## Owed` now records what this gate cannot reach: the whole instrument runs at hidden_size 8 with 8-wide norm groups, only the integers are pinned at the released config, and a first real-width numeric comparison is still owed. It must derive a relative bound: W3 measured that an exact-double evaluation of the oracle's own algorithm already exceeds 1e-5 absolute at model width, because torch runs the reduction in fp32. W2 still lands unreached, as recorded: `qwen4_exp` has no registry entry, no loader and no `ModelRegistry::Forward` arm until W5 assembles the model. The wiring is owned by row `MODEL-MM-QWEN4-EXP` and tracked by campaign issue #1978, and the spec lists it under `## Owed`. Refs #1987 FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: Claude:claude-opus-5 [Claude Code]
The branch was one commit behind, which made `check-commit-trailers` and `check-commit-style` SKIP rather than report, so neither had said anything about this tree. The merge is clean: #1999 touches the hybrid KV budget and this row touches only the Qwen4-Exp PLE files. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: Claude:claude-opus-5 [Claude Code]
The branch was 19 commits behind origin/main, so its green CI verdict was measured against a base that has since moved and the diff-scoped trailer gates would SKIP while still exiting zero. Merging restores the ancestry those gates need and puts the operator gate on the tree that will actually land. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [claude-code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The two components of
Qwen4ExpForConditionalGenerationthat have no vLLM op atall: the hashed n-gram index construction, and the PLE layer with its dilated
depthwise causal conv.
git grep -in dilatover vLLM'slayers/mamba/returns zero,and
layers/conv.pydefines onlyConv2dLayerandConv3dLayer, so transformers5.16.0 — this row's accepted lane pin — is the sole source for both. Host
reference; the device arm is owed.
This is integer-exact or it is silently wrong, and there is no downstream gate that
would localise an error here. Three divergence sites are named at the site and each is
mutation-covered:
_splitmix64must beuint64_tthroughout, because its shifts arelogical on a non-negative Python int and become arithmetic on a signed one, with the
top bit set about half the time; its
% half_boundmust be an unsigned modulo,because the dividend routinely exceeds 2^63; and the 128 shards of the released table
must be reassembled in numeric order, since a lexicographic key sort gives
shard_0, shard_1, shard_10, ...and silently permutes a 95 GiB table.The forward itself needs no bignum:
layer_multipliers[i]is a 0-dim int64 tensor, sothe product is int64 arithmetic, bounded below 2^63 because
multiplier_max * vocab_size <= 2^63 - 1. That bound holds only while every tokenid is in range, which is why the port refuses an out-of-range id where upstream does
not need to.
The goldens are quadruply confirmed.
config.seedis absent from the releasedconfig, so the dataclass default 1234 applies, giving
layer_multipliers = [23703573157769, 20109073645365, 8052911324071]. That value wasreached four independent ways: reconstructing the splitmix64 chain; a range read of the
buffer out of the released safetensors; the
qwen4exp.ple.layer_multiplierskey inunsloth/Qwen3.8-Flash-Next-GGUF; and a brute force showingvocab_size = 248320isthe unique preimage below 2e6 at that seed.
The first review FAILED this change, and the finding was a real silent divergence.
eos_token_idbypassed the range refusal that the whole safety argument rests on: itdefaults to -1,
Resetseeds the n-gram history with it unvalidated, and itreaches the
uint64_tmultiply on the FIRST token of every sequence, sinceShiftRightIgnoreEosemits EOS at every segment start. Measured against a runningoracle on the same 12 tokens: at
eos = -1upstream gives row-0 ids[2,35,67,96]andwe gave
[8,30,67,96]; ateos = 1000000,[9,38,65,108]against[9,38,81,83]. Noexception, no shape change, different rows of a 320M-row table. A negative id makes the
product negative in torch, where
torch.remaindernormalises it, while ourstatic_cast<uint64_t>reinterprets the same bits as ~2^64.The repair refuses by name at both entry points. It is a range check and not a blanket
refusal wearing one: three mutations exist purely to prove that — refuse-everything,
and each boundary shifted by one — and all three die on the
CHECK_NOTHROWarm ateos in {0, vocab_size-1}. The re-review went further and confirmed those validboundary values produce ids byte-identical to upstream, which is stronger than the
test asserts.
Three more gate defects the review found, all closed. The
conv_maskpath was entirelyungated — deleting the whole masking block, or masking only one of the two tensors
upstream masks, both passed — and the new golden's mask is adversarial: its zeros sit
at interior positions 3 and 4, which the dilation-3 conv propagates to t = 6, 9 and 12.
The coverage proof is the strongest form available: with the new case present both
mutations are red, and with that one case excluded both go green again.
IsPrime'seven-number arm had no test. And
kNgramExpectedIdswas produced by a transcriptionof upstream's forward rather than by executing it — a transcription cannot gate the
function it transcribes, and the generator and the port transcribed the same upstream
lines, so a shared misreading would have passed. The generator now recovers the ids
from upstream's own executed
forwardthrough an invertible embedding, and theregenerated file differs from the committed one by a single anchor comment: the values
were right, only the method was wrong.
Also corrected: a wrong anchor on the most load-bearing constant in the PLE half
(
short_conv_state_lencited thenn.Conv1d(call, not its definition), and two falsemeasurement claims in a test comment — the forward's
2.38419e-07is two ULP atits argmax magnitude, not one, and its bound sits ~42x above the observation, not ~4x.
## Owedrecords the gap this wave's own gate cannot close: the whole instrument runsat
hidden_size = 8, and only the multipliers, primes and offsets are pinned at thereleased config — those being integers. A first real-width numeric comparison is owed,
and it must derive a relative bound, because the sibling W3 wave measured that an
exact-double evaluation of the oracle's own algorithm already exceeds a 1e-5 absolute
bound at model width, torch running the reduction in fp32.
This slice lands unreached.
qwen4_exphas no registry entry, no loader and noModelRegistry::Forwardarm until W5 assembles the model; the commit body, the spec## Owedand the index row each name that, the owning row and #1978.Tracked by #1987, under #1978.
Gates:
test_qwen4_exp_ple9 cases / 395 assertions (up from 8 / 307);agent-preflight.shrc=0 with zero FAIL and zero SKIP — theorigin/mainmerge wasneeded because
check-commit-trailersandcheck-commit-stylehad been SKIPping, andtherefore reporting nothing, while the branch was behind. A fresh review returned FAIL,
a different implementer repaired it, and a fresh scoped re-review returned PASS with
zero findings, each repair proved by re-running the mutation that used to survive.
FOLLOWING_AGENTS_PROTOCOL
Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-opus-5 [Claude Code]