Skip to content

Fix Gemma4 weight mapping for 26b MoE and 31b alternative attention - #237

Closed
justinchuby wants to merge 5 commits into
mainfrom
gemma4-weight-fixes
Closed

Fix Gemma4 weight mapping for 26b MoE and 31b alternative attention#237
justinchuby wants to merge 5 commits into
mainfrom
gemma4-weight-fixes

Conversation

@justinchuby

Copy link
Copy Markdown
Member

Summary

Two weight mapping fixes for Gemma4 models that use attention_k_eq_v=True (26b-a4b, 31b):

Fix 1: Alternative attention (V=K) for full_attention layers

When attention_k_eq_v=True, full-attention layers derive V from K (no separate v_proj), matching HF Gemma4TextAttention. Changes:

  • Skip v_proj creation for alternative-attention layers
  • In forward: V = raw k_proj output (before k_norm/RoPE), then v_norm applied
  • Per-layer KV head count: full_attention uses num_global_key_value_heads
  • Update task KV cache inputs with per-layer head counts

Fix 2: MoE expert weight mapping in Gemma4Model

Gemma4Model (multimodal) had its own preprocess_weights that was missing:

  • Expert weight rename (experts.gate_up_projfc1_experts_weights)
  • Router scale folding (hidden_size^-0.5)

These were only in Gemma4CausalLMModel.preprocess_weights.

Testing

  • 12/12 Gemma4 L1 tests pass
  • 2662/2662 full suite pass
  • Verified: decoder exports successfully for both 26b-a4b and 31b models

Models affected

Model Issue Fixed
gemma-4-26b-a4b[-it] MoE expert weights + V=K
gemma-4-31b[-it] V=K alternative attention
gemma-4-e2b[-it] No issue (no k_eq_v) ✅ Unaffected
gemma-4-e4b[-it] No issue (no k_eq_v) ✅ Unaffected

justinchuby and others added 2 commits May 4, 2026 06:06
When attention_k_eq_v=True (26b-a4b, 31b models), full_attention layers
derive V from K (no separate v_proj), matching HF Gemma4TextAttention.

Changes:
- Add attention_k_eq_v and num_global_key_value_heads to Gemma4Config
- Skip v_proj creation for alternative-attention layers
- In forward: V = raw k_proj output (before k_norm/RoPE), then v_norm
- Per-layer KV head count: full_attention uses num_global_key_value_heads
- Update task KV cache to use per-layer head counts

Tests: 2680 passed (12 gemma4), lint clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
Gemma4Model (multimodal) has its own preprocess_weights that was missing
the expert weight rename (gate_up_proj → fc1_experts_weights) and router
scale folding. These were only in Gemma4CausalLMModel.preprocess_weights.

Added both transformations to the multimodal model's preprocess_weights,
fixing 26b-a4b and 26b-a4b-it exports.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown

Performance Comparison

Comparing 474f5b1698365f

Model Metric Baseline Current Delta
bert (feature-extraction) model_size_bytes 359 KB 359 KB +0.0%
bert (feature-extraction) num_nodes 60 60 +0.0%
falcon model_size_bytes 364 KB 364 KB +0.0%
falcon num_nodes 66 66 +0.0%
gemma2 model_size_bytes 428 KB 428 KB +0.0%
gemma2 num_nodes 107 107 +0.0%
gpt2 model_size_bytes 388 KB 388 KB +0.0%
gpt2 num_nodes 53 53 +0.0%
llama model_size_bytes 425 KB 425 KB +0.0%
llama num_nodes 61 61 +0.0%
llama (static-cache) model_size_bytes 425 KB 425 KB +0.0%
llama (static-cache) num_nodes 58 58 +0.0%
mamba (ssm-text-generation) model_size_bytes 296 KB 296 KB +0.0%
mamba (ssm-text-generation) num_nodes 98 98 +0.0%
phi3 model_size_bytes 421 KB 421 KB +0.0%
phi3 num_nodes 59 59 +0.0%
phi3 (static-cache) model_size_bytes 421 KB 421 KB +0.0%
phi3 (static-cache) num_nodes 56 56 +0.0%
qwen2 model_size_bytes 425 KB 425 KB +0.0%
qwen2 num_nodes 61 61 +0.0%
qwen2 (static-cache) model_size_bytes 425 KB 425 KB +0.0%
qwen2 (static-cache) num_nodes 58 58 +0.0%
qwen3_5_moe (hybrid-text-generation) model_size_bytes 506 KB 506 KB +0.0%
qwen3_5_moe (hybrid-text-generation) num_nodes 275 275 +0.0%
qwen3_5_text (hybrid-text-generation) model_size_bytes 458 KB 458 KB +0.0%
qwen3_5_text (hybrid-text-generation) num_nodes 129 129 +0.0%
qwen3_5_vl (hybrid-qwen-vl) model_size_bytes 977 KB 977 KB +0.0%
qwen3_5_vl (hybrid-qwen-vl) num_nodes 408 408 +0.0%
t5 (seq2seq) model_size_bytes 836 KB 836 KB +0.0%
t5 (seq2seq) num_nodes 166 166 +0.0%
whisper (speech-to-text) model_size_bytes 1008 KB 1008 KB +0.0%
whisper (speech-to-text) num_nodes 128 128 +0.0%

No performance regressions.

@codecov

codecov Bot commented May 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 48.57143% with 18 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/mobius/models/gemma4.py 40.00% 17 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown

🏗️ Architecture Diff

Comparing 474f5b1698365f

Model Sub-model Changes Status
bert (feature-extraction) model 0
falcon model 0
gemma2 model 0
gemma4 (gemma4) decoder 0
gemma4 (gemma4) embedding 0
gemma4 (gemma4) vision_encoder 0
gemma4_text model 0
gpt2 model 0
llama model 0
llama (static-cache) model 0
mamba (ssm-text-generation) model 0
phi3 model 0
phi3 (static-cache) model 0
qwen model 0
qwen (static-cache) model 0
qwen2 model 0
qwen2 (static-cache) model 0
qwen2_moe model 0
qwen2_moe (static-cache) model 0
qwen3 model 0
qwen3 (static-cache) model 0
qwen3_5_moe (hybrid-text-generation) model 0
qwen3_5_text (hybrid-text-generation) model 0
qwen3_5_vl (hybrid-qwen-vl) decoder 0
qwen3_5_vl (hybrid-qwen-vl) embedding 0
qwen3_5_vl (hybrid-qwen-vl) vision_encoder 0
qwen3_moe model 0
qwen3_moe (static-cache) model 0
qwen3_next (hybrid-text-generation) model 0
t5 (seq2seq) decoder 0
t5 (seq2seq) encoder 0
whisper (speech-to-text) decoder 0
whisper (speech-to-text) encoder 0

No architecture changes detected.


Legend: ⚪ No change · 🔵 Minor (attrs/inits) · 🟡 Moderate (nodes added/removed) · 🔴 Major (interface changed)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes Gemma4 HuggingFace weight/graph mapping for variants that enable alternative attention (attention_k_eq_v=True) and for multimodal Gemma4 MoE checkpoints, aligning Mobius’ ONNX module structure with HF’s parameterization.

Changes:

  • Implement alternative-attention behavior for full-attention layers (V derived from raw K projection, no v_proj, and per-layer KV head counts).
  • Add missing MoE expert weight renames and router scale folding to Gemma4Model.preprocess_weights (multimodal path).
  • Extend Gemma4Config with attention_k_eq_v and plumb it through from_transformers.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/mobius/tasks/_gemma4.py Adjusts KV-cache input shapes to account for alternative-attention KV head counts.
src/mobius/models/gemma4.py Implements V=K alternative attention (no v_proj) and adds MoE weight mapping + router scale folding for multimodal Gemma4.
src/mobius/_configs.py Adds attention_k_eq_v to Gemma4Config and extracts it from HF configs.

Comment thread src/mobius/models/gemma4.py Outdated
Comment thread src/mobius/tasks/_gemma4.py Outdated
Comment thread src/mobius/models/gemma4.py
justinchuby and others added 3 commits May 4, 2026 14:27
The need_fallback check only considered KV-shared layers but not layers
where head_dim exceeds CUDA GQA's max (256). Full-attention layers with
global_head_dim=512 fell through to GQA fallback with an empty bias dict,
causing KeyError: 'full_attention'.

Fix: include head_dim > 256 in the need_fallback condition.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
Latest ORT supports head_dim=512 in GroupQueryAttention. Remove the
fallback that routed full-attention layers (global_head_dim=512) to
standard Attention instead of GQA. All non-shared layers now use GQA
on CUDA EP regardless of head_dim.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
Decouple two independent Gemma4 features:
- num_global_key_value_heads: controls KV head count for full-attention
  layers. Now used whenever set (not None), regardless of attention_k_eq_v.
- attention_k_eq_v: controls V=K sharing (no v_proj). Gated separately.

Previously both were coupled: num_global_key_value_heads only took effect
when attention_k_eq_v was True. This was incorrect — a model could have
different KV head counts for global/local layers without sharing V=K.

Changes:
- gemma4.py: Use num_global_key_value_heads for full-attention layers
  whenever it's not None
- _gemma4.py: Same decoupling in _make_gemma4_kv_cache_inputs
- build_graph_test.py: Add test with k_eq_v=True and
  num_global_key_value_heads != num_key_value_heads, verifying no v_proj
  and correct KV cache shapes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
@justinchuby justinchuby closed this May 4, 2026
@justinchuby justinchuby reopened this May 4, 2026
@justinchuby justinchuby closed this May 4, 2026
@justinchuby
justinchuby deleted the gemma4-weight-fixes branch May 4, 2026 17:53
@justinchuby

Copy link
Copy Markdown
Member Author

Replaced by #239

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.

2 participants