fix(masking): preserve dict return type in create_masks_for_generate single-pattern path#46988
Closed
fyhon wants to merge 1 commit into
Closed
fix(masking): preserve dict return type in create_masks_for_generate single-pattern path#46988fyhon wants to merge 1 commit into
fyhon wants to merge 1 commit into
Conversation
…single-pattern path PR huggingface#41251 introduced an early-return path in create_masks_for_generate that returns a bare mask value (instead of a dict) when effective_config.layer_types contains a single unique pattern. Downstream forward methods like Qwen3Model.forward use isinstance(attention_mask, dict) to detect whether the mask was already prepared by generate(), so a bare return causes the model to silently rebuild the mask, defeating the purpose of precomputation. Wrap the single-pattern early-return in {layer_pattern: mask} to keep the dict contract. The unknown-types path (L1561) is left untouched: returning the raw attention_mask there is a deliberate 'defer to model' fallback whose semantics differ from the dict path. Fixes huggingface#46962 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Contributor
CI recapDashboard: View test results in Grafana |
Member
|
Would prefer to wait for Arthur to reply in the thread rather than just asking Claude to make a change immediately! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #46962. Restores the dict return-type contract of
create_masks_for_generatefor the single-pattern early-return path introduced by #41251, so that downstream models likeQwen3Model.forwarddo not silently rebuild the mask thatgeneratejust precomputed.Changes
src/transformers/masking_utils.py(2 insertions, 1 deletion): wrap the single-pattern early-return in a dict keyed by the layer pattern name.Before:
After:
The unknown-types path (L1560-1561,
return attention_mask) is intentionally left untouched: returning the raw attention_mask there is a deliberate 'defer to model' fallback whose semantics differ from the dict path — wrapping it in a synthetic key would over-reach.Root Cause
PR #41251 added two early-return paths in
create_masks_for_generatethat return bare values instead of the dict wrapper the function had always produced whenlayer_typeswas set. Downstream forward methods (e.g.Qwen3Model.forward, L403) detect precomputed masks withisinstance(attention_mask, dict); a bare mask value fails the check and triggers a secondcreate_causal_mask(...)call. In XPU/CPU paths this second call falls into_can_skip_causal_maskand cannot prove the mask is purely causal, so it builds a full 4D mask withis_causal=False, silently degrading generate() throughput.Duplicate Check
gh pr list --repo huggingface/transformers --state all --search "46962 in:body"→ 0 resultsgh pr list --repo huggingface/transformers --state open --search "create_masks_for_generate return type"→ 0 resultsTesting
Environment: CPU-only container based on
hub.bilibili.co/nyx-base/vllm:0.18.0(python 3.10, torch 2.10+cu128 with CUDA unavailable), transformers 5.8.0.dev0 (upstream/main@181beb3ba4 + this patch).Reproduction script (based on the
repro_contract.pyattached to the issue):layer_types=["full_attention"]*4) — used to returnTensor, now returns{"full_attention": Tensor}✅layer_types=["unknown_attn_type"]*2) — still returns bareNone, deliberate 'defer to model'layer_types=["full_attention", "sliding_attention", "full_attention"]) — always returned dict, unchangedDownstream
Qwen3Model.forwardnow uses the precomputed mask on Case A instead of rebuilding it.AI Disclosure
This PR was drafted with AI assistance (Claude Opus 4.6). The human submitter (@fyhon) has reviewed each changed line, ran the tests reported above, and takes responsibility for the change. The AI's role was scoped to:
No maintainer coordination was needed beyond the routing already present in the issue thread (Rocketknight1 cc'd @ArthurZucker), because the fix is a direct restoration of the pre-#41251 return-type contract on the specific path that regresses Qwen3.