Skip to content

Make DASC scalar analysis device independent - #2398

Merged
kaix-nv merged 2 commits into
feature/dasc-state-sparsity-review-real-scalarsfrom
feature/dasc-state-sparsity-review-device-independent
Sep 11, 2026
Merged

kaix-nv merged 2 commits into
feature/dasc-state-sparsity-review-real-scalarsfrom
feature/dasc-state-sparsity-review-device-independent

Conversation

@kaix-nv

@kaix-nv kaix-nv commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Addresses every finding on #2397:

  • compute the scalar log with math.log, avoiding ambient PyTorch default-device allocation entirely
  • explicitly reject booleans despite their numbers.Real inheritance
  • narrow normalization handlers to the reachable oversized-integer OverflowError
  • add boolean regressions through both public APIs
  • add a CPU-result regression under a non-CPU ambient default-device context

Validation

  • focused DASC suite: 51 passed, 1 optional Megatron skip
  • pre-commit hooks on all changed files
  • signed commit with DCO sign-off

Summary by CodeRabbit

  • Bug Fixes

    • Improved validation for sparsity analysis arguments, including rejection of boolean values.
    • Preserved expected error handling for invalid or non-finite inputs.
    • Ensured decay horizon calculations work correctly regardless of the ambient PyTorch device.
  • Tests

    • Expanded coverage for invalid boolean arguments and CPU-based horizon computation.

Signed-off-by: kaix-nv <kaix@nvidia.com>
@kaix-nv
kaix-nv requested review from a team as code owners September 11, 2026 04:32
@kaix-nv
kaix-nv requested review from kevalmorabia97 and removed request for a team September 11, 2026 04:32
@kaix-nv

kaix-nv commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

/claude review

@kaix-nv

kaix-nv commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

Warning

Review limit reached

Next included review available in 57 seconds.

Check out review usage here.

View limit details

Limit details: You’ve used all 12 included reviews currently available.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 0503c211-240f-45b9-8df5-47e8176ace85

📥 Commits

Reviewing files that changed from the base of the PR and between 81cc09e and 1dcafa5.

📒 Files selected for processing (2)
  • modelopt/torch/sparsity/state_sparsity/policy.py
  • tests/unit/torch/sparsity/state_sparsity/test_dasc.py

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 64bf4dd2-edc2-4823-afbe-494c2984f0ab

📥 Commits

Reviewing files that changed from the base of the PR and between c74facd and 81cc09e.

📒 Files selected for processing (3)
  • modelopt/torch/sparsity/state_sparsity/config.py
  • modelopt/torch/sparsity/state_sparsity/policy.py
  • tests/unit/torch/sparsity/state_sparsity/test_dasc.py

Included review availability: Your plan provides up to 12 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change tightens boolean argument validation and narrows exception handling. Decay-horizon computation now uses math.log. Tests cover invalid booleans and CPU output under a meta device context.

Changes

State sparsity behavior

Layer / File(s) Summary
Argument validation
modelopt/torch/sparsity/state_sparsity/config.py, tests/unit/torch/sparsity/state_sparsity/test_dasc.py
Validation rejects boolean epsilon and static_gate_input values. Tests cover boolean and boundary inputs.
Decay-horizon computation
modelopt/torch/sparsity/state_sparsity/policy.py, tests/unit/torch/sparsity/state_sparsity/test_dasc.py
Horizon calculation uses math.log(epsilon). Tests verify CPU tensor output under a meta device context.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 81cc0

The PR adds the intended boolean validation and CPU-safe scalar horizon computation without an identified merge-blocking risk.

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: making DASC scalar analysis device independent.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 3 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Security Anti-Patterns ✅ Passed PASS. The PR changes only two Python files under modelopt; no examples or dependency files changed. The diff adds validation logic and replaces a scalar PyTorch logarithm with math.log. No chang…
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/dasc-state-sparsity-review-device-independent

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

@claude claude 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.

Claude review — PR #2398 (Make DASC scalar analysis device independent)

Scope: full review. 3 files changed (26 additions / 8 deletions); reviewed all three — modelopt/torch/sparsity/state_sparsity/config.py, modelopt/torch/sparsity/state_sparsity/policy.py, and tests/unit/torch/sparsity/state_sparsity/test_dasc.py.

Findings: CRITICAL: 1, IMPORTANT: 0, SUGGESTION: 0

The two changes in this PR are correct on their own terms:

  • math.log(epsilon) / decay at policy.py:125 removes the last ambient-device allocation from compute_gdn_decay_horizons, keeps the float64 precision of the previous torch.log (both are C double), and now matches the already-scalar scale = -math.log(epsilon) in _storage_cast_horizon_bounds (policy.py:335) — so the two horizon paths are consistent. math is already imported at policy.py:22.
  • The not isinstance(..., bool) guards in _validate_analysis_arguments are the right fix: bool subclasses int, which is registered with numbers.Real, so True previously passed as epsilon (and 0.0 < True < 1.0 is False, so it happened to be rejected, but static_gate_input=True was silently accepted). Narrowing except (TypeError, ValueError, OverflowError) to except OverflowError holds for every reachable input, since non-Real types short-circuit at the isinstance check before math.isfinite is reached.
  • The torch.device("meta") regression genuinely exercises the fix — on the old code the ambient-device torch.tensor(epsilon) produced a meta result and not torch.isfinite(horizons).all() would have raised on the bool() conversion. It also runs on CPU-only CI.

[CRITICAL ModeState] modelopt/torch/sparsity/state_sparsity/policy.py:523 — the same ambient-default-device bug remains in the save/apply path

validate_dasc_decay_parameters still builds a tensor with an ambient-device factory call:

stored = torch.tensor(layer.static_horizons, dtype=torch.float64)

What the issue is. lower and upper come from _storage_cast_horizon_bounds, which explicitly forces .to(device="cpu", ...) and (after this PR) uses only scalar math.log, so both are unconditionally CPU float64. stored, by contrast, honors PyTorch's ambient default device. Under torch.set_default_device("cuda") — or inside a with torch.device(...) block, which is how HF and Megatron model construction/loading is commonly wrapped — stored lands on CUDA and the very next comparison

if torch.any(stored < lower * (1.0 - numerical_slack)) or torch.any(
    stored > upper * (1.0 + numerical_slack)
):

raises RuntimeError: Expected all tensors to be on the same device.

Why it matters. This is the same defect class the PR set out to eliminate, but on a path that is worse to break than the analysis helper:

  • conversion.py:122 calls it from update_dasc_metadata, guarded by except ApplyModeError. A device-mismatch RuntimeError is not an ApplyModeError, so it escapes the staleness-warning handler and propagates straight out of mto.save() / mto.modelopt_state(). Saving a DASC checkpoint fails hard instead of emitting the intended "re-run calibrate()" warning.
  • api.py:87 calls it on the calibrate/convert path, where it likewise turns into an unhandled RuntimeError.

Under a meta default device the failure mode is different but equally fatal: stored becomes a meta tensor and torch.any(...) cannot be converted to a Python bool.

Suggested fix — pin the tensor to CPU, matching the explicit device="cpu" convention used everywhere else in this module:

stored = torch.tensor(layer.static_horizons, dtype=torch.float64, device="cpu")

This is now the only remaining device-sensitive factory call in modelopt/torch/sparsity/state_sparsity/ (verified by grepping torch.tensor/zeros/ones/arange/empty/full/as_tensor across the sub-package), so fixing it completes the PR's stated goal.

It would also be worth extending the new regression beyond compute_gdn_decay_horizons — e.g. a calibrate() + mto.modelopt_state() round trip inside with torch.device("meta") (or torch.set_default_device) would have caught this line, whereas test_horizon_computation_ignores_the_default_device cannot reach it.


Risk assessment

Low risk as written, but the fix is incomplete. Nothing in the diff regresses existing behavior, and modelopt_state schema, mode registration, and public signatures are untouched, so there are no backward-compatibility or restore-fidelity concerns from the changed lines themselves. The single blocking item is the leftover ambient-device allocation on the save path — a one-line change that keeps the PR's device-independence guarantee from having a hole in the path users hit when they persist a DASC checkpoint.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 57 seconds.

@kaix-nv

kaix-nv commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the remaining full-package device-independence finding in #2399. validate_dasc_decay_parameters now creates stored horizons explicitly on CPU, and the regression runs both calibrate() and modelopt_state() under torch.device("meta"). A factory-call scan found no other ambient-device allocations in the state-sparsity package.

@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-09-11 04:50 UTC

@codecov

codecov Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.78%. Comparing base (c74facd) to head (1dcafa5).
⚠️ Report is 1 commits behind head on feature/dasc-state-sparsity-review-real-scalars.

Additional details and impacted files
@@                                 Coverage Diff                                  @@
##           feature/dasc-state-sparsity-review-real-scalars    #2398       +/-   ##
====================================================================================
+ Coverage                                            68.76%   78.78%   +10.02%     
====================================================================================
  Files                                                  548      548               
  Lines                                                64244    64243        -1     
====================================================================================
+ Hits                                                 44175    50615     +6440     
+ Misses                                               20069    13628     -6441     
Flag Coverage Δ
examples-diffusers 20.81% <0.00%> (+0.01%) ⬆️
examples-gpt-oss 13.39% <0.00%> (ø)
examples-hf_ptq 21.78% <0.00%> (+0.01%) ⬆️
examples-llm_distill 13.46% <0.00%> (ø)
examples-llm_eval 17.25% <0.00%> (+0.02%) ⬆️
examples-llm_qat 17.59% <0.00%> (+0.04%) ⬆️
examples-llm_sparsity 15.94% <0.00%> (ø)
examples-megatron_bridge 26.25% <0.00%> (+<0.01%) ⬆️
examples-specdec_bench 13.14% <0.00%> (ø)
examples-speculative_decoding 17.67% <0.00%> (+<0.01%) ⬆️
examples-torch_onnx 21.82% <0.00%> (+0.01%) ⬆️
examples-torch_trt 15.15% <0.00%> (+<0.01%) ⬆️
gpu 58.35% <0.00%> (+37.43%) ⬆️
regression 15.15% <0.00%> (ø)
unit 57.47% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

## Summary

Closes the remaining full-package device-independence finding on #2398:

- explicitly allocate stored policy horizons on CPU before comparing
with CPU bounds
- exercise calibration and `modelopt_state()` under a non-CPU ambient
default-device context
- retain the existing low-level horizon default-device regression

A full factory-call scan confirms this was the only remaining
ambient-device tensor allocation in `state_sparsity`.

## Validation

- focused DASC suite: 52 passed, 1 optional Megatron skip
- pre-commit hooks on both changed files
- signed commit with DCO sign-off

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved DASC calibration and checkpoint metadata generation when
PyTorch’s default device is set to `meta`.
* Ensured decay-parameter validation remains CPU-backed for reliable
processing.

* **Tests**
* Added regression coverage for CPU-backed DASC calibration and
checkpoint metadata.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: kaix-nv <kaix@nvidia.com>
@kaix-nv
kaix-nv merged commit e6da8d5 into feature/dasc-state-sparsity-review-real-scalars Sep 11, 2026
6 of 7 checks passed
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