PaddlePaddle/PaddleOCR · error · ValueError

anneal_strategy must by one of 'cos' or 'linear', instead go

Error message

anneal_strategy must by one of 'cos' or 'linear', instead got {}

What it means

Thrown by OneCycleDecay.__init__ when anneal_strategy is not exactly 'cos' or 'linear'. The string comparison is case-sensitive with no normalization, so any other spelling, casing, or whitespace causes the ValueError before the scheduler is built.

Source

Thrown at ppocr/optimizer/lr_scheduler.py:125

                    "start_lr": self.initial_lr,
                    "end_lr": self.max_lr,
                },
                {
                    "end_step": self.total_steps - 1,
                    "start_lr": self.max_lr,
                    "end_lr": self.min_lr,
                },
            ]

        # Validate pct_start
        if pct_start < 0 or pct_start > 1 or not isinstance(pct_start, float):
            raise ValueError(
                "Expected float between 0 and 1 pct_start, but got {}".format(pct_start)
            )

        # Validate anneal_strategy
        if anneal_strategy not in ["cos", "linear"]:
            raise ValueError(
                "anneal_strategy must by one of 'cos' or 'linear', instead got {}".format(
                    anneal_strategy
                )
            )
        elif anneal_strategy == "cos":
            self.anneal_func = self._annealing_cos
        elif anneal_strategy == "linear":
            self.anneal_func = self._annealing_linear

        super(OneCycleDecay, self).__init__(max_lr, last_epoch, verbose)

    def _annealing_cos(self, start, end, pct):
        "Cosine anneal from `start` to `end` as pct goes from 0.0 to 1.0."
        cos_out = math.cos(math.pi * pct) + 1
        return end + (start - end) / 2.0 * cos_out

    def _annealing_linear(self, start, end, pct):
        "Linearly anneal from `start` to `end` as pct goes from 0.0 to 1.0."

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Set anneal_strategy to the exact lowercase string 'cos' or 'linear' in the scheduler config block.
  2. Check for invisible whitespace/case issues if the value is generated programmatically: anneal_strategy.strip().lower().
  3. Consult the OneCycleDecay docstring/config template for the accepted values before editing.

Example fix

# before
Optimizer:
  scheduler:
    name: OneCycleDecay
    anneal_strategy: cosine  # rejected

# after
Optimizer:
  scheduler:
    name: OneCycleDecay
    anneal_strategy: cos
Defensive patterns

Strategy: validation

Validate before calling

ANNEAL_STRATEGIES = {"cos", "linear"}
strategy = cfg['Optimizer']['scheduler'].get('anneal_strategy', 'cos').strip().lower()
assert strategy in ANNEAL_STRATEGIES, f"anneal_strategy must be one of {ANNEAL_STRATEGIES}, got {strategy!r}"

Type guard

def is_valid_anneal_strategy(v) -> bool:
    return isinstance(v, str) and v.strip().lower() in {"cos", "linear"}

Prevention

When it happens

Trigger: Setting scheduler.anneal_strategy in the training config to anything other than the exact lowercase strings 'cos' or 'linear', e.g. 'Cos', 'cosine', 'lin', or a value with trailing whitespace.

Common situations: Copy-pasted configs from tutorials that use PyTorch/fastai vocabulary ('cosine'), typos, or uppercase values from templating. Paddle's own CosineAnnealingDecay configs often lead users to write 'cosine' here.

Related errors


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