opendatalab/MinerU · error · ValueError

PP-DocLayoutV2 reading-order mask must be 2D or 4D, got shap

Error message

PP-DocLayoutV2 reading-order mask must be 2D or 4D, got shape {tuple(attention_mask.shape)}

What it means

ValueError raised in _create_bidirectional_mask() (PP-DocLayoutV2 reading-order support) when the supplied attention_mask has neither 2 dims nor 4 dims. A 2D [batch, seq_len] mask is expanded to 4D internally and a 4D mask is passed through, but any other rank (e.g. 3D) cannot be interpreted and is rejected.

Source

Thrown at mineru/model/layout/pp_doclayoutv2.py:145

        freeze_stem_only=True,
        freeze_at=0,
        freeze_norm=True,
        lr_mult_list=[0, 0.05, 0.05, 0.05, 0.05],
        out_features=["stage2", "stage3", "stage4"],
    )


def _create_bidirectional_mask(
    inputs_embeds: torch.Tensor,
    attention_mask: Optional[torch.Tensor],
    encoder_hidden_states: Optional[torch.Tensor] = None,
) -> Optional[torch.Tensor]:
    if attention_mask is None:
        return None
    if attention_mask.ndim == 4:
        return attention_mask
    if attention_mask.ndim != 2:
        raise ValueError(
            f"PP-DocLayoutV2 reading-order mask must be 2D or 4D, got shape {tuple(attention_mask.shape)}"
        )

    embeds = encoder_hidden_states if encoder_hidden_states is not None else inputs_embeds
    batch_size, query_length = inputs_embeds.shape[:2]
    key_length = attention_mask.shape[1]

    if attention_mask.shape[0] != batch_size:
        raise ValueError(
            f"Attention mask batch size {attention_mask.shape[0]} does not match embeddings batch size {batch_size}"
        )

    expanded_mask = attention_mask[:, None, None, :].expand(batch_size, 1, query_length, key_length)
    expanded_mask = expanded_mask.to(device=embeds.device, dtype=embeds.dtype)
    min_value = torch.finfo(embeds.dtype).min
    return torch.where(
        expanded_mask > 0,
        torch.zeros(1, dtype=embeds.dtype, device=embeds.device),

View on GitHub (pinned to 4fe4bde114)

Solutions

  1. Supply a 2D mask: attention_mask of shape [batch_size, sequence_length].
  2. If you already built a 4D [batch, heads, q, k] mask, pass it unchanged — it is returned as-is.
  3. Fix upstream squeeze/unsqueeze logic: mask = mask.squeeze(1) to collapse a stray dim of size 1.

Example fix

# before
mask = torch.ones(1, 1, 128)          # 3D -> ValueError
out = model(boxes, mask=mask)

# after
mask = torch.ones(1, 128)             # 2D [batch, seq]
out = model(boxes, mask=mask)
Defensive patterns

Strategy: validation

Validate before calling

def normalize_mask(mask):
    if mask is None or mask.ndim in (2, 4):
        return mask
    if mask.ndim == 3 and mask.shape[1] == 1:
        return mask.squeeze(1)          # [b,1,s] -> [b,s]
    if mask.ndim == 3 and mask.shape[2] == 1:
        return mask.squeeze(-1)         # [b,s,1] -> [b,s]
    raise ValueError(f'cannot interpret mask with shape {tuple(mask.shape)}')

Type guard

def is_supported_attention_mask(mask) -> bool:
    import torch
    return isinstance(mask, torch.Tensor) and mask.ndim in (2, 4)

Prevention

When it happens

Trigger: Calling the reading-order forward path with attention_mask of shape [batch, 1, seq_len] or [batch, seq_len, 1]; passing a mask squeezed/unsqueezed incorrectly; feeding encoder-decoder style 3D masks from another model's preprocessing.

Common situations: Adapting masks produced by HF tokenizers/processors with extra dimensions; porting pipeline code from a different layout model whose mask convention is 3D; batch-wrapping a single sample's mask with an extra axis.

Related errors


AI-assisted analysis of opendatalab/MinerU@4fe4bde114 (2026-08-14). Data as JSON: /api/errors/9e739f37a7cd326d. Report an issue: GitHub.