PaddlePaddle/PaddleOCR · error · TypeError

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

Error message

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

What it means

TypeError from TwoStepCosineDecay.__init__ when T_max1 is not a Python int. The scheduler validates its period arguments strictly with isinstance(T_max1, int), so floats (even whole-valued like 300.0), strings, or numpy float scalars are rejected.

Source

Thrown at ppocr/optimizer/lr_scheduler.py:173

            )
        start_step = 0
        for i, phase in enumerate(self._schedule_phases):
            end_step = phase["end_step"]
            if step_num <= end_step or i == len(self._schedule_phases) - 1:
                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

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Write T_max1 as a plain integer in the config (T_max1: 300, not 300.0).
  2. Coerce computed values in code: TwoStepCosineDecay(lr, T_max1=int(t1), T_max2=int(t2)).
  3. If a fractional period is genuinely needed, round to the nearest int first and document the approximation.

Example fix

# before
TwoStepCosineDecay(learning_rate=lr, T_max1=epochs * 0.9, T_max2=30)  # float -> TypeError

# after
TwoStepCosineDecay(learning_rate=lr, T_max1=int(epochs * 0.9), T_max2=30)
Defensive patterns

Strategy: type-guard

Validate before calling

t_max1 = int(t_max1)  # coerce before construction; raises a clear TypeError here if non-numeric

Type guard

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

Prevention

When it happens

Trigger: Configuring a two-stage cosine decay schedule (e.g. for ViT/STR-style recognition training) with T_max1: 300.0 in YAML, or passing a computed float (epochs * something) or a string from a CLI into TwoStepCosineDecay.

Common situations: YAML configs where the value carries a decimal point; values computed with '/' in Python producing floats; JSON configs deserialized with float types; copying values from documentation that shows fractional epoch counts.

Related errors


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