Skip to content

Guard LRRangeTest and OneCycle schedulers against zero step sizes#8166

Open
ebarkhordar wants to merge 1 commit into
deepspeedai:masterfrom
ebarkhordar:fix/lr-schedules-zero-step-guards
Open

Guard LRRangeTest and OneCycle schedulers against zero step sizes#8166
ebarkhordar wants to merge 1 commit into
deepspeedai:masterfrom
ebarkhordar:fix/lr-schedules-zero-step-guards

Conversation

@ebarkhordar

Copy link
Copy Markdown

Problem

Two learning-rate schedulers in deepspeed/runtime/lr_schedules.py divide by a step-size value taken directly from user config, with no validation, so a 0 step size crashes with a bare ZeroDivisionError instead of a clear configuration error:

  • LRRangeTest divides the step index by self.step_size in _continuous_interval / _staircase_interval. With lr_range_test_step_size=0 the first step() raises ZeroDivisionError.
  • OneCycle computes self.step_ratio = cycle_first_step_size / self.total_size in _initialize_cycle, where total_size = cycle_first_step_size + cycle_second_step_size. When both halves are 0, the constructor raises ZeroDivisionError.

Repro (CPU-only):

import torch
from deepspeed.runtime.lr_schedules import LRRangeTest, OneCycle

opt = lambda: torch.optim.SGD([torch.nn.Parameter(torch.zeros(1))], lr=0.1)

LRRangeTest(opt(), lr_range_test_step_size=0).step()          # ZeroDivisionError
OneCycle(opt(), cycle_min_lr=0.001, cycle_max_lr=0.1,
         cycle_first_step_size=0, cycle_second_step_size=0)   # ZeroDivisionError at construction

The sibling WarmupLR/WarmupCosineLR constructors already reject invalid warmup_num_steps this way (#8126, #8142, #8151); these two schedulers were skipped.

Fix

Validate at construction, before the division:

  • LRRangeTest.__init__: reject a non-positive lr_range_test_step_size with a ValueError, mirroring the existing warmup_num_steps guard exactly.
  • OneCycle._initialize_cycle: reject a non-positive total_size (cycle_first_step_size + cycle_second_step_size) with a ValueError.

No behavior change for valid configs: the guards only fire when the value is <= 0, which previously crashed (or, for a negative OneCycle total, produced a meaningless schedule).

Testing

Added CPU-only regression tests next to the existing scheduler-validation tests. They raise ZeroDivisionError (OneCycle) or silently accept the misconfig (LRRangeTest) on current master, and pass with this change:

pytest tests/unit/runtime/test_lr_schedulers.py -k "nonpositive or warmup_cosine or reject_invalid"
15 passed, 45 deselected

yapf, flake8, codespell clean via pre-commit run. DCO signed off.

LRRangeTest divides the step index by self.step_size and OneCycle divides
cycle_first_step_size by total_size (first + second step size), both taken
unvalidated from user config. A zero step size raises a bare ZeroDivisionError
instead of a clear configuration error. Reject a non-positive step size at
construction with a ValueError, mirroring the existing warmup_num_steps guards
(deepspeedai#8126, deepspeedai#8142, deepspeedai#8151). Valid configs are unaffected.

Signed-off-by: Ehsan Barkhordar <realbarkhordar@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1673e819f8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

cycle_second_step_size) if cycle_second_step_size is not None else cycle_first_step_size

self.total_size = cycle_first_step_size + cycle_second_step_size
if self.total_size <= 0:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject zero first cycle step independently

When cycle_first_step_size=0 and cycle_second_step_size is positive, this sum-only check passes because total_size > 0, but self.step_ratio becomes 0. A get_lr() call before the first step() then enters _get_scale_factor() with x == 0 and evaluates x / self.step_ratio, raising the same ZeroDivisionError this guard is meant to prevent; DeepSpeed already exercises pre-training get_lr() via TestGetLrBeforeTrain. Please reject a zero first-step size separately, or explicitly handle a zero-length warm-up half.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant