Skip to content

fix(pt_expt): preserve numb_dos for exported DOS models - #6041

Open
Arthur031221 wants to merge 2 commits into
deepmodeling:masterfrom
Arthur031221:fix/pt-expt-numb-dos
Open

Arthur031221 wants to merge 2 commits into
deepmodeling:masterfrom
Arthur031221:fix/pt-expt-numb-dos

Conversation

@Arthur031221

@Arthur031221 Arthur031221 commented Oct 1, 2026 •

Copy link
Copy Markdown

Fixes #5949.

A user with a pt_expt DOS model configured with numb_dos: 2, exported to .pte or .pt2, gets ValueError: cannot reshape array of size 2 into shape (1,0) from DeepDOS.eval, because the exported model reports a DOS width of 0.

Two gaps caused it:

  • deepmd/pt_expt/model/dos_model.py::DOSModel had no get_numb_dos, so it fell back to the base default of 0. It now returns the fitting net's dim_out, as the dpmodel and pt DOS models do.
  • deepmd/pt_expt/infer/deep_eval.py::get_numb_dos returned 0 unconditionally. It now asks the reconstructed dpmodel, and for metadata-only archives (no extra/model.json) it reads a new numb_dos key. That key is written to metadata.json only for models with a dos output, and archives without it read as 0 as before.

Test: source/tests/pt_expt/infer/test_deep_eval_dos.py exports a numb_dos=2 se_e2_a DOS model to .pte and .pt2, in full and metadata-only form, and checks get_numb_dos() and the shapes returned by DeepDOS.eval. It also checks that an energy archive gets no numb_dos key. With the three source files reverted to the base commit, pytest reports 9 failures (0 != 2 and the reshape error above); with the fix, 4 tests and 8 subtests pass. Reverting only the serialization change fails the four metadata-only subtests.

Summary by CodeRabbit

  • New Features
    • DeepDOS inference now reports the number of DOS outputs for full and metadata-only model archives.
    • DOS evaluation returns total and atomic density-of-states arrays with the model’s output width.
    • Energy models without a DOS output report a DOS count of zero.

@github-actions github-actions Bot added the Python label Oct 1, 2026
@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d288d386-9704-4acd-806d-ac767627730a
📥 Commits

Reviewing files that changed from the base of the PR and between 2a82d16 and cfd8d2f.

📒 Files selected for processing: 2
  • deepmd/pt_expt/infer/deep_eval.py
  • source/tests/pt_expt/infer/test_deep_eval_dos.py

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

📝 Walkthrough

DOSModel now exposes its fitting-network output width. DeepEval reports the width from the reconstructed model or, for metadata-only archives, from the dos output definition. Tests cover DOS and energy models across full and metadata-only .pte and .pt2 archives.

Changes: DOS width preservation

Layer / File(s) Summary
Expose DOS width
deepmd/pt_expt/model/dos_model.py
DOSModel.get_numb_dos() returns the fitting network’s output dimension.
Read and test DOS width
deepmd/pt_expt/infer/deep_eval.py, source/tests/pt_expt/infer/test_deep_eval_dos.py
DeepEval.get_numb_dos() checks the reconstructed model, then the dos output definition, and returns 0 when that definition is absent. Tests check DOS widths and evaluation output shapes for full and metadata-only archives, plus zero width for energy-model archives.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: wanghan-iapcm, outisli

Merge Risk: ⚪ Minimal · up to cfd8d

The export paths preserve the configured DOS width for evaluation, including metadata-only archives. No actionable merge-blocking risk remains.

Security architecture risk: ⚪ Minimal · up to 2a82d

The change preserves an output width through export and inference without adding privileges or expanding access. Its traced consumer reshapes existing results rather than allocating resources based solely on the new value.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The demonstrated effect is confined to DOS-width reporting and result shaping in the invoking evaluator. The traced scalar path does not extend access to another tenant, service, data store, or credential authority.

Security Findings and Attack Paths

  • inferred — An archive author can influence the metadata-only width. An invalid integer or a width inconsistent with tensor size can cause conversion or reshape failure. This path does not establish a material security regression: reshaping is constrained by already-produced tensors and adds no independent allocation or privilege sink.

Trust Boundaries and Controls

  • observed — Full-model evaluation takes width from the reconstructed model rather than the metadata field. Metadata-only evaluation uses the existing archive-to-evaluator boundary; integer conversion is not an authenticity or provenance control.
Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 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: preserving numb_dos for exported DOS models.
Linked Issues check Passed The changes satisfy the coding requirements in #5949. DOSModel.get_numb_dos() returns the fitting network output width. DeepEval.get_numb_dos() returns the reconstructed model width and derives th…
Out of Scope Changes check Passed The changes stay within #5949. The production changes implement DOS-width recovery. The tests cover the affected export and inference paths. No unrelated production files or behavior are changed.
  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
🧪 Generate unit tests (beta)
  • Create a new PR
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.

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.

@njzjz-bot njzjz-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed 2a82d16f; the model getter, serialized metadata, and metadata-only inference fallback consistently preserve the DOS width. The change also keeps the existing zero fallback for older metadata-only archives and avoids adding DOS metadata to energy models.

Ran source/tests/pt_expt/infer/test_deep_eval_dos.py against this PR's source with Python 3.10 and PyTorch 2.13.0+cpu: 4 tests and 8 subtests passed, covering full and metadata-only .pte/.pt2 archives, DOS evaluation shapes, and the non-DOS case. No blocking findings.


Coding agent: Codex
Codex version: codex-cli 0.160.0
Model: gpt-6-astra
Reasoning effort: xhigh

@codecov

codecov Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.61%. Comparing base (5b9fe07) to head (cfd8d2f).
⚠️ Report is 5 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6041      +/-   ##
==========================================
- Coverage   77.74%   77.61%   -0.14%     
==========================================
  Files        1155     1170      +15     
  Lines      139649   140921    +1272     
  Branches     5056     5057       +1     
==========================================
+ Hits       108573   109372     +799     
- Misses      29191    29668     +477     
+ Partials     1885     1881       -4     

☔ 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@wanghan-iapcm wanghan-iapcm left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed at 2a82d16.

Verification:

  • I ran the new test source/tests/pt_expt/infer/test_deep_eval_dos.py against the head and against the base versions of the three source files. On head it passes: 4 passed. On pre-fix code it fails: 5 failures and 4 errors at subtest level (0 != 2 and cannot reshape array of size 2 into shape (1,0)). The test covers .pte and .pt2, full and metadata-only.
  • With only deepmd/pt_expt/utils/serialization.py reverted, exactly the four metadata-only subtests fail, as the PR description says.
  • The DOSModel.get_numb_dos override matches dpmodel (deepmd/dpmodel/model/dos_model.py) and pt (deepmd/pt/model/model/dos_model.py). This completes for pt_expt what #5722 did for dpmodel and JAX.
  • No C++ reader (source/api_cc, source/api_c, source/lmp) uses numb_dos, so the new metadata key affects only the Python DeepEval.
  • Related tests pass on head: test_deep_eval_dos.py, test_deep_eval_metadata_only.py, pt_expt/model/test_dos_model.py, pt_expt/model/test_dos_graph.py and consistent/model/test_dos.py give 75 passed and 7 skipped.

No blocking findings. Two non-blocking suggestions are inline.

Comment thread deepmd/pt_expt/infer/deep_eval.py Outdated
Comment on lines +1192 to +1193
get_numb_dos = getattr(self._dpmodel, "get_numb_dos", None)
return int(get_numb_dos()) if get_numb_dos is not None else 0

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Non-blocking: get_numb_dos always exists on the dpmodel here. The make_model base class defines it (returning 0 for models without a DOS output, deepmd/dpmodel/model/make_model.py:1148), and SpinModel.__getattr__ forwards to the backbone. So the getattr probe and its else 0 branch cannot be reached. The dpmodel and pt DeepEval call it directly (deepmd/dpmodel/infer/deep_eval.py:169, deepmd/pt/infer/deep_eval.py:459); return int(self._dpmodel.get_numb_dos()) would match them.

Comment thread deepmd/pt_expt/infer/deep_eval.py Outdated
return int(get_numb_dos()) if get_numb_dos is not None else 0
# Metadata-only mode: `numb_dos` is written by `_collect_metadata`
# for models with a `dos` output; other models read as 0.
return int(self.metadata.get("numb_dos", 0))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Non-blocking: the DOS width is already in the metadata. _collect_metadata writes every fitting output into fitting_output_defs with its shape, and for a DOS model the dos entry has shape [numb_dos] (I checked a numb_dos=3 archive: the dos shape is [3], the same as the new key). In metadata-only mode DeepEval already rebuilds self._model_output_def from that list (deep_eval.py:443-460), so get_numb_dos could read the width from the dos output def instead of a separate numb_dos key. That keeps a single source for the width, drops the metadata.get("numb_dos", 0) fallback that silently returns 0 when the key is missing, and also works for DOS archives exported before this PR. The numb_dos key added in serialization.py would then be unnecessary.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Took both suggestions in a new commit on top, so the reviewed commit is unchanged. The first one is your line as written, so the commit carries a Co-authored-by trailer for you.

DeepEval.get_numb_dos now calls self._dpmodel.get_numb_dos() directly. In metadata-only mode it reads the width from the shape of the dos entry in the output defs rebuilt from fitting_output_defs, and returns 0 when there's no dos output. The numb_dos key in _collect_metadata is gone, so DOS archives exported before this change work too.

The test now checks that an energy archive reports 0 in both full and metadata-only form, instead of checking a metadata key. test_deep_eval_dos.py, test_deep_eval_metadata_only.py and pt_expt/model/test_dos_model.py give 17 passed and 10 subtests passed. With deep_eval.py put back to the base version, test_deep_eval_dos.py gives 8 failures.

The description is now stale in two places: the second bullet (the numb_dos metadata key) and the test paragraph's check on that key, the serialization revert and the counts. The numbers above replace them.

Address review: call get_numb_dos directly on the dpmodel, and in
metadata-only mode take the width from the shape of the dos output
definition already stored in fitting_output_defs. This drops the
separate numb_dos metadata key, and also covers DOS archives exported
before this change.

Co-authored-by: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com>

This branch has not been deployed

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(pt-expt): preserve DOS width in exported models

3 participants