geekcomputers/Python · error · ValueError
Expected non-negative epoch, but got {}
Error message
Expected non-negative epoch, but got {} What it means
This ValueError is raised by the cosine-annealing-with-warm-restarts scheduler's step(epoch) when an explicit negative epoch value is passed. When epoch is not None the scheduler computes the position within the annealing cycle directly from it, so a negative epoch has no meaningful interpretation and is rejected before the logarithmic restart math runs.
Source
Thrown at ML/src/python/neuralforge/optim/schedulers.py:50
self.T_i = T_0
super().__init__(optimizer, last_epoch)
def get_lr(self):
return [
self.eta_min + (base_lr - self.eta_min) * (1 + math.cos(math.pi * self.T_cur / self.T_i)) / 2
for base_lr in self.base_lrs
]
def step(self, epoch=None):
if epoch is None:
epoch = self.last_epoch + 1
self.T_cur = self.T_cur + 1
if self.T_cur >= self.T_i:
self.T_cur = self.T_cur - self.T_i
self.T_i = self.T_i * self.T_mult
else:
if epoch < 0:
raise ValueError("Expected non-negative epoch, but got {}".format(epoch))
if epoch >= self.T_0:
if self.T_mult == 1:
self.T_cur = epoch % self.T_0
else:
n = int(math.log((epoch / self.T_0 * (self.T_mult - 1) + 1), self.T_mult))
self.T_cur = epoch - self.T_0 * (self.T_mult ** n - 1) / (self.T_mult - 1)
self.T_i = self.T_0 * self.T_mult ** n
else:
self.T_i = self.T_0
self.T_cur = epoch
self.last_epoch = math.floor(epoch)
for param_group, lr in zip(self.optimizer.param_groups, self.get_lr()):
param_group['lr'] = lr
class OneCycleLR(_LRScheduler):
def __init__(self, optimizer, max_lr, total_steps, pct_start=0.3, anneal_strategy='cos',View on GitHub (pinned to 40f4cd2652)
Solutions
- Pass a non-negative epoch, or call scheduler.step() with no argument to let the scheduler track epochs internally
- If computing epoch = step - warmup_steps, clamp it with max(0, step - warmup_steps)
- Verify checkpoint-resume logic restores the epoch counter to the correct non-negative value
Example fix
# before
for step, batch in enumerate(loader):
scheduler.step(step - warmup_steps) # negative during warmup
# after
for step, batch in enumerate(loader):
if step >= warmup_steps:
scheduler.step(step - warmup_steps)
else:
scheduler.step() Defensive patterns
Strategy: validation
Validate before calling
epoch = max(0, global_step - warmup_steps) scheduler.step(epoch) # or simply: scheduler.step() # internal epoch tracking
Try / catch
try:
scheduler.step(epoch)
except ValueError as e:
if 'non-negative epoch' in str(e):
scheduler.step() # fall back to internal counting
else:
raise Prevention
- Prefer calling scheduler.step() with no argument unless you need manual control
- Clamp computed epochs with max(0, ...) during warmup phases
- Test resume-from-checkpoint paths for off-by-one epoch values
When it happens
Trigger: Calling scheduler.step(epoch) with epoch=-1, or with a variable that can go negative such as epoch = step_count - warmup_steps before warmup completes, or epoch derived from len(loader) arithmetic that underflows early in training.
Common situations: Custom training loops that pass a raw global step or epoch counter that starts negative (e.g., during a warmup phase), off-by-one errors when computing epochs after resume from checkpoint, or off-by-one when epoch is derived from a zero-based loop index minus an offset.
Related errors
- Please give a integer
- Your integer should bigger than 0
- Invalid beta parameter at index 0: {betas[0]}
- Invalid beta parameter at index 1: {betas[1]}
- AdamW does not support sparse gradients
AI-assisted analysis of geekcomputers/Python@40f4cd2652 (2026-08-27).
Data as JSON: /api/errors/538ec2276e60505e.
Report an issue: GitHub.