{"record":{"id":"e2d0a42eb19bfad3","repo":"PaddlePaddle/PaddleOCR","slug":"expected-positive-integer-epochs-but-got","errorCode":null,"errorMessage":"Expected positive integer epochs, but got {}","messagePattern":"Expected positive integer epochs, but got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"ppocr/optimizer/lr_scheduler.py","lineNumber":70,"sourceCode":"    Code referred in https://pytorch.org/docs/stable/_modules/torch/optim/lr_scheduler.html#OneCycleLR\n    \"\"\"\n\n    def __init__(\n        self,\n        max_lr,\n        epochs=None,\n        steps_per_epoch=None,\n        pct_start=0.3,\n        anneal_strategy=\"cos\",\n        div_factor=25.0,\n        final_div_factor=1e4,\n        three_phase=False,\n        last_epoch=-1,\n        verbose=False,\n    ):\n        # Validate total_steps\n        if epochs <= 0 or not isinstance(epochs, int):\n            raise ValueError(\n                \"Expected positive integer epochs, but got {}\".format(epochs)\n            )\n        if steps_per_epoch <= 0 or not isinstance(steps_per_epoch, int):\n            raise ValueError(\n                \"Expected positive integer steps_per_epoch, but got {}\".format(\n                    steps_per_epoch\n                )\n            )\n        self.total_steps = epochs * steps_per_epoch\n\n        self.max_lr = max_lr\n        self.initial_lr = self.max_lr / div_factor\n        self.min_lr = self.initial_lr / final_div_factor\n\n        if three_phase:\n            self._schedule_phases = [\n                {\n                    \"end_step\": float(pct_start * self.total_steps) - 1,","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/ppocr/optimizer/lr_scheduler.py#L52-L88","documentation":"The one-cycle-style LR scheduler (CosineAnnealing/OneCycle port in lr_scheduler.py) derives total_steps = epochs * steps_per_epoch and requires both to be positive ints. If epochs <= 0 or is not an int (e.g. 0 from an unset config, or a float like 10.0), it raises this ValueError at scheduler construction.","triggerScenarios":"Building the optimizer with lr_scheduler where the epochs field is 0, negative, a float, or a string parsed from YAML/CLI that was never converted to int.","commonSituations":"Global configs (PaddleOCR train yamls) missing epoch num so it defaults to 0; computing epochs as len(train_samples)/batch (float division); passing epochs: 100.0 from a hyperparameter search tool.","solutions":["Set a positive integer epochs in the optimizer/scheduler config (e.g. epochs: 200)","Coerce before constructing: epochs = int(epochs) and validate epochs > 0","If epochs come from a computed value, wrap with max(1, int(round(epochs)))"],"exampleFix":"# before\nlr = decay(..., epochs=len(dataset)/batch_size)  # float\n# after\nepochs = max(1, int(round(len(dataset)/batch_size)))\nlr = decay(..., epochs=epochs)","handlingStrategy":"validation","validationCode":"epochs = int(epochs)\nassert isinstance(epochs, int) and epochs > 0, f'epochs must be a positive int, got {epochs!r}'","typeGuard":"def valid_epochs(e) -> bool:\n    return isinstance(e, int) and not isinstance(e, bool) and e > 0","tryCatchPattern":null,"preventionTips":["Int-cast computed epoch counts before scheduler construction","Fail fast on missing epoch config with a clear message at CLI parse time"],"tags":["paddle","lr-scheduler","config","type-error"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}