Skip to content

fix(dpmodel): use graph forward for output statistics - #5946

Open
Stardust0831 wants to merge 1 commit into
deepmodeling:masterfrom
Stardust0831:fix/graph-native-statistics-forward
Open

fix(dpmodel): use graph forward for output statistics#5946
Stardust0831 wants to merge 1 commit into
deepmodeling:masterfrom
Stardust0831:fix/graph-native-statistics-forward

Conversation

@Stardust0831

@Stardust0831 Stardust0831 commented Aug 1, 2026

Copy link
Copy Markdown

Summary

This PR routes model predictions used by output-bias statistics through the graph lower when the atomic model declares uses_graph_lower(), while preserving the existing dense neighbor-list path for all other models.

Motivation

The output-statistics wrapper currently always calls extend_input_and_build_neighbor_list(). For graph-native models, sel describes normalization rather than a desired fixed neighbor capacity, so constructing a dense (nframes, nloc, nsel) neighbor list can allocate a large amount of padding that the model does not need. The regular graph execution path already avoids this representation by carrying only the neighbors found within the cutoff.

Changes

  • Use the public uses_graph_lower() capability to select the statistics forward path without checking descriptor or model names.
  • Build a carry-all NeighborGraph directly from coordinates, atom types, the periodic box, cutoff, and model-level pair exclusions.
  • Flatten atype and aparam onto the graph node axis while keeping fparam and charge_spin frame-level.
  • Restore graph outputs from (nframes * nloc, ...) to (nframes, nloc, ...) before the existing statistics reduction.
  • Preserve the previous dense implementation unchanged as the fallback for non-graph models and empty systems.

Compatibility

This change does not add or modify any public API or configuration option. Traditional dense models retain their existing execution path and output behavior. Empty systems also retain the dense path because the existing dense neighbor-list implementation explicitly supports zero local atoms.

Tests

  • Added one-frame and multi-frame coverage proving that graph-capable output-statistics forward does not call the dense neighbor-list builder or consult sel.
  • Verified forwarding and shapes for atom types, frame parameters, atomic parameters, charge/spin conditioning, periodic boxes, and pair exclusions.
  • Added an end-to-end change-by-statistic regression test using self-consistent labels.
  • Added zero-atom coverage for the dense compatibility fallback.
  • Ran the graph-lower, graph-parity, global-statistics, and atomic-statistics test subsets: 58 tests passed.
  • Ran ruff format --check, ruff check, and git diff --check on the changed files.

Summary by CodeRabbit

  • New Features
    • Added graph-based neighbor processing for compatible models, improving support for graph-based inference.
    • Preserved dense neighbor-list processing for models that do not support graph-based inference.
    • Added support for forwarding frame-level, atom-level, and charge/spin parameters through graph-based processing.
    • Improved handling of empty systems and output shapes.

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

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The atomic model wrapper now routes graph-capable models through neighbor-graph inference while retaining dense inference for other models. Tests cover parameter propagation, statistics, bias updates, direct graph equivalence, and empty systems.

Changes

Graph atomic forwarding

Layer / File(s) Summary
Graph forwarding dispatch
deepmd/dpmodel/atomic_model/base_atomic_model.py
The wrapper selects graph-based inference for graph-capable models and preserves dense neighbor-list inference for other models. It reshapes atomic parameters and outputs around graph execution.
Graph forwarding validation
source/tests/pt_expt/model/test_dpa1_graph_lower.py
Tests validate graph execution, fparam, aparam, charge_spin, statistics, bias updates, direct graph equivalence, and empty-system output shapes.

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

Sequence Diagram(s)

sequenceDiagram
  participant AtomicModelWrapper
  participant build_neighbor_graph
  participant forward_common_atomic_graph
  AtomicModelWrapper->>build_neighbor_graph: construct neighbor graph
  build_neighbor_graph-->>AtomicModelWrapper: graph and flattened atom data
  AtomicModelWrapper->>forward_common_atomic_graph: forward graph and model parameters
  forward_common_atomic_graph-->>AtomicModelWrapper: atomic outputs
  AtomicModelWrapper->>AtomicModelWrapper: restore atom dimensions
Loading

Possibly related PRs

Suggested labels: bug

Suggested reviewers: njzjz-bot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: using graph-based forwarding for output statistics.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

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

🧹 Nitpick comments (1)
source/tests/pt_expt/model/test_dpa1_graph_lower.py (1)

203-211: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the duplicated dense-route regression guard. Both test_output_stat_forward_uses_graph_lower and test_change_out_bias_uses_graph_lower define an identical fail_dense function and apply the same two monkeypatch.setattr calls (get_sel and extend_input_and_build_neighbor_list) to prove the dense route is never used. One shared helper removes the duplication and keeps both guards synchronized if the dense-route entry points change.

  • source/tests/pt_expt/model/test_dpa1_graph_lower.py#L203-L211: replace this block with a call to a shared helper (e.g., self._assert_dense_route_unused(monkeypatch, atomic_model)).
  • source/tests/pt_expt/model/test_dpa1_graph_lower.py#L270-L277: replace this block with the same shared helper call.
♻️ Proposed helper extraction
+    def _assert_dense_route_unused(self, monkeypatch, atomic_model) -> None:
+        def fail_dense(*args, **kwargs):
+            raise AssertionError("the graph statistics route must not use dense sel")
+
+        monkeypatch.setattr(atomic_model, "get_sel", fail_dense)
+        monkeypatch.setattr(
+            "deepmd.dpmodel.utils.nlist.extend_input_and_build_neighbor_list",
+            fail_dense,
+        )

Then in each test:

-        def fail_dense(*args, **kwargs):
-            raise AssertionError("the graph statistics route must not use dense sel")
-
-        monkeypatch.setattr(atomic_model, "get_sel", fail_dense)
-        monkeypatch.setattr(
-            "deepmd.dpmodel.utils.nlist.extend_input_and_build_neighbor_list",
-            fail_dense,
-        )
+        self._assert_dense_route_unused(monkeypatch, atomic_model)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/tests/pt_expt/model/test_dpa1_graph_lower.py` around lines 203 - 211,
Extract the duplicated dense-route guard into a shared helper, such as
_assert_dense_route_unused, in
source/tests/pt_expt/model/test_dpa1_graph_lower.py. Have it define the failure
callback and apply both monkeypatches for get_sel and
extend_input_and_build_neighbor_list; replace the duplicated blocks at lines
203-211 and 270-277 with calls to this helper, passing monkeypatch and
atomic_model.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@source/tests/pt_expt/model/test_dpa1_graph_lower.py`:
- Around line 203-211: Extract the duplicated dense-route guard into a shared
helper, such as _assert_dense_route_unused, in
source/tests/pt_expt/model/test_dpa1_graph_lower.py. Have it define the failure
callback and apply both monkeypatches for get_sel and
extend_input_and_build_neighbor_list; replace the duplicated blocks at lines
203-211 and 270-277 with calls to this helper, passing monkeypatch and
atomic_model.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 19393888-4818-44c2-8db2-de69b9682d7f

📥 Commits

Reviewing files that changed from the base of the PR and between e61de2e and 686bc84.

📒 Files selected for processing (2)
  • deepmd/dpmodel/atomic_model/base_atomic_model.py
  • source/tests/pt_expt/model/test_dpa1_graph_lower.py

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.

1 participant