Skip to content

feat(MODEL-MM-QWEN4-EXP): W3 — the 4-branch gated-residual hyper-connection stream and its grouped RMSNorm - #2045

Merged
localai-bot merged 8 commits into
mainfrom
row/MODEL-MM-QWEN4-EXP-W3
Aug 27, 2026
Merged

feat(MODEL-MM-QWEN4-EXP): W3 — the 4-branch gated-residual hyper-connection stream and its grouped RMSNorm#2045
localai-bot merged 8 commits into
mainfrom
row/MODEL-MM-QWEN4-EXP-W3

Conversation

@localai-bot

@localai-bot localai-bot commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

feat(MODEL-MM-QWEN4-EXP): W3 — the 4-branch gated-residual hyper-connection stream and its grouped RMSNorm

Qwen4Exp does not carry a residual of hidden_size. It carries hc_count * hidden_size = 4 x 2560 = 10240 through the entire stack, with a low-rank read
gate and a per-branch scalar write gate around both attention and the MLP. That
is a change to the per-layer loop and to every residual buffer, not a drop-in
module, which is why it is its own wave.

This lands the stream and its grouped RMSNorm against a running transformers
5.16.0 oracle, with goldens that regenerate byte-identical from the pinned
oracle under both python3 and python3 -O.

Nothing is reachable yet. No ModelRegistry entry resolves
Qwen4ExpForConditionalGeneration, so this slice is unreached by design; the
wiring is owned by W5 (#2031)
and is listed under ## Owed in the row spec.

The GGUF fold guidance is anchored at the pinned oracle

The header passage that tells a W5 loader author how the +1 norm fold works is
anchored to stock upstream llama.cpp at tag b10451
(10bf611e533d81f739128304991c5e133c6aebd8), read from git archive b10451
because the working checkout is dirty and the tag object is the only honest
source. git grep -il qwen4exp returns nothing tree-wide at that tag, so a
released llama.cpp can neither convert nor load this architecture.

The +1 rule and its linear_attn.norm.weight exception are at
conversion/qwen.py:387-388; _LinearAttentionVReorderBase is :438;
Qwen3NextModel is :365. PR ggml-org/llama.cpp#27742 is still OPEN and
unmerged at head 035e22731a7fd70b9854b3a2d64ec68e9b1a45d3, and its
modify_tensors carries no hc_norm branch, so hc_norm.weight falls through
to super() and the fold covers attn_q_norm, attn_k_norm and the
PLE/indexer gammas while sparing ssm_norm. Skip the fold for hc_norm alone
and every other norm is double-folded.

An earlier revision of this branch attributed that rule to llama.cpp "mainline"
at conversion/qwen.py:302-303, read at 237ad9b96. That commit is not
mainline: it is reachable only from a local branch in the developer's checkout,
has no merge base with ggml-org/llama.cpp, and .agents/oracles/llama-cpp.md
records it as the retired contaminated pin. The anchors were wrong at every
ggml-org revision too, so an author following the passage would have landed on
unrelated code in a tree they cannot fetch. Fresh review caught it; the
assertions all survived re-verification at b10451 and were re-anchored rather
than rewritten.

Two defects the repair found on its own

tests/support/max_abs_diff.h narrowed both operands to float, so a
std::vector<double> compared against an fp32 golden lost any difference
smaller than fp32 resolution. Proven red-first with a 2^-30 difference that
exists in double and vanishes in float: CHECK( 0 == 9.31323e-10 ). 7 cases /
33 assertions -> 9 cases / 47 assertions.

scripts/gen-qwen4-exp-hc-goldens.py:97 guarded the oracle's aliasing contract
with a bare assert, which python3 -O deletes. With the oracle corrupted and
the sha guard retargeted so it could not fire first, the old form exits rc=0
and writes a corrupted golden
under -O; the new raise SystemExit exits 1
and writes nothing under both interpreters.

Evidence

  • test_qwen4_exp_hc: 14 cases / 230 assertions, SUCCESS
  • goldens regenerate byte-identical from the pinned oracle (sha 77fec77d...c459)
  • scripts/agent-preflight.sh: rc=0, all gates green, zero FAIL and zero SKIP;
    commit-trailers and commit-style both RAN against origin/main

Closes #1988

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]

mudler added 8 commits August 26, 2026 16:57
…PED norm and writes a rank-1 update (#1988)

Qwen4-Exp carries its residual as `hc_count * hidden_size` = 4 x 2560 = 10240
floats through all 48 layers, reads and rewrites it twice per layer, and
collapses it at the end with the same class that gates it. This wave lands the
host reference for that class and for the grouped RMSNorm underneath it.

It is written against two oracles because the row has two, by developer
direction: transformers v5.16.0 supplies the algorithm (vLLM has never
registered `qwen4_exp` at any revision), vLLM supplies the op form. The grouped
norm therefore mirrors `RMSNormGated(group_size=)` — not the plain `RMSNorm`,
whose only related knob is `var_hidden_size` and which has no group concept at
all — while its semantics come from `Qwen4ExpTextRMSNorm`.

The reason this needs a gate rather than a careful reading is that four of its
guarantees are one-character defects with no visible symptom:

* The `1 + w` parameterization. transformers scales by `(1.0 + weight)` on a
  ZERO-init weight; vLLM scales by `weight` on a ONES-init one. They agree only
  under a load-time `w = 1.0 + w_hf`. Skip it and every `hc_norm` scales by
  ~zero, which reads as a broken checkpoint rather than a broken port; apply it
  twice and it scales by ~2x. It now lives in exactly one named function,
  `HcNormWeightFromHf`, so the question "has the 1 already been added?" is about
  one call site instead of about arithmetic inside a kernel.
* The division by `hc_count` inside the SiLU sits BEFORE the activation.
  `silu(x/4)` is not `silu(x)/4`, and on this data the two answers differ by as
  little as 6.6e-3 — under a percent, and invisible to a loose comparison.
* There is no such division on the up-projection sigmoid, and the reduce over
  the four streams is a MEAN and not a sum.
* The elementwise multiply uses the NORMED stream while the write-back adds to
  the RAW one, so the two ends of the same function disagree about which copy
  they hold on purpose.

The goldens are not derived, hand-computed, or transcribed. `Qwen4ExpTextRMSNorm`
and `Qwen4ExpTextGatedResidual` are lifted verbatim by line range out of the
lane-pinned oracle file, its sha256 re-checked at dump time, and EXECUTED; the
generator is committed and reproduces the .inc byte for byte. A second,
independent double-precision reference then reproduces the same numbers, and a
flag-per-defect sweep proves each of the five traps opens a gap the goldens can
actually see — measured, tabulated in the test, and floored at 6.6x under the
smallest of them.

The write-back is deliberately an in-place rank-1 update rather than the
broadcast-and-multiply upstream spells. That shape is the fusion seam: both
llama.cpp implementations of this architecture materialise it as `repeat_4d` +
`mul`, which is 96 dense [2560, 4, T] tensors built and discarded per forward
pass at 48 layers x 2 sites. Keeping the pointer form as the primitive means a
device kernel replaces this one function and nothing above it moves. No speed is
claimed here; no arm of this model runs on any device we own.

The spec's claim that DeepSeek-V4's `MhcPost` is a bit-exact bring-up bridge for
this write-back under an identity comb matrix is verified rather than repeated,
by a bit-equality case against that kernel. It holds; it costs hc-squared work
where hc suffices, and it is not an identity for a negative-zero or non-finite
residual, neither of which this path reaches.

NOT REACHED at this commit, per AGENTS.md "Nothing lands dead": W1 config
registration (#1986) is still in review, so no `qwen4_exp` resolves through the
loader and nothing production-side calls this yet. The wiring is owed by W5,
assembly, under #1978, and the debt is recorded under the spec's `## Owed`
together with the model-matrix cell that W1 owns.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-opus-5 [Claude Code]
…eted refusals, or the model's own width (#1988)

Fresh review of a5bd413 returned FAIL with eight findings, and its own summary
is the shape of this change: "the port itself is the strongest part of this
change and I could not break it ... Every finding is about the GATE, not the
arithmetic." `qwen4_exp_hc.cpp` is byte-for-byte unchanged here and the header
change is comments only. What changes is what the suite can detect.

Issue #449, re-opened locally. `test_qwen4_exp_hc.cpp` defined two local
max|diff| helpers spelled `worst = std::max(worst, std::abs(...))` — verbatim
the NaN-blind "form B" that `tests/support/max_abs_diff.h` exists to prevent,
in a file that already included that header. Reproduced before repairing:
poisoning `GroupedRmsNorm`'s large-eps path to all-NaN left
`CHECK(MaxAbsDV(big_eps, ...) < kTol)` GREEN, and the suite only went red
because the sibling assertion one line up happened to use the hardened helper.
The fix is not a third local copy. `MaxAbsDiffScan` and `MaxAbsDiff` are now
templated on both operand types, so an fp32-result-against-double-reference
comparison — the shape every "second independent reference" case takes — routes
through the same hardened scan instead of being written again by hand. The same
mutation now reddens the assertion itself.

Eight of eleven refusals had no assertion at all. Each was deleted in turn and
the suite stayed 280/280 green each time, including all three `RequireSize`
calls in `GatedResidualWriteBack` — which, since `GatedResidualWriteBackInPlace`
takes raw pointers and the header declares it the seam a device kernel replaces,
are the only bounds check between a caller and an out-of-bounds read. That class
of guard does not fail tidily: deleting the divisibility guard produces `Fatal
glibc error: malloc.c:2599` and `Aborted (core dumped)` with no doctest summary
at all, and deleting the `group_size` guard is `x.size() % 0` and SIGFPE. All
eight are now message-pinned with `CHECK_THROWS_WITH_AS`, because every guard in
the translation unit throws `std::invalid_argument` and a type-only assertion
cannot tell a deleted guard from a different one firing further down.

`kTol = 1e-5` was a property of the toy shapes and nothing else, and this is the
part the review ranked MEDIUM that deserved the most work. At flat = 24 and 15
the implementation is bit-identical to the oracle — 2.384e-07 over every golden
array — so the tolerance was unconstrained there. Measured against the pinned
oracle at the model's own shape (hidden 2560, hc 4, lowrank 320), max|diff| on
`mixed_input` is 2.325e-05 and 2.137e-05 over two tokens, 2.1x to 2.3x over.
The reflex is to widen kTol, which AGENTS.md forbids and which would be wrong
anyway. The measurement that settles it is the second row of the table now in
the file: an EXACT double evaluation of the same algorithm is itself 1.360e-05
from the oracle, because torch runs this in fp32 too. No fp32 implementation
meets a 1e-5 absolute bound at hidden_size 2560, and widening our own
accumulator cannot rescue one — so the arithmetic is not the thing that is
wrong at that width, the absolute tolerance is. kTol is unchanged and is now
documented as scale-bound; a real-width case carries a RELATIVE bound derived as
6.6x the sqrt(K)*u random-walk bound for a sequential fp32 dot of K = 10240, and
all three measurements sit inside it. Agreement with the oracle at model width
needs a real checkpoint and is recorded as owed rather than claimed.

The `double` accumulator was documented and ungated: `double ss` to `float ss`
left 280/280 green, so the gate could not distinguish the convention from its
opposite. It is kept, because it makes the host reference more accurate than the
oracle rather than less, and it is now gated at the model's real group size of
2560 on magnitude-separated data, where the two differ by 742x (3.168430e-06
against 2.352230e-03, bound 1e-4, identical at -O0 and -O2). The consequence for
the device wave is stated in the spec rather than left to be discovered: a
straight fp32-accumulate device reduction will not meet that bound on that data,
and that is the signal, not a defect in the gate.

The GGUF fold claim was true and under-scoped in the way that causes the defect
it warns about. Read at source rather than relayed: llama.cpp mainline has no
`qwen4exp` at all, the converter is the still-open ggml-org/llama.cpp#27742 at
035e22731a7fd70b9854b3a2d64ec68e9b1a45d3, and it adds no `hc_norm` branch — the
`+1` comes from the inherited `Qwen3NextModel` rule at `conversion/qwen.py`
:302-303, `endswith("norm.weight") and not endswith("linear_attn.norm.weight")`.
So the fold covers `hc_norm`, `attn_q_norm`, `attn_k_norm` and the PLE and
indexer gammas, and excludes `ssm_norm`. A W5 loader author reading the old
sentence would have skipped the fold for `hc_norm` and double-folded everything
else. The header and the spec now state the rule, its exception, the PR and its
head SHA, and that it is unmerged and may change.

Three smaller ones. "Bit for bit" was asserted with `==`, which cannot see the
negative-zero divergence the comment beside it names; both sites now compare bit
patterns, and a case pins the helper's polarity. The in-place-versus-allocating
check was a tautology — the wrapper calls the primitive — proven by mutating the
primitive and watching that line stay green while three others reddened; the
seam is now gated against the oracle directly. `Variant::norm_weight_plus_one`
was declared and read but never once set false, so the struct advertised
coverage the file did not have; it is now flipped in the sweep.

And the goldens generator pinned its oracle with a bare `assert`, which
`python3 -O` strips. Verified both ways: under `-O` the old script happily dumped
goldens from a corrupted source file at rc=0, the new one exits 1. The generator
still reproduces the committed `.inc` byte for byte.

`.agents/issue-index.md` is append-only, so the under-scoped fold sentence in the
#1988 row stays where it is; the header and the spec are the surfaces a loader
author reads and both are corrected there.

Still NOT REACHED at this commit, unchanged from a5bd413: the wiring is owed by
W5, assembly, under #1978, and is recorded under the spec's `## Owed`.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-opus-5 [Claude Code]
…nned llama.cpp, not a repudiated local commit

CORRECTION TO 09ce43f. That commit, its header passage and the spec all
attributed the Qwen3-Next `+1` fold rule to llama.cpp "mainline at
`conversion/qwen.py:302-303`", read at `237ad9b96`. `237ad9b96` is not mainline.
It is reachable only from the local branch `localai-paged` in the developer's
llama.cpp checkout, it has no merge base with `ggml-org/llama.cpp`
`origin/master`, and `.agents/oracles/llama-cpp.md` already records it as the
retired, contaminated pin: 65 of this project's own performance commits past
upstream tag `b9827`, built from a working tree carrying 27 uncommitted entries.
The live pin is stock upstream tag `b10451`,
`10bf611e533d81f739128304991c5e133c6aebd8`. The three line anchors were wrong at
every ggml-org revision as well, so a W5 loader author following that passage
would have landed on unrelated code in a tree they cannot fetch.

Everything the passage asserts remains TRUE, and it is re-anchored rather than
rewritten. Read from `git archive b10451` (the working checkout is dirty, so the
tag object is the only honest source): `git grep -il qwen4exp` still returns
nothing tree-wide, so a released llama.cpp can neither convert nor load this
architecture. The `+1` rule and its `linear_attn.norm.weight` exception are at
`conversion/qwen.py:387-388`; `_LinearAttentionVReorderBase` is `:438`;
`Qwen3NextModel` is `:365`, and its signature is now
`class Qwen3NextModel(_QwenMtpMixin, Qwen2MoeModel)`, which the old quotation had
stale. PR ggml-org/llama.cpp#27742 is still OPEN and unmerged at head
`035e22731a7fd70b9854b3a2d64ec68e9b1a45d3` (`refs/pull/27742/head` and a live
`/merge` ref; the head is not an ancestor of `origin/master`), and its
`modify_tensors` still carries no `hc_norm` branch, so `hc_norm.weight` falls
through to `super()` and the fold covers `attn_q_norm`, `attn_k_norm` and the
PLE/indexer gammas while sparing `ssm_norm`. That is the whole point of the
passage: skip the fold for `hc_norm` alone and every other norm is double-folded.
The word "mainline" is gone, and `237ad9b96` is cited nowhere in it.

Three smaller repairs ride along.

The claim that "the ORACLE is itself 1.36x over kTol" was one draw of random
inputs stated as a general fact; an independent draw gives 0.91x and 0.82x. Both
the test comment and the spec now say the oracle sits of the same ORDER as kTol,
name both draws, and label the measurement table as one draw. The conclusion is
unchanged and holds on either draw: no fp32 implementation of this function meets
a 1e-5 ABSOLUTE bound at hidden_size 2560, because torch runs the reduction in
fp32 too, so widening our own accumulator cannot rescue it.

`scripts/gen-qwen4-exp-hc-goldens.py` still guarded "upstream must return
hyper_input RAW" with a bare `assert`, one line away from the sha256 pin guard
fixed for exactly this reason. `python3 -O` strips it. Proven rather than argued:
with the oracle corrupted to return `hyper_input * 2` and the sha guard retargeted
in a scratch copy so it could not fire first, the old script under `python3 -O`
exited 0 and wrote a golden file that differs from the committed `.inc`. It is a
`raise SystemExit` now, and the same experiment exits 1 with no output file under
both `python3` and `python3 -O`.

`tests/support/test_max_abs_diff.cpp` exercised only `float`/`float`, so the
double-sided instantiation of the helper was covered only by its one caller. Two
cases now compare a `std::vector<double>` reference against an fp32 golden through
both the scan and both wrapper overloads, using a difference of 2^-30 that exists
in double and vanishes in float. Narrowing the operands to float inside the scan
reddens those cases and nothing else; the pre-widening header refuses to compile
them at all.

`qwen4_exp_hc.cpp` is untouched, the goldens reproduce byte-for-byte from the
pinned oracle under both `python3` and `python3 -O`, and `test_qwen4_exp_hc` is
unmoved at 14 cases / 230 assertions.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-opus-5 [Claude Code]
The branch was ten commits behind `origin/main`, and `scripts/agent-preflight.sh`
answers that state by SKIPPING `commit-trailers` and `commit-style` rather than
running them, so a preflight read by exit code alone would have called this
branch green while neither gate had said anything about it. Merged so both gates
actually run before the push. The merge is clean and touches no file this row
changed.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-opus-5 [Claude Code]
`origin/main` advanced again between the first merge and the rerun of
`scripts/agent-preflight.sh`, which fetches for itself, so the trailer gates
SKIPPED a second time on the same "branch is behind" reason. Merged again so
`commit-trailers` and `commit-style` run against a HEAD that has `origin/main`
as an ancestor. Clean merge, no file this row changed is touched.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude:claude-opus-5 [Claude Code]
The fresh scoped re-review measured this branch 3 commits behind origin/main
again. That matters beyond tidiness: check-commit-style refuses a range whose
base is not an ancestor of its head, and diff-scoped gates SKIP silently under a
moved base while still exiting zero, so the branch's own preflight evidence was
taken against a base that no longer exists.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
The remote head had gone stale enough that GitHub refused the squash with "the
merge commit cannot be cleanly created", while the same three-way merge resolves
cleanly in git. The overlap with main is three additive registration files —
.agents/issue-index.md, CMakeLists.txt and tests/CMakeLists.txt — which is
exactly the shape that automerges into something that does not build, so the
merged tree was configured and built rather than assumed: cmake configure rc=0,
`test_max_abs_diff` 47/47 and `test_qwen4_exp_hc` 230/230, both SUCCESS.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
…oth)

W4 landed as 3104a52 and W2 as 583b9a9, so this branch conflicted with its
own siblings in two places. Both resolutions are take-both, and both are the
shape that automerges into something that does not build, so the result was
configured rather than assumed.

`tests/CMakeLists.txt`: W3 and W4 each appended a test registration at the same
point. Both blocks are kept, W4's first because it is already on main. The two
targets are independent — `test_qwen4_exp_qsa` and `test_qwen4_exp_hc`, each
with its own model-private src/ grant.

`.agents/specs/qwen4-exp-flash-next.md`: both sides append `## Owed` bullets,
W4's four and W3's four. All eight are kept. They document different unreached
slices and neither supersedes the other.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
@localai-bot
localai-bot merged commit fcdf2fa into main Aug 27, 2026
7 of 20 checks passed
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.

MODEL-MM-QWEN4-EXP W3: the 4-branch gated-residual hyper-connection stream and its grouped RMSNorm

2 participants