PaddlePaddle/PaddleOCR · error · Exception

main_loss_type in BalanceLoss() can only be one of {}

Error message

main_loss_type in BalanceLoss() can only be one of {}

What it means

BalanceLoss dispatches its internal main loss on the main_loss_type string, supporting exactly 'CrossEntropy', 'DiceLoss', 'Euclidean', 'BCELoss' and 'MaskL1Loss'. Any other string raises a generic Exception listing the allowed values. This happens in __init__, so the error fires as soon as the loss layer is built.

Source

Thrown at ppocr/losses/det_basic_loss.py:74

        if self.main_loss_type == "CrossEntropy":
            self.loss = nn.CrossEntropyLoss()
        elif self.main_loss_type == "Euclidean":
            self.loss = nn.MSELoss()
        elif self.main_loss_type == "DiceLoss":
            self.loss = DiceLoss(self.eps)
        elif self.main_loss_type == "BCELoss":
            self.loss = BCELoss(reduction="none")
        elif self.main_loss_type == "MaskL1Loss":
            self.loss = MaskL1Loss(self.eps)
        else:
            loss_type = [
                "CrossEntropy",
                "DiceLoss",
                "Euclidean",
                "BCELoss",
                "MaskL1Loss",
            ]
            raise Exception(
                "main_loss_type in BalanceLoss() can only be one of {}".format(
                    loss_type
                )
            )

    def forward(self, pred, gt, mask=None):
        """
        The BalanceLoss for Differentiable Binarization text detection
        args:
            pred (variable): predicted feature maps.
            gt (variable): ground truth feature maps.
            mask (variable): masked maps.
        return: (variable) balanced loss
        """
        positive = gt * mask
        negative = (1 - gt) * mask

        positive_count = int(positive.sum())

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Use one of the five exact names: 'CrossEntropy', 'DiceLoss', 'Euclidean', 'BCELoss', 'MaskL1Loss'
  2. Fix the main_loss_type value in the detection config's BalanceLoss block (watch casing)
  3. If you need focal-style behavior, use balance_loss=True with BCELoss rather than inventing a type name

Example fix

# before
BalanceLoss(main_loss_type='bce')

# after
BalanceLoss(main_loss_type='BCELoss')
Defensive patterns

Strategy: validation

Validate before calling

BALANCE_LOSS_TYPES = {'CrossEntropy', 'DiceLoss', 'Euclidean', 'BCELoss', 'MaskL1Loss'}
assert main_loss_type in BALANCE_LOSS_TYPES, f'main_loss_type must be one of {sorted(BALANCE_LOSS_TYPES)}'

Type guard

def is_balance_loss_type(t: str) -> bool:
    return t in {'CrossEntropy', 'DiceLoss', 'Euclidean', 'BCELoss', 'MaskL1Loss'}

Prevention

When it happens

Trigger: BalanceLoss(main_loss_type='focal_loss'), 'bce' (wrong casing), or any unsupported name during model construction; commonly configured via the detection config's Loss section.

Common situations: Editing a DB/DB++ YAML and typing a lowercase or abbreviated loss name, or assuming a loss supported by another head (e.g. 'FocalLoss') is available here.

Related errors


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