PaddlePaddle/PaddleOCR · error · ValueError
Head mask for a single layer should be of shape {(self.num_h
Error message
Head mask for a single layer should be of shape {(self.num_heads,)}, but is {layer_head_mask.shape} What it means
In the eager attention path of the UniMERNet decoder layer, an optional per-layer head mask must have exactly num_heads elements so it can scale each attention head's weights. The code validates tuple(layer_head_mask.shape) == (num_heads,) before applying the mask, raising ValueError otherwise because a wrong-size mask would broadcast incorrectly over the [bsz, num_heads, tgt, src] weights.
Source
Thrown at ppocr/modeling/heads/rec_unimernet_head.py:628
key_states = key_states.reshape(proj_shape)
value_states = value_states.reshape(proj_shape)
src_len = key_states.shape[1]
attn_weights = paddle.bmm(query_states, key_states.transpose([0, 2, 1]))
if attention_mask is not None:
attn_weights = (
attn_weights.reshape([bsz, self.num_heads, tgt_len, src_len])
+ attention_mask
)
attn_weights = attn_weights.reshape(
[bsz * self.num_heads, tgt_len, src_len]
)
attn_weights = nn.functional.softmax(attn_weights, axis=-1)
if layer_head_mask is not None:
if tuple(layer_head_mask.shape) != (self.num_heads,):
raise ValueError(
f"Head mask for a single layer should be of shape {(self.num_heads,)}, but is"
f" {layer_head_mask.shape}"
)
attn_weights = layer_head_mask.reshape(
[1, -1, 1, 1]
) * attn_weights.reshape([bsz, self.num_heads, tgt_len, src_len])
attn_weights = attn_weights.reshape(
[bsz * self.num_heads, tgt_len, src_len]
)
if output_attentions:
attn_weights_reshaped = attn_weights.reshape(
[bsz, self.num_heads, tgt_len, src_len]
)
attn_weights = attn_weights_reshaped.reshape(
[bsz * self.num_heads, tgt_len, src_len]
)
else:View on GitHub (pinned to 2661c7c0ef)
Solutions
- Pass head_mask=None (the normal path for this head; head pruning is rarely needed)
- If masking heads, supply shape [num_layers, num_heads] so each layer slice is (num_heads,)
Example fix
# before out = layer(hidden, head_mask=head_mask_scalar) # wrong shape # after out = layer(hidden, head_mask=None)
Defensive patterns
Strategy: validation
Validate before calling
if head_mask is not None:
assert head_mask.shape[1:] == (num_heads,), f'per-layer head mask must be ({num_heads},)' Type guard
def valid_head_mask(mask, num_layers: int, num_heads: int) -> bool:
return mask is None or (tuple(mask.shape) == (num_layers, num_heads)) Prevention
- Default to head_mask=None; head masking is a debugging feature
- Derive mask shapes from the live model (len(decoder.layers)) instead of hardcoded ints
When it happens
Trigger: Passing head_mask (or cross_attn_head_mask) to the decoder forward with a per-layer slice whose shape is not (num_heads,), e.g. shape [num_layers] used directly, or a scalar broadcast mask.
Common situations: Porting generation code from transformers where head_mask semantics differ; debugging attention with a custom mask tensor whose leading layer dimension was indexed incorrectly.
Related errors
- embed_dim must be divisible by num_heads (got `embed_dim`: {
- The `{mask_name}` should be specified for {len(self.layers)}
- The `{mask_name}` should be specified for {len(self.layers)}
- Incorrect 4D attention_mask shape: {tuple(attention_mask.sha
- Please set inference model dir in Global.inference_model or
AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14).
Data as JSON: /api/errors/3b3ff83ec328c4ba.
Report an issue: GitHub.