PaddlePaddle/PaddleOCR · error · ValueError

The mode.lower() if KLJSLoss should be one of ['kl', 'js']

Error message

The mode.lower() if KLJSLoss should be one of ['kl', 'js']

What it means

KLJSLoss implements only two divergence modes: 'kl' (symmetrized KL, first branch) and 'js' (Jensen-Shannon, second branch). The comparison is done on self.mode.lower(), so case is irrelevant, but any other string (e.g. 'JS ' with whitespace, 'kl_div', 'JSdiv') falls into the else and raises ValueError at forward time.

Source

Thrown at ppocr/losses/basic_loss.py:81

            "JS",
        ], "mode can only be one of ['kl', 'KL', 'js', 'JS']"
        self.mode = mode

    def __call__(self, p1, p2, reduction="mean", eps=1e-5):
        if self.mode.lower() == "kl":
            loss = paddle.multiply(p2, paddle.log((p2 + eps) / (p1 + eps) + eps))
            loss += paddle.multiply(p1, paddle.log((p1 + eps) / (p2 + eps) + eps))
            loss *= 0.5
        elif self.mode.lower() == "js":
            loss = paddle.multiply(
                p2, paddle.log((2 * p2 + eps) / (p1 + p2 + eps) + eps)
            )
            loss += paddle.multiply(
                p1, paddle.log((2 * p1 + eps) / (p1 + p2 + eps) + eps)
            )
            loss *= 0.5
        else:
            raise ValueError(
                "The mode.lower() if KLJSLoss should be one of ['kl', 'js']"
            )

        if reduction == "mean":
            loss = paddle.mean(loss, axis=[1, 2])
        elif reduction == "none" or reduction is None:
            return loss
        else:
            loss = paddle.sum(loss, axis=[1, 2])

        return loss


class DMLLoss(nn.Layer):
    """
    DMLLoss
    """

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Set the loss mode to exactly 'kl' or 'js' (case-insensitive) in the config/constructor
  2. Check the distillation config block that instantiates KLJSLoss and fix the mode key's value
  3. Strip/normalize the string if it comes from user input: mode.strip().lower() before passing

Example fix

# before
KLJSLoss(mode='jsd')   # ValueError at forward

# after
KLJSLoss(mode='js')
Defensive patterns

Strategy: validation

Validate before calling

mode = mode.strip().lower()
assert mode in ('kl', 'js'), f"KLJSLoss mode must be 'kl' or 'js', got {mode!r}"
loss = KLJSLoss(mode=mode)

Type guard

def is_kljs_mode(m: str) -> bool:
    return isinstance(m, str) and m.strip().lower() in ('kl', 'js')

Prevention

When it happens

Trigger: Constructing KLJSLoss(mode='kd') or any string other than 'kl'/'js' (in any casing) and calling its forward; typical in distillation configs where mode is chosen per loss item.

Common situations: Typo in a distillation YAML (model_name/loss config under Loss for DistillationModel), copying a mode name from another framework ('kld', 'jsd'), or trailing whitespace in the config string.

Related errors


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