Skip to content

Add gqa_max_head_dim feature flag for configurable GQA limit - #241

Closed
justinchuby wants to merge 5 commits into
mainfrom
head-dim-feature-flag
Closed

Add gqa_max_head_dim feature flag for configurable GQA limit#241
justinchuby wants to merge 5 commits into
mainfrom
head-dim-feature-flag

Conversation

@justinchuby

Copy link
Copy Markdown
Member

Summary

Make the Attention→GroupQueryAttention rewrite rule head_dim limit configurable via a feature flag instead of a hardcoded constant.

Problem

The GQA rewrite rule had a hardcoded _MAX_GQA_HEAD_DIM = 256 that prevented GQA fusion for Gemma4 global attention layers (head_dim=512). PR #240 intended to change this to 512 but the value was not actually updated.

Solution

Replace the constant with flags.gqa_max_head_dim (default: 512), configurable via:

  • Environment variable: MOBIUS_GQA_MAX_HEAD_DIM=256
  • Programmatic: override_flags(gqa_max_head_dim=256)

Changes

  • _flags.py: Add _env_int helper, gqa_max_head_dim flag (default 512), update override_flags type hint
  • _group_query_attention.py: Replace _MAX_GQA_HEAD_DIM constant with flags.gqa_max_head_dim
  • _flags_test.py: 6 new tests (default value, env var, override, integration with GQA rewrite)

Testing

2674 tests pass, lint clean.

Make the Attention→GroupQueryAttention rewrite rule's head_dim limit
configurable via the gqa_max_head_dim flag (default: 512).

Previously the limit was hardcoded as _MAX_GQA_HEAD_DIM = 256, which
prevented GQA fusion for Gemma4 global attention layers (head_dim=512).
The new default of 512 matches newer ORT builds. Users targeting
older ORT builds can restore the limit with:
  export MOBIUS_GQA_MAX_HEAD_DIM=256
or programmatically:
  from mobius import override_flags
  with override_flags(gqa_max_head_dim=256): ...

Changes:
- _flags.py: Add _env_int helper, gqa_max_head_dim flag, update
  override_flags type hint to accept int
- _group_query_attention.py: Replace _MAX_GQA_HEAD_DIM constant
  with flags.gqa_max_head_dim
- _flags_test.py: 6 new tests covering default, env var, override,
  and integration with the GQA rewrite rule

2674 tests pass, lint clean.

Signed-off-by: Justin Chu <justinchu@microsoft.com>
@justinchuby
justinchuby requested review from a team and Copilot May 4, 2026 18:34
@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown

🏗️ Architecture Diff

Comparing d39b13b79f71d7

Model Sub-model Changes Status

No architecture changes detected.


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

@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown

Performance Comparison

Comparing d39b13b79f71d7

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

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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 makes the Attention→GroupQueryAttention rewrite rule’s head_dim cutoff configurable via a runtime feature flag (flags.gqa_max_head_dim) instead of using a hardcoded constant, enabling GQA fusion for models with larger head_dim (e.g., 512) while still allowing users to opt back into the legacy 256 limit via env var or override_flags().

Changes:

  • Add _env_int() and introduce gqa_max_head_dim flag (default 512), plus widen override_flags() typing to allow integer overrides.
  • Update the GQA rewrite rule to use flags.gqa_max_head_dim for the head-dim guard and for the corresponding failure message.
  • Add unit tests covering default/env/override behavior and verifying the GQA head-dim check respects the flag.

Reviewed changes

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

File Description
src/mobius/rewrite_rules/_group_query_attention.py Switches the GQA head-dim limit check to use flags.gqa_max_head_dim instead of a constant.
src/mobius/_flags.py Adds integer env parsing and introduces the gqa_max_head_dim feature flag (default 512).
src/mobius/_flags_test.py Adds tests for the new integer flag and verifies the GQA rewrite guard respects it.

Comment thread src/mobius/rewrite_rules/_group_query_attention.py
Comment thread src/mobius/rewrite_rules/_group_query_attention.py
Comment thread src/mobius/_flags.py Outdated
- Update inline comments from hardcoded '(256)' to reference
  gqa_max_head_dim flag
- Update docs/_generate_flags_docs.py to recognize _env_int() calls
  alongside _env_bool() so generated docs show correct defaults
- Regenerate docs/feature-flags.md with gqa_max_head_dim entry

Signed-off-by: Justin Chu <justinchu@microsoft.com>
docs/feature-flags.md is auto-generated by docs/_generate_flags_docs.py
and should not be committed. Add it to .gitignore.

Signed-off-by: Justin Chu <justinchu@microsoft.com>
Keep the conservative default (256) matching older ORT builds.
Users targeting newer ORT can set MOBIUS_GQA_MAX_HEAD_DIM=512.

Signed-off-by: Justin Chu <justinchu@microsoft.com>

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

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

Comment thread src/mobius/_flags.py Outdated
"""

gqa_max_head_dim: int = dataclasses.field(
default_factory=lambda: _env_int("MOBIUS_GQA_MAX_HEAD_DIM", 256)
Comment thread src/mobius/_flags.py Outdated
(ORT ≤1.24.x workaround).
* - ``gqa_max_head_dim``
- ``MOBIUS_GQA_MAX_HEAD_DIM``
- ``256``
Comment thread src/mobius/_flags_test.py Outdated
Comment on lines +116 to +120
def test_default_is_512(self, monkeypatch):
monkeypatch.delenv("MOBIUS_GQA_MAX_HEAD_DIM", raising=False)
f = _flags._Flags()
assert f.gqa_max_head_dim == 256

Comment on lines +171 to +176
# Skip when head_dim exceeds gqa_max_head_dim flag (default 256).
hd = _head_dim_exceeds_gqa_limit(past_key)
if hd is not None:
return result.fail(f"head_dim={hd} exceeds GQA MAX_HEAD_SIZE={_MAX_GQA_HEAD_DIM}")
return result.fail(
f"head_dim={hd} exceeds GQA MAX_HEAD_SIZE={flags.gqa_max_head_dim}"
)
Comment on lines +55 to +57
# The limit is now configurable via the ``gqa_max_head_dim`` flag (default 256
# for newer ORT builds). Set ``MOBIUS_GQA_MAX_HEAD_DIM=256`` to restore the
# old limit for ORT ≤1.24.
Comment thread src/mobius/_flags_test.py Outdated
"""Tests for the gqa_max_head_dim integer flag."""

def test_default_is_512(self, monkeypatch):
monkeypatch.delenv("MOBIUS_GQA_MAX_HEAD_DIM", raising=False)

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.

We set it as ENV? Why not just hard code it to 512 since it's a "max" value anyway.

The feature flag is unnecessary — old ORT versions have other CUDA
issues regardless, and CPU EP is unaffected by head_dim limits.

Simply update the hardcoded limit from 256 to 512 to support Gemma4
global attention (head_dim=512) with newer ORT builds.

Removes: gqa_max_head_dim flag, _env_int helper, associated tests.
Signed-off-by: Justin Chu <justinchu@microsoft.com>
@justinchuby

Copy link
Copy Markdown
Member Author

Closing this PR. After further discussion, the feature flag is not needed — we will hardcode MAX_HEAD_DIM=512 since older ORT versions have other CUDA issues that prevent usage anyway, and CPU EP is unaffected by head_dim. The 512 limit is already set in #240.

@justinchuby justinchuby closed this May 4, 2026
@justinchuby
justinchuby deleted the head-dim-feature-flag branch May 7, 2026 01:03
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.

3 participants