Commit 395f022
authored
gemma4 MoE: fix com.microsoft::MoE input slots + activation_type (#324)
## Problem
Per [upstream report on
microsoft/onnxruntime-genai#2062](microsoft/onnxruntime-genai#2062 (comment)),
the `justinchuby/gemma-4-26b-a4b-it-onnx` export does not load under
public ORT 1.25+:
```
MoE node has input size 4 not in range [min=5, max=8]
```
After patching the schema (inserting `fc1_experts_bias`), the next
failure is a weight shape mismatch:
```
Input 'fc1_experts_weights' is expected to have shape {128,704,2816}, got {128,1408,2816}
```
## Root cause
`Gemma4MoeBlock.forward` was emitting `com.microsoft::MoE` with:
- only 4 positional inputs (missing the optional `fc1_experts_bias` slot
at index 3, so `fc2_experts_weights` was in the wrong position); and
- `activation_type="silu"` even though `fc1_experts_weights` is laid out
as `[E, 2*inter, hidden]` (gate + up concatenated).
A surface fix (add `None` for slot 3, change `activation_type="swiglu"`)
gets past those two errors but uncovers a deeper incompatibility: the
ORT MoE kernel for `swiglu` is hardcoded for **GPT-OSS-style SwiGLU** —
not standard Gemma 4 SwiGLU. Full evidence + repro in
**microsoft/onnxruntime#28738**.
So there's currently no ORT-public SwiGLU MoE mode compatible with Gemma
4's standard SwiGLU semantics. Using the fused op silently produces
wrong outputs even when it loads.
## Fix
Always take the static-unroll fallback path (`_dispatch_moe_fallback`)
for Gemma 4 — drop the `ep_capabilities().supports_fused_moe` branch
entirely. The fallback emits standard ONNX ops (`Gather`, `MatMul`,
`Mul`, etc.) and computes the math correctly. Detailed comment in source
explains why so it doesn't get "re-optimized" back to the fused op
without an upstream kernel fix (microsoft/onnxruntime#28738).
Also fixes a latent bug in the fallback itself: `op.TopK(...)` was
unpacked without `_outputs=2`, so the path would have crashed at build
time the first time it was exercised.
## Verification
1. **Unit + L1 tests**: `tests/build_graph_test.py -k gemma4` → 15
passed.
2. **End-to-end ORT load**: rebuilt `google/gemma-4-26b-a4b-it` (`mobius
build ... --dtype f16`), the decoder (~51GB ONNX) loads cleanly under
public `onnxruntime==1.27.0`:
```
ORT 1.27.0
load OK in 959.6s (CPUExecutionProvider, ORT_DISABLE_ALL)
inputs (63): ['inputs_embeds', 'attention_mask', 'position_ids',
'past_key_values.0.key', 'past_key_values.0.value'] ...
```
(The 16-min load time is dominated by the 7680 expert MatMul nodes from
the fallback path — see "Followups" below.)
3. **HF Hub re-upload**: pushed the fixed fp16 build to
[`justinchuby/gemma-4-26b-a4b-it-onnx` under
`f16/default/`](https://huggingface.co/justinchuby/gemma-4-26b-a4b-it-onnx/tree/main/f16/default).
Users on the upstream issue can pull this and run with public ORT 1.27.
## Out of scope / followups
These are real but separate from the schema fix:
- **Native Gemma 4 SwiGLU kernel in ORT** — tracked upstream at
microsoft/onnxruntime#28738. Once ORT's MoE kernel supports standard
SwiGLU (concatenated layout, alpha=1.0, no clipping), mobius can
re-enable the fused path and get a fast quantizable form.
- **`OnnxKQuantQuantization` skips expert weights** — tracked at
microsoft/Olive#2489. The fallback's per-expert weights are accessed via
`op.Gather(stacked_weights, expert_idx)` (dynamic, not static
initializers), so the k-quant pass leaves them at fp16. Result: the
Q4_K_M build is only ~6% smaller than fp16 (47GB vs 51GB). The Olive
issue proposes two fix paths (pattern-aware kquant or a pre-pass that
unstacks per-expert weights).
## Related
- microsoft/onnxruntime-genai#2062 (upstream report from @tmtiwari)
- microsoft/onnxruntime#28738 (ORT MoE SwiGLU kernel hardcoded for
GPT-OSS, blocks standard SwiGLU)
- huggingface.co/justinchuby/gemma-4-26b-a4b-it-onnx (re-uploaded fp16)
Signed-off-by: justinchuby <11205048+justinchuby@users.noreply.github.com>
Co-authored-by: justinchuby <11205048+justinchuby@users.noreply.github.com>1 parent ef17fcb commit 395f022
1 file changed
Lines changed: 21 additions & 23 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1175 | 1175 | | |
1176 | 1176 | | |
1177 | 1177 | | |
1178 | | - | |
1179 | | - | |
1180 | | - | |
1181 | | - | |
1182 | | - | |
1183 | | - | |
1184 | | - | |
1185 | | - | |
1186 | | - | |
1187 | | - | |
1188 | | - | |
1189 | | - | |
1190 | | - | |
1191 | | - | |
1192 | | - | |
1193 | | - | |
1194 | | - | |
1195 | | - | |
1196 | | - | |
1197 | | - | |
1198 | | - | |
1199 | | - | |
| 1178 | + | |
| 1179 | + | |
| 1180 | + | |
| 1181 | + | |
| 1182 | + | |
| 1183 | + | |
| 1184 | + | |
| 1185 | + | |
| 1186 | + | |
| 1187 | + | |
| 1188 | + | |
| 1189 | + | |
| 1190 | + | |
| 1191 | + | |
| 1192 | + | |
| 1193 | + | |
| 1194 | + | |
| 1195 | + | |
| 1196 | + | |
| 1197 | + | |
1200 | 1198 | | |
1201 | 1199 | | |
1202 | 1200 | | |
| |||
1248 | 1246 | | |
1249 | 1247 | | |
1250 | 1248 | | |
1251 | | - | |
| 1249 | + | |
1252 | 1250 | | |
1253 | 1251 | | |
1254 | 1252 | | |
| |||
0 commit comments