PaddlePaddle/PaddleOCR · error · TypeError

The type of 'T_max2' in 'CosineAnnealingDecay' must be 'int'

Error message

The type of 'T_max2' in 'CosineAnnealingDecay' must be 'int', but received %s.

What it means

TypeError from TwoStepCosineDecay.__init__ when T_max2 (the second cosine period) is not a Python int. Same strict isinstance check as T_max1: floats, strings, and non-int numerics are rejected before the scheduler stores the value.

Source

Thrown at ppocr/optimizer/lr_scheduler.py:178

                pct = (step_num - start_step) / (end_step - start_step)
                computed_lr = self.anneal_func(phase["start_lr"], phase["end_lr"], pct)
                break
            start_step = phase["end_step"]

        return computed_lr


class TwoStepCosineDecay(LRScheduler):
    def __init__(
        self, learning_rate, T_max1, T_max2, eta_min=0, last_epoch=-1, verbose=False
    ):
        if not isinstance(T_max1, int):
            raise TypeError(
                "The type of 'T_max1' in 'CosineAnnealingDecay' must be 'int', but received %s."
                % type(T_max1)
            )
        if not isinstance(T_max2, int):
            raise TypeError(
                "The type of 'T_max2' in 'CosineAnnealingDecay' must be 'int', but received %s."
                % type(T_max2)
            )
        if not isinstance(eta_min, (float, int)):
            raise TypeError(
                "The type of 'eta_min' in 'CosineAnnealingDecay' must be 'float, int', but received %s."
                % type(eta_min)
            )
        assert T_max1 > 0 and isinstance(
            T_max1, int
        ), " 'T_max1' must be a positive integer."
        assert T_max2 > 0 and isinstance(
            T_max2, int
        ), " 'T_max1' must be a positive integer."
        self.T_max1 = T_max1
        self.T_max2 = T_max2
        self.eta_min = float(eta_min)
        super(TwoStepCosineDecay, self).__init__(learning_rate, last_epoch, verbose)

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Set T_max2 as an integer literal in the config file.
  2. Coerce in code: T_max2=int(total_epochs - warm_epochs).
  3. Double-check both T_max1 and T_max2 together, since each is validated independently.

Example fix

# before
TwoStepCosineDecay(learning_rate=lr, T_max1=270, T_max2=total_epochs - 270)  # float result

# after
TwoStepCosineDecay(learning_rate=lr, T_max1=270, T_max2=int(total_epochs - 270))
Defensive patterns

Strategy: type-guard

Validate before calling

t_max2 = int(t_max2)  # coerce computed second-period values before construction

Type guard

def is_int_period(v) -> bool:
    return isinstance(v, int) and not isinstance(v, bool)

Prevention

When it happens

Trigger: Building TwoStepCosineDecay with T_max2: 50.0 from config, a float computed at runtime, or a string argument; T_max1 passes validation but T_max2 does not.

Common situations: Asymmetric decay configs where T_max2 is derived by subtraction/division of epoch counts; YAML values with decimals; mixed configs where one period was fixed to int and the other left as a computed float.

Related errors


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