{"record":{"id":"9e739f37a7cd326d","repo":"opendatalab/MinerU","slug":"pp-doclayoutv2-reading-order-mask-must-be-2d-or-4d","errorCode":null,"errorMessage":"PP-DocLayoutV2 reading-order mask must be 2D or 4D, got shape {tuple(attention_mask.shape)}","messagePattern":"PP-DocLayoutV2 reading-order mask must be 2D or 4D, got shape (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mineru/model/layout/pp_doclayoutv2.py","lineNumber":145,"sourceCode":"        freeze_stem_only=True,\n        freeze_at=0,\n        freeze_norm=True,\n        lr_mult_list=[0, 0.05, 0.05, 0.05, 0.05],\n        out_features=[\"stage2\", \"stage3\", \"stage4\"],\n    )\n\n\ndef _create_bidirectional_mask(\n    inputs_embeds: torch.Tensor,\n    attention_mask: Optional[torch.Tensor],\n    encoder_hidden_states: Optional[torch.Tensor] = None,\n) -> Optional[torch.Tensor]:\n    if attention_mask is None:\n        return None\n    if attention_mask.ndim == 4:\n        return attention_mask\n    if attention_mask.ndim != 2:\n        raise ValueError(\n            f\"PP-DocLayoutV2 reading-order mask must be 2D or 4D, got shape {tuple(attention_mask.shape)}\"\n        )\n\n    embeds = encoder_hidden_states if encoder_hidden_states is not None else inputs_embeds\n    batch_size, query_length = inputs_embeds.shape[:2]\n    key_length = attention_mask.shape[1]\n\n    if attention_mask.shape[0] != batch_size:\n        raise ValueError(\n            f\"Attention mask batch size {attention_mask.shape[0]} does not match embeddings batch size {batch_size}\"\n        )\n\n    expanded_mask = attention_mask[:, None, None, :].expand(batch_size, 1, query_length, key_length)\n    expanded_mask = expanded_mask.to(device=embeds.device, dtype=embeds.dtype)\n    min_value = torch.finfo(embeds.dtype).min\n    return torch.where(\n        expanded_mask > 0,\n        torch.zeros(1, dtype=embeds.dtype, device=embeds.device),","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/opendatalab/MinerU/blob/4fe4bde114a23ee5dd637eae99b767f4669bf58c/mineru/model/layout/pp_doclayoutv2.py#L127-L163","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Supply a 2D mask: attention_mask of shape [batch_size, sequence_length].","If you already built a 4D [batch, heads, q, k] mask, pass it unchanged — it is returned as-is.","Fix upstream squeeze/unsqueeze logic: mask = mask.squeeze(1) to collapse a stray dim of size 1."],"exampleFix":"# before\nmask = torch.ones(1, 1, 128)          # 3D -> ValueError\nout = model(boxes, mask=mask)\n\n# after\nmask = torch.ones(1, 128)             # 2D [batch, seq]\nout = model(boxes, mask=mask)","handlingStrategy":"validation","validationCode":"def normalize_mask(mask):\n    if mask is None or mask.ndim in (2, 4):\n        return mask\n    if mask.ndim == 3 and mask.shape[1] == 1:\n        return mask.squeeze(1)          # [b,1,s] -> [b,s]\n    if mask.ndim == 3 and mask.shape[2] == 1:\n        return mask.squeeze(-1)         # [b,s,1] -> [b,s]\n    raise ValueError(f'cannot interpret mask with shape {tuple(mask.shape)}')","typeGuard":"def is_supported_attention_mask(mask) -> bool:\n    import torch\n    return isinstance(mask, torch.Tensor) and mask.ndim in (2, 4)","tryCatchPattern":null,"preventionTips":["Always build masks as 2D [batch, seq_len] with torch.ones/zeros.","Keep mask construction next to input construction so ranks stay in sync.","Add shape asserts before model.forward in debugging builds."],"tags":["pytorch","deep-learning","shape-mismatch","layout-model","attention-mask"],"backgroundTag":null,"analyzedSha":"4fe4bde114a23ee5dd637eae99b767f4669bf58c","analyzedAt":"2026-08-14T21:29:18.456Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}