PaddlePaddle/PaddleOCR · error · ValueError

Cannot use sin/cos positional encoding with odd dimension (g

Error message

Cannot use sin/cos positional encoding with odd dimension (got dim={:d})

What it means

positionalencoding2d in TBSRN builds sine/cos positional encodings by splitting d_model into two halves and then stepping by 2, which requires d_model % 4 == 0. Odd or non-multiple-of-4 dims would break the arithmetic, so the function raises ValueError up front.

Source

Thrown at ppocr/modeling/transforms/tbsrn.py:47

from .stn import STN as STNHead
from .tsrn import GruBlock, mish, UpsampleBLock
from ppocr.modeling.heads.sr_rensnet_transformer import (
    Transformer,
    LayerNorm,
    PositionwiseFeedForward,
    MultiHeadedAttention,
)


def positionalencoding2d(d_model, height, width):
    """
    :param d_model: dimension of the model
    :param height: height of the positions
    :param width: width of the positions
    :return: d_model*height*width position matrix
    """
    if d_model % 4 != 0:
        raise ValueError(
            "Cannot use sin/cos positional encoding with "
            "odd dimension (got dim={:d})".format(d_model)
        )
    pe = paddle.zeros([d_model, height, width])
    # Each dimension use half of d_model
    d_model = int(d_model / 2)
    div_term = paddle.exp(
        paddle.arange(0.0, d_model, 2, dtype="int64") * -(math.log(10000.0) / d_model)
    )
    pos_w = paddle.arange(0.0, width, dtype="float32").unsqueeze(1)
    pos_h = paddle.arange(0.0, height, dtype="float32").unsqueeze(1)

    pe[0:d_model:2, :, :] = (
        paddle.sin(pos_w * div_term).transpose([1, 0]).unsqueeze(1).tile([1, height, 1])
    )
    pe[1:d_model:2, :, :] = (
        paddle.cos(pos_w * div_term).transpose([1, 0]).unsqueeze(1).tile([1, height, 1])
    )

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Set d_model in the TBSRN config to a multiple of 4 (e.g. 384, 512)
  2. If a custom dim is mandatory, pad the embedding to the next multiple of 4 before encoding

Example fix

# before
Transform:
  name: TBSRN
  d_model: 386
# after
Transform:
  name: TBSRN
  d_model: 384
Defensive patterns

Strategy: validation

Validate before calling

assert cfg['d_model'] % 4 == 0, f"d_model must be a multiple of 4 for sin/cos 2D PE, got {cfg['d_model']}"

Type guard

def valid_pe_dim(d_model: int) -> bool:
    return isinstance(d_model, int) and d_model > 0 and d_model % 4 == 0

Prevention

When it happens

Trigger: Constructing/running TBSRN with d_model not divisible by 4 (e.g. 386, 390, or an odd value), typically from the Transform config's d_model or hidden dim.

Common situations: Editing TBSRN configs to tune model width; reusing the function elsewhere with an arbitrary embedding dim; merging configs from different text recognition models.

Related errors


AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14). Data as JSON: /api/errors/4b113d55daaef10e. Report an issue: GitHub.