You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Summary
Enables converting the **unsloth/gemma-4-E2B-it GGUF (Q4_K_M)** directly
into a working INT4 ONNX model that targets the **QNN EP / Hexagon HTP**
— reusing the GGUF's existing INT4 weights instead of running expensive
Olive quantization. Pairs with olive-recipes#432 (adds a GGUF-direct
`config_gguf.json`).
## What's here
**1. Gemma 4 GGUF INT4 conversion fixes** (make `mobius build-gguf
--keep-quantized` work for E2B):
- Collapse per-layer `feed_forward_length` array → scalar
`intermediate_size` + `use_double_wide_mlp`.
- Map the top-level per-layer-input tensors + strip the
`layer_scalar.weight` artefact.
- Thread the INT4 `MatMulNBits` linear class through Gemma4
(`--keep-quantized` was silently producing a **float** model) + tie the
float LM head.
- Fix KV-shared standard-Attention shape inference (opset-24 `Attention`
present outputs are un-inferred → `o_proj` collapsed → model
unloadable).
- Fix the Gemma GGUF activation default (`silu` → `gelu_pytorch_tanh`;
the wrong default produced garbage output).
**2. QNN HTP lowering** (two EP-capability-gated transforms; both
default-on, off for `qnn`):
- `supports_attention=False` → `DecomposeAttentionPass` rewrites the
fused opset-24 `Attention` op into SDPA primitives
(Reshape/Transpose/MatMul/Softmax/Add, Tile for GQA). An `onnx_ir`
InPlacePass so it can rewire the 3 outputs (present-KV are graph outputs
on some layers, dead on shared-KV layers — mixed arity the pattern
rewriter can't express).
- `supports_matmul_nbits=False` → `com.microsoft::MatMulNBits` lowered
to blocked-uint4 `DequantizeLinear` + `MatMul` (QDQ), implemented as a
**model-local ir.Function** expanded by the existing InlinePass
mechanism (like SkipLayerNormalization / PackedMultiHeadAttention).
Supported EPs keep the native contrib op + kernel.
## Verification
- Dequantized GGUF weights match the gated `google/gemma-4-E2B-it`
checkpoint (corr ≥ 0.98).
- Both lowerings are numerically identical to the originals via ORT
(maxdiff 0.0 for prefill/decode/GQA/mask; ~5e-7 with softcap due to fp
rounding).
- The INT4 model generates correct text on ORT ("capital of France →
Paris", "capital of Japan → Tokyo", valid haiku).
- A full `qnn` build lowers to **0 Attention / 35 Softmax** and **0
MatMulNBits / 205 DequantizeLinear**, all 30 present-KV graph outputs
preserved; CPU/CUDA builds unchanged (still emit GQA + MatMulNBits).
- Empirically confirmed on a Snapdragon X box (ORT 1.27, QNN SDK
2.48.40): HTP runs the primitive ops
(MatMul/Softmax/RMSNormalization/Gelu) but **not** fused
Attention/MatMulNBits — exactly what this lowering removes. (Plugin QNN
EP is engaged via `add_provider_for_devices`, and HTP requires fully
static shapes.)
## Remaining / follow-up
- Unit tests for `DecomposeAttentionPass` and the `MatMulNBits` function
body (in progress).
- End-to-end HTP EPContext compile validation (olive-recipes
`config_gguf.json` path) not yet hardware-validated.
🤖 Generated with GitHub Copilot CLI
---------
Signed-off-by: Justin Chu <justinchu@microsoft.com>
Signed-off-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
0 commit comments