Bvicii Claude Code commited on
Commit
1cd6565
·
verified ·
1 Parent(s): 8410628

Always use native create_causal_mask; fix FA2 and save_pretrained on v5

Browse files

- Drop the cache gate and `_create_causal_mask_fallback`. This file already needs transformers >= 4.54, where `masking_utils.create_causal_mask` exists. The gate pushed every cached call on 5.6-5.16 onto the fallback, which lost the SDPA `is_causal` fast path and the flex BlockMask, and gave FA3/FA4 a 4D mask. The signature differences (`input_embeds` -> `inputs_embeds`, removal of `cache_position`) are now resolved once from `inspect.signature`, and `position_ids` is passed as None because 3D M-RoPE coordinates are not packed-sequence positions.
- Declare `_supports_flash_attn = True` on `PaddleOCRPreTrainedModel`. v5 reads only this name, so `attn_implementation="flash_attention_2"` raised "PaddleOCRVisionModel does not support Flash Attention 2 yet". 4.x accepts both names.
- Use dict-style `_tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}`. v5 calls `.items()` on it, so the list form made `save_pretrained` raise `AttributeError: 'list' object has no attribute 'keys'`. 4.x only iterates it, which yields the same key. `tie_word_embeddings` is false in config.json, so lm_head stays untied.

Same change as PaddlePaddle/PaddleOCR-VL-1.6#15 (commits 91669010 and 0f4ece18); the modeling, configuration and config.json files of this PR are identical to that one before the change.

Tested on a tiny random model with transformers 4.57.6, 5.12.1 and 5.22.1, on CPU fp32 (eager, sdpa) and A100 bf16 (eager, sdpa, flash_attention_2): generation matches the previous PR head, cache == no cache, a left-padded row matches the same row unpadded, packed multi-image vision encoding matches per-image encoding, and save_pretrained + from_pretrained restores the rotary/position buffers, keeps lm_head tying as configured, and reproduces pre-save generation.

Co-Authored-By: Claude Code <noreply@anthropic.com>

Files changed (1) hide show
  1. modeling_paddleocr_vl.py +22 -70
modeling_paddleocr_vl.py CHANGED
@@ -30,6 +30,7 @@ from transformers.cache_utils import (
30
  Cache,
31
  DynamicCache,
32
  )
 
33
  from transformers.generation import GenerationMixin
34
  from transformers.integrations import use_kernel_forward_from_hub
35
  from transformers.modeling_attn_mask_utils import AttentionMaskConverter
@@ -68,24 +69,16 @@ from .configuration_paddleocr_vl import PaddleOCRVisionConfig, PaddleOCRVLConfig
68
 
69
 
70
  # Resolve optional framework interfaces once, outside the forward path.
71
- try:
72
- from transformers.masking_utils import create_causal_mask as _hf_create_causal_mask
73
- except ImportError:
74
- _hf_create_causal_mask = None
75
-
76
  try:
77
  from transformers import initialization as _hf_initialization
78
  except ImportError:
79
  _hf_initialization = None
80
 
81
- try:
82
- _HF_MASK_PARAMETERS = frozenset(inspect.signature(_hf_create_causal_mask).parameters)
83
- except (TypeError, ValueError):
84
- _HF_MASK_PARAMETERS = frozenset()
85
-
86
- _HF_MASK_INPUT_NAME = next(
87
- (name for name in ("inputs_embeds", "input_embeds") if name in _HF_MASK_PARAMETERS), None
88
- )
89
 
90
 
91
  def _guard_initializer(function):
@@ -118,60 +111,18 @@ def _create_causal_mask(config, inputs_embeds, attention_mask, past_key_values,
118
  return additive.masked_fill(~mask, torch.finfo(inputs_embeds.dtype).min)
119
  return mask.to(dtype=inputs_embeds.dtype)
120
 
121
- cache_supported = past_key_values is None or (
122
- hasattr(past_key_values, "get_mask_sizes")
123
- and ("cache_position" in _HF_MASK_PARAMETERS or hasattr(past_key_values, "get_query_offset"))
124
- )
125
- if _hf_create_causal_mask is not None and _HF_MASK_INPUT_NAME is not None and cache_supported:
126
- mask_kwargs = {
127
- "config": config,
128
- _HF_MASK_INPUT_NAME: inputs_embeds,
129
- "attention_mask": attention_mask,
130
- "past_key_values": past_key_values,
131
- }
132
- if "cache_position" in _HF_MASK_PARAMETERS:
133
- mask_kwargs["cache_position"] = cache_position
134
- if "position_ids" in _HF_MASK_PARAMETERS:
135
- # 3D M-RoPE coordinates are not packed text-sequence positions.
136
- mask_kwargs["position_ids"] = None
137
- return _hf_create_causal_mask(**mask_kwargs)
138
-
139
- return _create_causal_mask_fallback(
140
- config, inputs_embeds, attention_mask, past_key_values, cache_position
141
- )
142
-
143
-
144
- def _create_causal_mask_fallback(config, inputs_embeds, attention_mask, past_key_values, cache_position):
145
- # Keep mask semantics local: Transformers renamed inputs and removed
146
- # cache_position across releases. M-RoPE coordinates are handled separately.
147
- if attention_mask is not None and attention_mask.ndim == 4:
148
- mask = attention_mask.to(device=inputs_embeds.device)
149
- if mask.dtype == torch.bool:
150
- additive = torch.zeros(mask.shape, device=mask.device, dtype=inputs_embeds.dtype)
151
- return additive.masked_fill(~mask, torch.finfo(inputs_embeds.dtype).min)
152
- return mask.to(dtype=inputs_embeds.dtype)
153
- if config._attn_implementation == "flash_attention_2":
154
- return attention_mask if attention_mask is not None and (attention_mask == 0).any() else None
155
- batch_size, query_length = inputs_embeds.shape[:2]
156
- past_length = past_key_values.get_seq_length() if past_key_values is not None else 0
157
- key_length = past_length + query_length
158
- if attention_mask is not None:
159
- key_length = max(key_length, attention_mask.shape[-1])
160
- if past_key_values is not None and getattr(past_key_values, "is_compileable", False):
161
- maximum = past_key_values.get_max_cache_shape()
162
- if isinstance(maximum, int):
163
- key_length = max(key_length, maximum)
164
- query_positions = cache_position[-query_length:].to(inputs_embeds.device)
165
- key_positions = torch.arange(key_length, device=inputs_embeds.device)
166
- allowed = key_positions[None, :] <= query_positions[:, None]
167
- allowed = allowed[None, None, :, :].expand(batch_size, 1, query_length, key_length)
168
- if attention_mask is not None:
169
- padding = attention_mask[:, :key_length].to(device=inputs_embeds.device, dtype=torch.bool)
170
- if padding.shape[-1] < key_length:
171
- padding = F.pad(padding, (0, key_length - padding.shape[-1]), value=False)
172
- allowed = allowed & padding[:, None, None, :]
173
- mask = torch.zeros(allowed.shape, dtype=inputs_embeds.dtype, device=inputs_embeds.device)
174
- return mask.masked_fill(~allowed, torch.finfo(inputs_embeds.dtype).min)
175
 
176
 
177
  def _init_derived_buffers(module):
@@ -779,7 +730,7 @@ class Ernie4_5Model(Ernie4_5PreTrainedModel):
779
 
780
 
781
  class Ernie4_5ForCausalLM(Ernie4_5PreTrainedModel, GenerationMixin):
782
- _tied_weights_keys = ["lm_head.weight"]
783
  _tp_plan = {"lm_head": "colwise_rep"}
784
  _pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
785
 
@@ -1429,7 +1380,8 @@ class PaddleOCRPreTrainedModel(PreTrainedModel):
1429
  "PaddleOCRVisionEmbeddings",
1430
  "PaddleOCRMultiheadAttentionPoolingHead",
1431
  ]
1432
- _supports_flash_attn_2 = True
 
1433
  _supports_sdpa = True
1434
 
1435
  def _init_weights(self, module):
@@ -2033,7 +1985,7 @@ class PaddleOCRVLCausalLMOutputWithPast(ModelOutput):
2033
 
2034
 
2035
  class PaddleOCRVLForConditionalGeneration(Ernie4_5PreTrainedModel, GenerationMixin):
2036
- _tied_weights_keys = ["lm_head.weight"]
2037
  config_class = PaddleOCRVLConfig
2038
  _no_split_modules = ["Ernie4_5_DecoderLayer", "PaddleOCREncoderLayer"]
2039
 
 
30
  Cache,
31
  DynamicCache,
32
  )
33
+ from transformers.masking_utils import create_causal_mask as _hf_create_causal_mask
34
  from transformers.generation import GenerationMixin
35
  from transformers.integrations import use_kernel_forward_from_hub
36
  from transformers.modeling_attn_mask_utils import AttentionMaskConverter
 
69
 
70
 
71
  # Resolve optional framework interfaces once, outside the forward path.
 
 
 
 
 
72
  try:
73
  from transformers import initialization as _hf_initialization
74
  except ImportError:
75
  _hf_initialization = None
76
 
77
+ # create_causal_mask exists in every release this file can import on (>= 4.54),
78
+ # but its signature changed: `input_embeds` -> `inputs_embeds`, and
79
+ # `cache_position` was later removed in favor of reading offsets from the cache.
80
+ _HF_MASK_PARAMETERS = frozenset(inspect.signature(_hf_create_causal_mask).parameters)
81
+ _HF_MASK_INPUT_NAME = "inputs_embeds" if "inputs_embeds" in _HF_MASK_PARAMETERS else "input_embeds"
 
 
 
82
 
83
 
84
  def _guard_initializer(function):
 
111
  return additive.masked_fill(~mask, torch.finfo(inputs_embeds.dtype).min)
112
  return mask.to(dtype=inputs_embeds.dtype)
113
 
114
+ mask_kwargs = {
115
+ "config": config,
116
+ _HF_MASK_INPUT_NAME: inputs_embeds,
117
+ "attention_mask": attention_mask,
118
+ "past_key_values": past_key_values,
119
+ }
120
+ if "cache_position" in _HF_MASK_PARAMETERS:
121
+ mask_kwargs["cache_position"] = cache_position
122
+ if "position_ids" in _HF_MASK_PARAMETERS:
123
+ # 3D M-RoPE coordinates are not packed text-sequence positions.
124
+ mask_kwargs["position_ids"] = None
125
+ return _hf_create_causal_mask(**mask_kwargs)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
 
128
  def _init_derived_buffers(module):
 
730
 
731
 
732
  class Ernie4_5ForCausalLM(Ernie4_5PreTrainedModel, GenerationMixin):
733
+ _tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
734
  _tp_plan = {"lm_head": "colwise_rep"}
735
  _pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
736
 
 
1380
  "PaddleOCRVisionEmbeddings",
1381
  "PaddleOCRMultiheadAttentionPoolingHead",
1382
  ]
1383
+ # v5 only reads `_supports_flash_attn`; 4.x accepts both names.
1384
+ _supports_flash_attn = True
1385
  _supports_sdpa = True
1386
 
1387
  def _init_weights(self, module):
 
1985
 
1986
 
1987
  class PaddleOCRVLForConditionalGeneration(Ernie4_5PreTrainedModel, GenerationMixin):
1988
+ _tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
1989
  config_class = PaddleOCRVLConfig
1990
  _no_split_modules = ["Ernie4_5_DecoderLayer", "PaddleOCREncoderLayer"]
1991