{"record":{"id":"4b113d55daaef10e","repo":"PaddlePaddle/PaddleOCR","slug":"cannot-use-sin-cos-positional-encoding-with-odd-di","errorCode":null,"errorMessage":"Cannot use sin/cos positional encoding with odd dimension (got dim={:d})","messagePattern":"Cannot use sin/cos positional encoding with odd dimension \\(got dim=(.+?)\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"ppocr/modeling/transforms/tbsrn.py","lineNumber":47,"sourceCode":"from .stn import STN as STNHead\nfrom .tsrn import GruBlock, mish, UpsampleBLock\nfrom ppocr.modeling.heads.sr_rensnet_transformer import (\n    Transformer,\n    LayerNorm,\n    PositionwiseFeedForward,\n    MultiHeadedAttention,\n)\n\n\ndef positionalencoding2d(d_model, height, width):\n    \"\"\"\n    :param d_model: dimension of the model\n    :param height: height of the positions\n    :param width: width of the positions\n    :return: d_model*height*width position matrix\n    \"\"\"\n    if d_model % 4 != 0:\n        raise ValueError(\n            \"Cannot use sin/cos positional encoding with \"\n            \"odd dimension (got dim={:d})\".format(d_model)\n        )\n    pe = paddle.zeros([d_model, height, width])\n    # Each dimension use half of d_model\n    d_model = int(d_model / 2)\n    div_term = paddle.exp(\n        paddle.arange(0.0, d_model, 2, dtype=\"int64\") * -(math.log(10000.0) / d_model)\n    )\n    pos_w = paddle.arange(0.0, width, dtype=\"float32\").unsqueeze(1)\n    pos_h = paddle.arange(0.0, height, dtype=\"float32\").unsqueeze(1)\n\n    pe[0:d_model:2, :, :] = (\n        paddle.sin(pos_w * div_term).transpose([1, 0]).unsqueeze(1).tile([1, height, 1])\n    )\n    pe[1:d_model:2, :, :] = (\n        paddle.cos(pos_w * div_term).transpose([1, 0]).unsqueeze(1).tile([1, height, 1])\n    )","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/ppocr/modeling/transforms/tbsrn.py#L29-L65","documentation":"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.","triggerScenarios":"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.","commonSituations":"Editing TBSRN configs to tune model width; reusing the function elsewhere with an arbitrary embedding dim; merging configs from different text recognition models.","solutions":["Set d_model in the TBSRN config to a multiple of 4 (e.g. 384, 512)","If a custom dim is mandatory, pad the embedding to the next multiple of 4 before encoding"],"exampleFix":"# before\nTransform:\n  name: TBSRN\n  d_model: 386\n# after\nTransform:\n  name: TBSRN\n  d_model: 384","handlingStrategy":"validation","validationCode":"assert cfg['d_model'] % 4 == 0, f\"d_model must be a multiple of 4 for sin/cos 2D PE, got {cfg['d_model']}\"","typeGuard":"def valid_pe_dim(d_model: int) -> bool:\n    return isinstance(d_model, int) and d_model > 0 and d_model % 4 == 0","tryCatchPattern":null,"preventionTips":["Choose model widths from multiples of 4 (and of num_heads) by convention","Add a config-time divisibility assert for TBSRN d_model"],"tags":["paddle","tbsrn","positional-encoding","config","validation"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}