Skip to content

fix(qwen3.5-moe): stack per-expert gate_proj/up_proj/down_proj weight names#587

Merged
inureyes merged 2 commits into
mainfrom
fix/issue-519-qwen35-moe-expert-name-variants
Jul 1, 2026
Merged

fix(qwen3.5-moe): stack per-expert gate_proj/up_proj/down_proj weight names#587
inureyes merged 2 commits into
mainfrom
fix/issue-519-qwen35-moe-expert-name-variants

Conversation

@inureyes

@inureyes inureyes commented Jul 1, 2026

Copy link
Copy Markdown
Member

Summary

Fixes a weight loading failure for Qwen3.5-MoE checkpoints that store per-expert tensors under gate_proj/up_proj/down_proj names instead of w1/w2/w3. The previous code only handled the w1/w2/w3 naming, leaving those checkpoints with Missing weight: model.layers.N.mlp.switch_mlp.w1.

What changed

  • src/models/qwen3_5.rs (sanitize_weights step 6): added a second inner pass that stacks experts.{e}.gate_proj/up_proj/down_proj into switch_mlp.w1/w3/w2 (gate->w1, up->w3, down->w2), matching the fused gate_up_proj path naming. The pass skips any slot already filled by the w1/w2/w3 pass to prevent clobbering. Quantized .scales and .biases receive the same rename.
  • Three unit tests in a new sanitize_tests module: plain float stacking, stacking with quantized scales/biases, and the priority guard.

Test plan

  • cargo test --lib models::qwen3_5::sanitize_tests -- 3 tests pass
  • cargo check --lib --tests -- clean
  • cargo clippy --lib --tests -- -D warnings -- no warnings

Closes #519

… names

In sanitize_weights step 6, also match experts.{e}.{gate_proj,up_proj,down_proj}.weight and stack them into switch_mlp.{w1,w3,w2} (gate->w1, up->w3, down->w2), mirroring the fused gate_up_proj path's naming convention.

The existing path only handled experts.{e}.{w1,w2,w3}.weight, so checkpoints shipping per-expert tensors under the gate_proj/up_proj/down_proj names failed with 'Missing weight: model.layers.N.mlp.switch_mlp.w1'.

The gate_proj pass skips any slot already filled by the w1/w2/w3 pass, preventing accidental clobber when both conventions appear in the same checkpoint. Quantized scales and biases are forwarded with the same slot rename.

Three unit tests cover: plain float stacking, stacking with quantized scales/biases, and the priority guard against clobbering w1/w2/w3 slots.
@inureyes inureyes added the status:review Under review label Jul 1, 2026
@inureyes inureyes merged commit c494840 into main Jul 1, 2026
5 checks passed
@inureyes inureyes deleted the fix/issue-519-qwen35-moe-expert-name-variants branch July 2, 2026 13:49
inureyes added a commit that referenced this pull request Jul 6, 2026
…eMoeBlock actually loads (#671)

PR #588 renamed the shared qwen3_next SwitchGLU/SparseMoeBlock expert projections from w1/w2/w3 to gate_proj/up_proj/down_proj, but qwen3_5::sanitize_weights kept normalizing in the OLD direction: step 6 stacked per-expert experts.{e}.{w1,w2,w3} into switch_mlp.{w1,w2,w3}, and step 8 renamed pre-stacked switch_mlp.{gate,up,down}_proj INTO switch_mlp.{w1,w3,w2}. Every qwen3.5-MoE / qwen3.6-MoE checkpoint has therefore failed to load since #588 with "Missing weight: model.layers.0.mlp.switch_mlp.gate_proj" (issue #670; found by the 2026-07-06 benchmark sweep, where qwen3.5-35b-a3b-4bit and qwen3.6-35b-a3b-4bit regressed from 70/67 tok/s on 2026-06-12 to FAIL). The #587 per-expert gate/up/down stacking pass also targeted the stale w1/w3/w2 slots; its tests asserted sanitize output keys only and never loaded the result, so they passed against the wrong convention. The fix aligns all three passes with the block naming: per-expert w1/w2/w3 stacks into gate_proj/down_proj/up_proj, per-expert gate/up/down stacks into the same-name slots, and step 8 now renames legacy stacked w1/w3/w2 forward into gate/up/down while pre-stacked gate/up/down checkpoints pass through untouched. The missing gate is added as a regression test: sanitize output must load end to end through the shared SwitchGLU for all four naming conventions checkpoints ship (per-expert and pre-stacked, in both namings). Real-checkpoint validation: qwen3.5-35b-a3b-4bit and qwen3.6-35b-a3b-4bit load and answer coherently again (57.8 and 72.8 tok/s; "The capital of France is Paris." at a 200-token budget through the thinking template), and dense qwen3.5-4b-4bit is unaffected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status:review Under review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(qwen3.5-moe): load per-expert split MoE weights (experts.{e}.gate_proj/up_proj/down_proj)

1 participant