Skip to content

🚨 [gemma 3/4] Fix bidirectional attention masking crossing sliding window boundaries - #46850

Merged
zucchini-nlp merged 7 commits into
huggingface:mainfrom
douglas-reid:fix/attention-masking-sliding-window-bidirectional
Jun 30, 2026
Merged

zucchini-nlp merged 7 commits into
huggingface:mainfrom
douglas-reid:fix/attention-masking-sliding-window-bidirectional

Conversation

@douglas-reid

@douglas-reid douglas-reid commented Jun 23, 2026 •

Copy link
Copy Markdown
Contributor

CI

What does this PR do?

This fixes the behavior of attention masking for image tokens to properly respect sliding window boundaries for Gemma 3/4 models. This was needed to match the intended model behavior for local layers.

  • I confirm that this is not a pure code agent PR.

Before submitting

  • Did you read the contributor guideline and the
    Pull Request checks?
  • Was this discussed/approved via a Github issue or the forum? Please add a link
    to it if that's the case.
  • Did you make sure to update the documentation with your changes according to the guidelines?
  • Did you write any new necessary tests?

CI recap

Dashboard: View test results in Grafana
Latest run: 28405951213:2
Result: success | Jobs: 7 | Tests: 2,337 | Failures: 0 | Duration: 32m 59s

…ion tokens

For Gemma 4, vision tokens should only attend bidirectionally within local
(sliding window) layers, not global (full attention) layers.

Previously, this implementation shared a single
create_masks_for_vision_model function (defined in modular_gemma3.py)
between both Gemma 3 and Gemma 4. This was incorrect because:

- Gemma 3 uses a single unified mask with bidirectional attention baked in for ALL layers
  (including global).
- Gemma 4 explicitly disables bidirectional attention on global layers.

This commit:
- Keeps Gemma 3's create_masks_for_vision_model unchanged (OR(causal,
  blockwise) on global layers).
- Adds a Gemma 4-specific create_masks_for_vision_model in
  modular_gemma4.py that uses causal-only masking for global layers.
@douglas-reid
douglas-reid force-pushed the fix/attention-masking-sliding-window-bidirectional branch from 01689c6 to 21a175b Compare June 25, 2026 19:50

@zucchini-nlp zucchini-nlp left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oke, so we have different masks for Gemma3 and Gemma4 at the end. I think this is change the expected outputs in slow CI, let me trigger it. Some fast tests on assisted decoding are failing btw

Also lets mark the PR with 🚨 , as it is breaking even if in a good way

@zucchini-nlp

Copy link
Copy Markdown
Member

run-slow: gemma3, gemma4, gemma4_unified

@github-actions

Copy link
Copy Markdown
Contributor

Workflow Run ⚙️

This comment contains run-slow, running the specified jobs:

models: ["models/gemma3", "models/gemma4", "models/gemma4_unified"]
quantizations: []

@HuggingFaceDocBuilderDev

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@douglas-reid douglas-reid changed the title [gemma 3/4] Fix bidirectional attention masking crossing sliding window boundaries 🚨 [gemma 3/4] Fix bidirectional attention masking crossing sliding window boundaries Jun 29, 2026
Manually pad `block_sequence_ids` to `kv_length` before it is passed as a closure to `or_mask_function` in `create_causal_mask`. This ensures the shape matches the full cache length during autoregressive decoding, fixing a device-side assert crash during generation.

Additionally, moved local `create_masks_for_vision_model` test imports to the top of the file as requested in PR review.
@github-actions

Copy link
Copy Markdown
Contributor

[For maintainers] Suggested jobs to run (before merge)

run-slow: gemma3, gemma4, gemma4_unified

@douglas-reid

Copy link
Copy Markdown
Contributor Author

Applied some test updates and added 🚨 to the PR title.

@zucchini-nlp

Copy link
Copy Markdown
Member

run-slow: gemma3, gemma4, gemma4_unified

@huggingface huggingface deleted a comment from github-actions Bot Jun 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Workflow Run ⚙️

This comment contains run-slow, running the specified jobs:

models: ["models/gemma3", "models/gemma4", "models/gemma4_unified"]
quantizations: []

@github-actions

Copy link
Copy Markdown
Contributor

CI Results

Workflow Run ⚙️

Commit Info

Context Commit Description
RUN 2dfad5da workflow commit (merge commit)
PR 59c04311 branch commit (from PR)
main 957e6032 base commit (on main)

✅ No failing test specific to this PR 🎉 👏 !

@zucchini-nlp
zucchini-nlp added this pull request to the merge queue Jun 30, 2026
Merged via the queue into huggingface:main with commit 1f3294c Jun 30, 2026
45 checks passed
stevhliu pushed a commit to stevhliu/transformers that referenced this pull request Jul 30, 2026
…ndow boundaries (huggingface#46850)

* Fix bidirectional attention masking crossing sliding window boundaries in Gemma 3/4

* run make fix-repo

* remove unused vars in test

* update unified model as well

* fix(gemma4): disable bidirectional attention on global layers for vision tokens

For Gemma 4, vision tokens should only attend bidirectionally within local
(sliding window) layers, not global (full attention) layers.

Previously, this implementation shared a single
create_masks_for_vision_model function (defined in modular_gemma3.py)
between both Gemma 3 and Gemma 4. This was incorrect because:

- Gemma 3 uses a single unified mask with bidirectional attention baked in for ALL layers
  (including global).
- Gemma 4 explicitly disables bidirectional attention on global layers.

This commit:
- Keeps Gemma 3's create_masks_for_vision_model unchanged (OR(causal,
  blockwise) on global layers).
- Adds a Gemma 4-specific create_masks_for_vision_model in
  modular_gemma4.py that uses causal-only masking for global layers.

* Fix CUDA assert during generation in Gemma 3/4 sliding window attention

Manually pad `block_sequence_ids` to `kv_length` before it is passed as a closure to `or_mask_function` in `create_causal_mask`. This ensures the shape matches the full cache length during autoregressive decoding, fixing a device-side assert crash during generation.

Additionally, moved local `create_masks_for_vision_model` test imports to the top of the file as requested in PR review.

* Fix misleading test comments: correct query/key direction in mask assertions

---------

Co-authored-by: Douglas Reid <21148125+douglas-reid@users.noreply.github.com>
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