Skip to content

Conversation

@ytl0623
Copy link
Contributor

@ytl0623 ytl0623 commented Nov 5, 2025

Fixes #8600

Description

The np.linspace approach generates a descending array that starts exactly at 999 and ends exactly at 0 (after rounding), ensuring the scheduler samples the entire intended trajectory.

Types of changes

  • Non-breaking change (fix or new feature that would not break existing functionality).
  • Breaking change (fix or new feature that would cause existing functionality to change).
  • New tests added to cover the changes.
  • Integration tests passed locally by running ./runtests.sh -f -u --net --coverage.
  • Quick tests passed locally by running ./runtests.sh --quick --unittests --disttests.
  • In-line docstrings updated.
  • Documentation updated, tested make html command in the docs/ folder.

@ytl0623 ytl0623 requested a review from virginiafdez as a code owner November 5, 2025 08:51
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 5, 2025

Walkthrough

The diff changes how DDPM and DDIM compute inference timesteps in set_timesteps: instead of using np.arange * step_ratio, they use numpy.linspace from (num_train_timesteps - 1) down to 0 with num_inference_steps, round and cast to int64, then convert to a torch tensor. DDIM also adds validation for steps_offset to be within [0, num_train_timesteps). Public APIs remain unchanged. The selected discrete timesteps and their ordering are altered and the endpoint is ensured to be included.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Two files with similar but not identical changes (DDPM and DDIM); DDIM includes additional validation logic.
  • Single-area numerical logic change but affects timestep selection semantics and ordering.

Areas to review:

  • Behavior for edge cases: num_inference_steps = 1, equal to num_train_timesteps, very large values.
  • Correct inclusion of endpoints and expected rounding behavior across ranges.
  • Interaction with steps_offset (DDIM) and any downstream code that depends on previous timestep ordering.

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title directly summarizes the main change: replacing timestep computation with np.linspace approach in scheduler files.
Description check ✅ Passed Description matches template structure with issue reference, clear explanation of changes, and completed checklist; non-critical sections like tests/docs unmarked but acceptable.
Linked Issues check ✅ Passed PR successfully addresses issue #8600 by replacing ratio-based timestep computation with np.linspace to ensure timesteps reach endpoint (999 instead of 990).
Out of Scope Changes check ✅ Passed Changes are narrowly scoped to timestep computation in DDPM and DDIM schedulers as required by issue #8600; no extraneous modifications detected.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
monai/networks/schedulers/ddim.py (1)

120-126: Validation logic is now incorrect with linspace approach.

step_ratio is no longer used in timestep generation (line 130 uses linspace). The validation at lines 121-126 incorrectly assumes step_ratio spacing. With linspace starting at num_train_timesteps - 1, the constraint should prevent steps_offset from causing timesteps to exceed valid indices [0, num_train_timesteps - 1].

Required fix: replace the validation to ensure steps_offset < 1 when using linspace from num_train_timesteps - 1, or adjust the linspace start point to accommodate the offset.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between e72145c and b96ec40.

📒 Files selected for processing (2)
  • monai/networks/schedulers/ddim.py (1 hunks)
  • monai/networks/schedulers/ddpm.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

⚙️ CodeRabbit configuration file

Review the Python code for quality and correctness. Ensure variable names adhere to PEP8 style guides, are sensible and informative in regards to their function, though permitting simple names for loop and comprehension variables. Ensure routine names are meaningful in regards to their function and use verbs, adjectives, and nouns in a semantically appropriate way. Docstrings should be present for all definition which describe each variable, return value, and raised exception in the appropriate section of the Google-style of docstrings. Examine code for logical error or inconsistencies, and suggest what may be changed to addressed these. Suggest any enhancements for code improving efficiency, maintainability, comprehensibility, and correctness. Ensure new or modified definitions will be covered by existing or new unit tests.

Files:

  • monai/networks/schedulers/ddpm.py
  • monai/networks/schedulers/ddim.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: min-dep-pytorch (2.7.1)
  • GitHub Check: min-dep-pytorch (2.8.0)
  • GitHub Check: min-dep-py3 (3.11)
  • GitHub Check: min-dep-pytorch (2.6.0)
  • GitHub Check: min-dep-py3 (3.12)
  • GitHub Check: min-dep-pytorch (2.5.1)
  • GitHub Check: min-dep-os (windows-latest)
  • GitHub Check: min-dep-py3 (3.9)
  • GitHub Check: min-dep-os (ubuntu-latest)
  • GitHub Check: min-dep-py3 (3.10)
  • GitHub Check: min-dep-os (macOS-latest)
  • GitHub Check: quick-py3 (ubuntu-latest)
  • GitHub Check: quick-py3 (windows-latest)
  • GitHub Check: quick-py3 (macOS-latest)
  • GitHub Check: flake8-py3 (mypy)
  • GitHub Check: build-docs
  • GitHub Check: packaging
  • GitHub Check: flake8-py3 (codeformat)
  • GitHub Check: flake8-py3 (pytype)
🔇 Additional comments (2)
monai/networks/schedulers/ddpm.py (1)

128-129: Fix correctly addresses the endpoint issue and tests pass.

The linspace approach generates timesteps from num_train_timesteps - 1 to 0, ensuring both endpoints are included and all values are valid array indices for the alpha arrays used in the step() method. Existing tests verify functionality and error handling.

monai/networks/schedulers/ddim.py (1)

179-179: Spacing assumption needs verification.

The concern is valid: self.timesteps uses linspace with rounding (line 130), creating non-uniform gaps. Fixed offset arithmetic (line 179: timestep - step_ratio) doesn't guarantee alignment with actual previous scheduled timestep. If gaps vary, prev_timestep may misalign, causing incorrect alpha lookups.

However, impact on diffusion quality (whether approximation is acceptable per DDIM paper or requires dynamic lookup from self.timesteps) requires verification against:

  • Reference DDIM implementations (HuggingFace, Stable Diffusion, etc.)
  • Whether existing tests catch quality degradation

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
monai/networks/schedulers/ddim.py (1)

121-126: Validation logic is incorrect for the new implementation.

With the linspace approach, max_timestep = (num_train_timesteps - 1 - steps_offset) + steps_offset = num_train_timesteps - 1 regardless of the relationship between steps_offset and step_ratio. The actual constraint is 0 <= steps_offset < num_train_timesteps.

Apply this diff:

-        step_ratio = self.num_train_timesteps // self.num_inference_steps
-        if self.steps_offset >= step_ratio:
+        if self.steps_offset < 0 or self.steps_offset >= self.num_train_timesteps:
             raise ValueError(
-                f"`steps_offset`: {self.steps_offset} cannot be greater than or equal to "
-                f"`num_train_timesteps // num_inference_steps : {step_ratio}` as this will cause timesteps to exceed"
-                f" the max train timestep."
+                f"`steps_offset`: {self.steps_offset} must be in range [0, {self.num_train_timesteps})."
             )
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 3a2ffc5 and f7ca165.

📒 Files selected for processing (2)
  • monai/networks/schedulers/ddim.py (1 hunks)
  • monai/networks/schedulers/ddpm.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • monai/networks/schedulers/ddpm.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

⚙️ CodeRabbit configuration file

Review the Python code for quality and correctness. Ensure variable names adhere to PEP8 style guides, are sensible and informative in regards to their function, though permitting simple names for loop and comprehension variables. Ensure routine names are meaningful in regards to their function and use verbs, adjectives, and nouns in a semantically appropriate way. Docstrings should be present for all definition which describe each variable, return value, and raised exception in the appropriate section of the Google-style of docstrings. Examine code for logical error or inconsistencies, and suggest what may be changed to addressed these. Suggest any enhancements for code improving efficiency, maintainability, comprehensibility, and correctness. Ensure new or modified definitions will be covered by existing or new unit tests.

Files:

  • monai/networks/schedulers/ddim.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: min-dep-pytorch (2.8.0)
  • GitHub Check: min-dep-py3 (3.12)
  • GitHub Check: min-dep-os (windows-latest)
  • GitHub Check: min-dep-pytorch (2.7.1)
  • GitHub Check: min-dep-os (ubuntu-latest)
  • GitHub Check: min-dep-os (macOS-latest)
  • GitHub Check: min-dep-py3 (3.9)
  • GitHub Check: min-dep-py3 (3.11)
  • GitHub Check: min-dep-pytorch (2.6.0)
  • GitHub Check: min-dep-py3 (3.10)
  • GitHub Check: min-dep-pytorch (2.5.1)
  • GitHub Check: flake8-py3 (pytype)
  • GitHub Check: packaging
  • GitHub Check: flake8-py3 (mypy)
  • GitHub Check: quick-py3 (macOS-latest)
  • GitHub Check: quick-py3 (windows-latest)
  • GitHub Check: quick-py3 (ubuntu-latest)
  • GitHub Check: build-docs
  • GitHub Check: flake8-py3 (codeformat)
🔇 Additional comments (1)
monai/networks/schedulers/ddim.py (1)

128-130: Correctly fixes the endpoint issue.

The subtract-then-add pattern ensures max timestep = num_train_timesteps - 1 and min timestep = steps_offset, keeping all indices valid. The linspace approach guarantees the endpoint is reached.

… steps_offset) + steps_offset = num_train_timesteps - 1 regardless of the relationship between steps_offset and step_ratio. The actual constraint is 0 <= steps_offset < num_train_timesteps.

Signed-off-by: ytl0623 <[email protected]>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
monai/networks/schedulers/ddim.py (1)

120-121: Validation logic is correct.

The range check ensures the linspace start is non-negative and the final max timestep stays at num_train_timesteps - 1.

Static analysis suggests defining a custom exception or shortening the message to comply with TRY003, though this is a minor style concern.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between f7ca165 and ef7e83c.

📒 Files selected for processing (1)
  • monai/networks/schedulers/ddim.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

⚙️ CodeRabbit configuration file

Review the Python code for quality and correctness. Ensure variable names adhere to PEP8 style guides, are sensible and informative in regards to their function, though permitting simple names for loop and comprehension variables. Ensure routine names are meaningful in regards to their function and use verbs, adjectives, and nouns in a semantically appropriate way. Docstrings should be present for all definition which describe each variable, return value, and raised exception in the appropriate section of the Google-style of docstrings. Examine code for logical error or inconsistencies, and suggest what may be changed to addressed these. Suggest any enhancements for code improving efficiency, maintainability, comprehensibility, and correctness. Ensure new or modified definitions will be covered by existing or new unit tests.

Files:

  • monai/networks/schedulers/ddim.py
🪛 Ruff (0.14.3)
monai/networks/schedulers/ddim.py

121-121: Avoid specifying long messages outside the exception class

(TRY003)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: min-dep-pytorch (2.7.1)
  • GitHub Check: flake8-py3 (codeformat)
  • GitHub Check: quick-py3 (macOS-latest)
  • GitHub Check: flake8-py3 (pytype)
  • GitHub Check: min-dep-py3 (3.9)
  • GitHub Check: min-dep-pytorch (2.8.0)
  • GitHub Check: quick-py3 (windows-latest)
  • GitHub Check: min-dep-os (macOS-latest)
  • GitHub Check: min-dep-os (ubuntu-latest)
  • GitHub Check: min-dep-py3 (3.11)
  • GitHub Check: min-dep-pytorch (2.6.0)
  • GitHub Check: min-dep-py3 (3.12)
  • GitHub Check: min-dep-pytorch (2.5.1)
  • GitHub Check: min-dep-os (windows-latest)
  • GitHub Check: flake8-py3 (mypy)
  • GitHub Check: build-docs
  • GitHub Check: packaging
  • GitHub Check: quick-py3 (ubuntu-latest)
  • GitHub Check: min-dep-py3 (3.10)
🔇 Additional comments (1)
monai/networks/schedulers/ddim.py (1)

123-129: Timestep computation is correct and validated by tests.

The linspace approach with rounding produces nearly-uniform spacing (gaps of 10–11). The step() method's prev_timestep approximation (gap = num_train_timesteps // num_inference_steps) works correctly despite minor non-uniformity. The test_full_timestep_loop test validates numerical correctness end-to-end, confirming alphas_cumprod indexing is sound.

@ytl0623
Copy link
Contributor Author

ytl0623 commented Nov 6, 2025

Hi @virginiafdez, @KumoLiu, @Nic-Ma and @ericspod,

Sorry to bother.
Could you please review the PR or give some tips?

Thanks in advance!

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.

timesteps in set_timesteps of DDPM and DDIM schedulers doesn't reach end point T (e.g. T= 1000)

1 participant