Skip to content

Clarify DASC layer validation - #2385

Closed
kaix-nv wants to merge 2 commits into
feature/dasc-state-sparsity-complete-layersfrom
feature/dasc-state-sparsity-validation-helpers
Closed

kaix-nv wants to merge 2 commits into
feature/dasc-state-sparsity-complete-layersfrom
feature/dasc-state-sparsity-validation-helpers

Conversation

@kaix-nv

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

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #2384 addressing its complete Claude review:

  • move incomplete-layer and unconverted-subclass checks into named fail-closed helpers
  • remove the redundant identity-module dict alias
  • anchor malformed-layer diagnostics to the exact offending path
  • add a mixed valid-plus-unconverted-subclass regression
  • document that both mixed malformed cases are intentionally rejected

This PR is intentionally stacked on #2384 because repository rules protect a PR head branch after creation.

Validation

  • focused DASC suite: 23 passed, 1 absent optional Megatron skip
  • DASC plus weight sparsity plus attention sparsity compatibility suite: 134 passed, 1 optional skip
  • DASC package coverage: 408/408 statements, 100%
  • full pre-commit on touched files: passed

Summary by CodeRabbit

  • Bug Fixes

    • Improved validation for GDN modules during sparsity policy processing.
    • Clear errors now identify missing tensor values and unsupported subclasses that require conversion.
    • Diagnostics include affected module paths and remediation guidance.
    • Module processing order is now deterministic.
  • Tests

    • Expanded coverage for missing tensors, unsupported subclasses, and mixed valid and stale modules.

Signed-off-by: Kai Xu <kaix@nvidia.com>
@kaix-nv
kaix-nv requested review from a team as code owners September 11, 2026 02:41
@kaix-nv
kaix-nv requested review from realAsma and removed request for a team September 11, 2026 02:41
@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

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: c0f33af6-7d1a-4450-9c5b-c0c8fd8f6946

📥 Commits

Reviewing files that changed from the base of the PR and between 2da09a6 and 1b2d494.

📒 Files selected for processing (1)
  • modelopt/torch/sparsity/state_sparsity/policy.py

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


📝 Walkthrough

Walkthrough

The GDN module discovery path validates required tensors and supported module identities before policy processing. Tests verify module paths and conversion guidance in resulting errors.

Changes

GDN validation

Layer / File(s) Summary
Validate GDN modules before policy processing
modelopt/torch/sparsity/state_sparsity/policy.py, tests/unit/torch/sparsity/state_sparsity/test_dasc.py
The policy rejects recognized GDN modules without tensor-valued A_log or dt_bias. It rejects unconverted ordinary subclasses of supported GDN classes. Module collection remains sorted. Tests verify module paths and conversion guidance in error messages.

Priority: ⬇️ Low

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

Merge Risk: ⚪ Minimal · up to 1b2d4

The GDN validation changes are covered by focused regression tests and required checks, with no remaining merge-blocking risk identified.

🚥 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: improved DASC layer validation, including clearer rejection checks and diagnostics.
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 6 functions across 2 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 authoritative PR diff changes only modelopt/torch/sparsity/state_sparsity/policy.py and a test file. The source diff adds no torch.load(..., weights_only=False), `numpy.load(..., allow_p…
✨ 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-validation-helpers

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

@kaix-nv

kaix-nv commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

/claude review

)
raise ApplyModeError(f"DASC found no supported GDN modules; expected one of: {supported}")
return dict(sorted(modules.items()))
return dict(sorted(identity_modules))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[SUGGESTION] Sorting the raw (name, module) tuples makes the sort key implicitly include the module.

Previously this was dict(sorted(modules.items())), where modules = dict(identity_modules) had already collapsed names, so only strings were ever compared. Now sorted() operates on tuples, and if two entries ever shared a name Python would fall through to comparing the second elements — nn.Module defines no ordering, so that raises TypeError: '<' not supported between instances of 'GatedDeltaNet' and 'GatedDeltaNet' instead of the intended ApplyModeError.

This is unreachable today: named_modules() defaults to remove_duplicate=True and yields unique qualified paths, so no tie can occur. Purely defensive — sorting on the name explicitly keeps the key intent obvious and immune to the comparison fallback, without reintroducing the dict alias this PR removed.

Suggested change
return dict(sorted(identity_modules))
return dict(sorted(identity_modules, key=lambda item: item[0]))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in #2386. The sort now uses an explicit qualified-name key, so it cannot fall through to comparing nn.Module objects even under a hypothetical duplicate-name input.

@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 passed — no blocking issues found. LGTM

Scope

Full review — the trigger comment was a bare /claude review. Both changed files opened (modelopt/torch/sparsity/state_sparsity/policy.py, tests/unit/torch/sparsity/state_sparsity/test_dasc.py), plus surrounding context in policy.py (_has_supported_gdn_identity, compute_gdn_decay_horizons, _analyze_gdn_modules) to confirm the extraction is semantics-preserving.

Findings

  • CRITICAL: 0
  • IMPORTANT: 0
  • SUGGESTION: 1

Assessment

Risk: low. This is a pure internal refactor plus one regression test. No mode registration, modelopt_state schema, config field, public __init__.py export, or export path is touched, so there are no composability, restore-fidelity, or backward-compatibility concerns to weigh.

The extraction into _reject_incomplete_gdn_modules and _reject_unconverted_gdn_subclasses preserves behavior exactly:

  • Check order is unchanged — incomplete-decay-tensor rejection still fires before the unconverted-subclass rejection, which still fires before the empty-identity_modules ApplyModeError. A model malformed in both ways reports the same message it did before.
  • Predicates are identical to the inlined versions, including the name or "<root>" fallback and the __mro__[1:] slice that lets an exact supported class pass the subclass check.
  • The dropped modules alias is a no-opif not modules and if not identity_modules agree in truthiness, and the returned dict is still keyed and sorted by module path.

The two new/tightened test regexes match the ApplyModeError message strings in policy.py character-for-character, including the implicit-concatenation seam in the second one ("...use a " + "supported class directly"). The end-of-string anchors are the substantive part of the test change and pull real weight: they assert the diagnostic names only the offending path, so a regression that swept the valid sibling (good) into the error list would now fail rather than pass on a loose substring match. The new mixed valid-plus-unconverted-subclass case closes the gap its counterpart already covered for missing decay tensors.

The one SUGGESTION concerns dict(sorted(identity_modules)) sorting raw tuples, which makes the sort key implicitly include the nn.Module. It is unreachable given named_modules() yields unique paths — non-blocking and purely defensive.

I reviewed the test changes statically rather than executing them; running the suite locally needed a permission I did not have, so I did not independently reproduce the 23-passed result reported in the PR description.

🤖 Generated with Claude Code

@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:54 UTC

## Summary

Follow-up to #2385 addressing its sole defensive Claude suggestion:

- sort discovered GDN modules with an explicit qualified-name key
- prevent any hypothetical duplicate-name fallback from comparing
nn.Module objects

This PR is intentionally stacked on #2385 because repository rules
protect a PR head branch after creation.

## Validation

- focused DASC suite: 23 passed, 1 absent optional Megatron skip
- DASC plus weight sparsity plus attention sparsity compatibility suite:
134 passed, 1 optional skip
- full pre-commit on the touched file: passed
- prior full-package coverage remains 408/408 statements; this change
adds no statements and the line is exercised by the focused suite

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

## Summary by CodeRabbit

* **Bug Fixes**
  * GDN modules are now returned in a consistent, predictable order.

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

Signed-off-by: Kai Xu <kaix@nvidia.com>
@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.76%. Comparing base (680cfb0) to head (1b2d494).

Additional details and impacted files
@@                             Coverage Diff                              @@
##           feature/dasc-state-sparsity-complete-layers    #2385   +/-   ##
============================================================================
  Coverage                                        78.76%   78.76%           
============================================================================
  Files                                              548      548           
  Lines                                            64189    64192    +3     
============================================================================
+ Hits                                             50561    50564    +3     
  Misses                                           13628    13628           
Flag Coverage Δ
examples-diffusers 20.81% <27.27%> (+<0.01%) ⬆️
examples-gpt-oss 13.38% <27.27%> (+<0.01%) ⬆️
examples-hf_ptq 21.78% <27.27%> (+<0.01%) ⬆️
examples-llm_distill 13.45% <27.27%> (+<0.01%) ⬆️
examples-llm_eval 17.25% <27.27%> (+<0.01%) ⬆️
examples-llm_qat 17.59% <27.27%> (+<0.01%) ⬆️
examples-llm_sparsity 15.94% <27.27%> (+<0.01%) ⬆️
examples-megatron_bridge 26.26% <27.27%> (+<0.01%) ⬆️
examples-specdec_bench 13.13% <27.27%> (+<0.01%) ⬆️
examples-speculative_decoding 17.67% <27.27%> (+<0.01%) ⬆️
examples-torch_onnx 21.82% <27.27%> (+0.01%) ⬆️
examples-torch_trt 15.14% <27.27%> (+<0.01%) ⬆️
gpu 58.38% <27.27%> (+<0.01%) ⬆️
regression 15.15% <27.27%> (+<0.01%) ⬆️
unit 57.44% <100.00%> (+0.01%) ⬆️

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.

kaix-nv added a commit that referenced this pull request Sep 11, 2026
## Summary

Consolidates the complete reviewed fix stack for #2375 into one DCO-safe
commit:

- harden package exports, measurement semantics, wrapper handling, and
actionable calibration errors
- validate exact installed GDN identities plus ModelOpt dynamic
subclasses; reject lookalikes, ordinary subclasses, incomplete layers,
and partial layer sets
- make stale checkpoints saveable and restorable while keeping
deployment export strict
- make DASC recalibration replace and deduplicate existing mode state
without stale-metadata refresh
- record the declared decay-parameter checkpoint storage dtype and use
derived FP16/BF16/FP32 rounding bounds
- preserve BF16/FP16 storage and wider/cross-dtype reload compatibility
without globally widening FP32 tolerance
- add installed Transformers path coverage, optional Megatron gating,
lifecycle, tamper, lossy-cast, and mixed-layer regressions
- document the explicit storage-dtype contract

This consolidated PR supersedes the mechanically stacked review-fix PRs
#2377, #2378, #2379, #2380, #2382, #2383, #2384, and #2385. Its tree is
byte-identical to the independently reviewed leaf commit from #2386.

## Validation

- focused DASC suite: 23 passed, 1 absent optional Megatron skip
- DASC plus weight sparsity plus attention sparsity compatibility suite:
134 passed, 1 optional skip
- DASC package coverage: 408/408 statements, 100%
- full pre-commit on all touched files: passed
- real Transformers Qwen3NextGatedDeltaNet BF16 storage to FP32 reload
smoke: passed
- commit author and Signed-off-by identity both use kaix-nv
<kaix@nvidia.com>

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

## Summary by CodeRabbit

* **New Features**
* Added support for configuring decay-parameter storage precision with
FP16, BF16, or FP32.
  * Added safer recalibration that replaces existing DASC state.
* Expanded compatibility with supported GDN adapter classes and model
wrappers.
* Added improved validation for sparsity policies, measurements, model
structure, and decay parameters.
  * Added support for perplexity-retention values above 1.

* **Documentation**
* Clarified evaluation responsibilities, recalibration behavior,
stale-policy handling, supported adapters, and dtype requirements.

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

---------

Signed-off-by: kaix-nv <kaix@nvidia.com>
@kaix-nv

kaix-nv commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by consolidated review-fix PR #2387, now merged into #2375’s head. Closing this mechanical stack layer.

@kaix-nv kaix-nv closed this Sep 11, 2026
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