{"record":{"id":"176430078ed9a5c8","repo":"PaddlePaddle/PaddleOCR","slug":"the-type-of-t-max2-in-cosineannealingdecay-mus","errorCode":null,"errorMessage":"The type of 'T_max2' in 'CosineAnnealingDecay' must be 'int', but received %s.","messagePattern":"The type of 'T_max2' in 'CosineAnnealingDecay' must be 'int', but received (.+?)\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ppocr/optimizer/lr_scheduler.py","lineNumber":178,"sourceCode":"                pct = (step_num - start_step) / (end_step - start_step)\n                computed_lr = self.anneal_func(phase[\"start_lr\"], phase[\"end_lr\"], pct)\n                break\n            start_step = phase[\"end_step\"]\n\n        return computed_lr\n\n\nclass TwoStepCosineDecay(LRScheduler):\n    def __init__(\n        self, learning_rate, T_max1, T_max2, eta_min=0, last_epoch=-1, verbose=False\n    ):\n        if not isinstance(T_max1, int):\n            raise TypeError(\n                \"The type of 'T_max1' in 'CosineAnnealingDecay' must be 'int', but received %s.\"\n                % type(T_max1)\n            )\n        if not isinstance(T_max2, int):\n            raise TypeError(\n                \"The type of 'T_max2' in 'CosineAnnealingDecay' must be 'int', but received %s.\"\n                % type(T_max2)\n            )\n        if not isinstance(eta_min, (float, int)):\n            raise TypeError(\n                \"The type of 'eta_min' in 'CosineAnnealingDecay' must be 'float, int', but received %s.\"\n                % type(eta_min)\n            )\n        assert T_max1 > 0 and isinstance(\n            T_max1, int\n        ), \" 'T_max1' must be a positive integer.\"\n        assert T_max2 > 0 and isinstance(\n            T_max2, int\n        ), \" 'T_max1' must be a positive integer.\"\n        self.T_max1 = T_max1\n        self.T_max2 = T_max2\n        self.eta_min = float(eta_min)\n        super(TwoStepCosineDecay, self).__init__(learning_rate, last_epoch, verbose)","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/ppocr/optimizer/lr_scheduler.py#L160-L196","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set T_max2 as an integer literal in the config file.","Coerce in code: T_max2=int(total_epochs - warm_epochs).","Double-check both T_max1 and T_max2 together, since each is validated independently."],"exampleFix":"# before\nTwoStepCosineDecay(learning_rate=lr, T_max1=270, T_max2=total_epochs - 270)  # float result\n\n# after\nTwoStepCosineDecay(learning_rate=lr, T_max1=270, T_max2=int(total_epochs - 270))","handlingStrategy":"type-guard","validationCode":"t_max2 = int(t_max2)  # coerce computed second-period values before construction","typeGuard":"def is_int_period(v) -> bool:\n    return isinstance(v, int) and not isinstance(v, bool)","tryCatchPattern":null,"preventionTips":["Apply int() to any arithmetic result passed as T_max1/T_max2.","Validate both periods together in a config pre-check helper."],"tags":["lr-scheduler","type-validation","config","training"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}