Skip to content

feat(pt/dpmodel): add use_default_pf#5356

Open
iProzd wants to merge 3 commits intodeepmodeling:masterfrom
iProzd:0330-default-pf
Open

feat(pt/dpmodel): add use_default_pf#5356
iProzd wants to merge 3 commits intodeepmodeling:masterfrom
iProzd:0330-default-pf

Conversation

@iProzd
Copy link
Copy Markdown
Collaborator

@iProzd iProzd commented Mar 30, 2026

Summary by CodeRabbit

  • New Features

    • Added use_default_pf option to enable prefactor-force loss using a default atom preference of 1.0 so atom_pref.npy can be omitted.
  • Behavior Changes

    • Prefactor-force loss will be computed when this option is enabled; force label requirements expanded accordingly.
    • PyTorch backend: supported. TensorFlow/Paddle: currently not implemented (raises if used).
  • Documentation

    • Training docs updated with guidance and example config.
  • Tests

    • Added tests for default-prefactor behavior and serialization/versioning.

Copilot AI review requested due to automatic review settings March 30, 2026 12:03
@dosubot dosubot bot added the new feature label Mar 30, 2026
)
pt_loss_val = pt_loss.detach().cpu().numpy()
# loss should be non-zero because pf loss is activated via use_default_pf
self.assertTrue(pt_loss_val != 0.0)

Check notice

Code scanning / CodeQL

Imprecise assert Note test

assertTrue(a != b) cannot provide an informative message. Using assertNotEqual(a, b) instead will give more informative messages.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 44a55465-f7ba-427a-9e84-d34ee94b14d1

📥 Commits

Reviewing files that changed from the base of the PR and between 28e6fdd and 7d8a307.

📒 Files selected for processing (2)
  • deepmd/pd/loss/ener.py
  • deepmd/tf/loss/ener.py

📝 Walkthrough

Walkthrough

Added a boolean flag use_default_pf to energy-loss implementations enabling a default per-atom prefactor (1.0) when atom_pref is absent; updated label requirements and defaults, bumped loss serialization schema from version 2→3 across backends, added CLI/config option, docs, and PyTorch unit tests.

Changes

Cohort / File(s) Summary
Core dpmodel loss
deepmd/dpmodel/loss/ener.py
Add use_default_pf to EnergyLoss; when true find_atom_pref is treated as 1.0 in call(); atom_pref label gets default=1.0; serialize/deserialize bumped to @version: 3 and persist use_default_pf.
PyTorch loss & tests
deepmd/pt/loss/ener.py, source/tests/pt/test_loss_default_pf.py
Add use_default_pf to EnergyStdLoss constructor and serialization (@version: 3); prefactor selection logic honors use_default_pf; expand label_requirement (force inclusion) and atom_pref default; add comprehensive PT tests for behavior and (de)serialization.
Paddle & TensorFlow losses
deepmd/pd/loss/ener.py, deepmd/tf/loss/ener.py
Serialize now emits @version: 3 and includes use_default_pf; constructors explicitly reject use_default_pf=True (NotImplementedError) for these backends; deserialization compatibility updated to expect version 3.
CLI/config schema
deepmd/utils/argcheck.py
Add use_default_pf: bool option to loss_ener() config schema (default False).
Docs
doc/model/train-se-a-mask.md
Document use_default_pf behavior and example config showing that a default atom_pref=1.0 can be applied when atom_pref.npy is missing.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • njzjz
  • wanghan-iapcm
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 68.97% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(pt/dpmodel): add use_default_pf' clearly and concisely summarizes the main change—adding a new feature parameter across PyTorch and dpmodel modules.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

Copy link
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@deepmd/utils/argcheck.py`:
- Around line 3307-3313: The schema now accepts use_default_pf but the Paddle
training path silently ignores it; update the Paddle loss handling in
deepmd/pd/train/training.py so that when loss_params (the dict forwarded into
the loss constructor) contains "use_default_pf" it is either honored by passing
it into the Paddle loss implementation or rejected up-front. Specifically,
either (A) extend the Paddle loss constructor(s) referenced where loss_params is
passed (look for the loss creation block around the code forwarding loss_params
at lines ~1316-1329) to accept and act on use_default_pf, or (B) validate and
remove/raise on presence of "use_default_pf" before forwarding (e.g., check
loss_params.get("use_default_pf") and raise a clear error), and ensure the
change references the same loss_params variable and the Paddle training module
functions so behavior is consistent with the other backends.

In `@source/tests/pt/test_loss_default_pf.py`:
- Around line 198-206: The test binds unused variables pt_loss_without and
pt_loss_with from the loss_fn return tuple; change those bindings to dummy
underscores (e.g., replace pt_loss_without and pt_loss_with with _ or use a
single leading underscore name) or omit binding them entirely so the unpacked
but unused values don't trigger Ruff RUF059; update the two calls to loss_fn
(the ones assigning "_, pt_loss_without, pt_more_loss_without" and "_,
pt_loss_with, pt_more_loss_with") to use a dummy name for the middle element
(e.g., "_, _, pt_more_loss_without" and "_, _, pt_more_loss_with" or "_,
_pt_loss, pt_more_loss...") and run ruff format/check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 860ed2bb-bc14-45f0-a96c-b7ec609a1629

📥 Commits

Reviewing files that changed from the base of the PR and between 0828604 and e5f7ce5.

📒 Files selected for processing (5)
  • deepmd/dpmodel/loss/ener.py
  • deepmd/pt/loss/ener.py
  • deepmd/utils/argcheck.py
  • doc/model/train-se-a-mask.md
  • source/tests/pt/test_loss_default_pf.py

Comment on lines +3307 to +3313
Argument(
"use_default_pf",
bool,
optional=True,
default=False,
doc=doc_use_default_pf,
),
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.

⚠️ Potential issue | 🟠 Major

use_default_pf is accepted here but can be a silent no-op on Paddle backend.

This option is now valid in schema, but the Paddle training path (deepmd/pd/train/training.py Line 1316-Line 1329) forwards loss_params into a loss constructor that does not consume use_default_pf as an active field, so users can set it without effect. Please either implement it in the Paddle loss path or explicitly reject it there to avoid backend-inconsistent behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deepmd/utils/argcheck.py` around lines 3307 - 3313, The schema now accepts
use_default_pf but the Paddle training path silently ignores it; update the
Paddle loss handling in deepmd/pd/train/training.py so that when loss_params
(the dict forwarded into the loss constructor) contains "use_default_pf" it is
either honored by passing it into the Paddle loss implementation or rejected
up-front. Specifically, either (A) extend the Paddle loss constructor(s)
referenced where loss_params is passed (look for the loss creation block around
the code forwarding loss_params at lines ~1316-1329) to accept and act on
use_default_pf, or (B) validate and remove/raise on presence of "use_default_pf"
before forwarding (e.g., check loss_params.get("use_default_pf") and raise a
clear error), and ensure the change references the same loss_params variable and
the Paddle training module functions so behavior is consistent with the other
backends.

Comment on lines +198 to +206
_, pt_loss_without, pt_more_loss_without = loss_fn(
{},
fake_model,
self.label_without_pref,
self.nloc,
self.cur_lr,
)
# With find_atom_pref=1.0, pf loss should be computed
_, pt_loss_with, pt_more_loss_with = loss_fn(
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.

⚠️ Potential issue | 🟡 Minor

Fix Ruff RUF059: unused unpacked variables in tests.

pt_loss_without and pt_loss_with are assigned but unused. Rename to dummy variables (or avoid binding) so lint stays green.

🔧 Minimal fix
-        _, pt_loss_without, pt_more_loss_without = loss_fn(
+        _, _pt_loss_without, pt_more_loss_without = loss_fn(
             {},
             fake_model,
             self.label_without_pref,
             self.nloc,
             self.cur_lr,
         )
@@
-        _, pt_loss_with, pt_more_loss_with = loss_fn(
+        _, _pt_loss_with, pt_more_loss_with = loss_fn(
             {},
             fake_model,
             self.label_with_pref,
             self.nloc,
             self.cur_lr,
         )

As per coding guidelines **/*.py: "Always run ruff check . and ruff format . before committing changes or CI will fail".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
_, pt_loss_without, pt_more_loss_without = loss_fn(
{},
fake_model,
self.label_without_pref,
self.nloc,
self.cur_lr,
)
# With find_atom_pref=1.0, pf loss should be computed
_, pt_loss_with, pt_more_loss_with = loss_fn(
_, _pt_loss_without, pt_more_loss_without = loss_fn(
{},
fake_model,
self.label_without_pref,
self.nloc,
self.cur_lr,
)
# With find_atom_pref=1.0, pf loss should be computed
_, _pt_loss_with, pt_more_loss_with = loss_fn(
🧰 Tools
🪛 Ruff (0.15.7)

[warning] 198-198: Unpacked variable pt_loss_without is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


[warning] 206-206: Unpacked variable pt_loss_with is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/tests/pt/test_loss_default_pf.py` around lines 198 - 206, The test
binds unused variables pt_loss_without and pt_loss_with from the loss_fn return
tuple; change those bindings to dummy underscores (e.g., replace pt_loss_without
and pt_loss_with with _ or use a single leading underscore name) or omit binding
them entirely so the unpacked but unused values don't trigger Ruff RUF059;
update the two calls to loss_fn (the ones assigning "_, pt_loss_without,
pt_more_loss_without" and "_, pt_loss_with, pt_more_loss_with") to use a dummy
name for the middle element (e.g., "_, _, pt_more_loss_without" and "_, _,
pt_more_loss_with" or "_, _pt_loss, pt_more_loss...") and run ruff format/check.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a use_default_pf option to energy loss implementations so the prefactor-force (pf) term can be used even when atom_pref.npy is absent by falling back to a default atom preference of 1.0.

Changes:

  • Add use_default_pf to PT EnergyStdLoss and DPModel EnergyLoss, including serialization/deserialization updates.
  • Adjust label requirements so force is requested when pf is used, and set atom_pref’s default to 1.0.
  • Add PT unit tests for the new behavior and document the new config flag.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
deepmd/pt/loss/ener.py Implements use_default_pf behavior, updates label requirements, bumps serialization version.
deepmd/dpmodel/loss/ener.py Implements use_default_pf behavior, updates atom_pref default, bumps serialization version.
deepmd/utils/argcheck.py Exposes use_default_pf in loss/ener arg validation/docs.
doc/model/train-se-a-mask.md Documents how to enable use_default_pf in training JSON.
source/tests/pt/test_loss_default_pf.py Adds PT-only tests for use_default_pf, label requirements, and serialization.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +190 to +192
find_atom_pref = (
label_dict["find_atom_pref"] if not self.use_default_pf else 1.0
)
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

The use_default_pf behavior change in EnergyLoss.call() (overriding find_atom_pref) isn’t covered by the existing dpmodel loss unit tests (e.g., source/tests/common/dpmodel/test_loss_ener.py). Please add a small test case asserting that with find_atom_pref=0.0 and use_default_pf=True, the pf contribution/metrics are computed, and that with use_default_pf=False they remain suppressed.

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +58
def get_single_batch(dataset, index=None):
if index is None:
index = dp_random.choice(np.arange(len(dataset)))
np_batch = dataset[index]
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

get_single_batch() picks a random frame index via dp_random.choice(...) but this test module never seeds dp_random, so the selected frame can vary between runs/environments. To avoid flaky tests, either pass an explicit index (e.g., 0) or seed dp_random in setUp() (consistent with other tests that call dp_random.seed(...)).

Copilot uses AI. Check for mistakes.
}
```

If `atom_pref.npy` is not provided in the training data, one can set `use_default_pf` to `true` to use a default atom preference of 1.0 for all atoms. This allows using the prefactor force loss (`pf` loss) without requiring `atom_pref.npy` files. When `atom_pref.npy` is provided, it will be used as-is regardless of this setting.
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

The new paragraph implies use_default_pf works in general training, but the implementation appears to exist only in the PyTorch/DPModel losses (TF/Paddle EnerStdLoss accept **kwargs and will silently ignore use_default_pf). Please clarify the backend scope here (e.g., explicitly state “PyTorch/DP backend only”) or implement equivalent behavior for the other backends to avoid a configuration option that is accepted but has no effect.

Suggested change
If `atom_pref.npy` is not provided in the training data, one can set `use_default_pf` to `true` to use a default atom preference of 1.0 for all atoms. This allows using the prefactor force loss (`pf` loss) without requiring `atom_pref.npy` files. When `atom_pref.npy` is provided, it will be used as-is regardless of this setting.
If `atom_pref.npy` is not provided in the training data and you are using the PyTorch/DP backend, you can set `use_default_pf` to `true` to use a default atom preference of 1.0 for all atoms. This allows using the prefactor force loss (`pf` loss) without requiring `atom_pref.npy` files. When `atom_pref.npy` is provided, it will be used as-is regardless of this setting. For TensorFlow/Paddle backends (for example, when using `EnerStdLoss`), the `use_default_pf` option is accepted but ignored and therefore has no effect.

Copilot uses AI. Check for mistakes.
Comment on lines 3190 to +3195
)
doc_limit_pref_pf = limit_pref("atomic prefactor force")
doc_use_default_pf = (
"If true, use default atom_pref of 1.0 for all atoms when atom_pref data is not provided. "
"This allows using the prefactor force loss (pf) without requiring atom_pref.npy files in training data. "
"When atom_pref.npy is provided, it will be used as-is regardless of this setting."
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

use_default_pf is now validated/documented for loss/ener, but TF/Paddle energy losses do not implement this behavior (they accept **kwargs and will ignore it). Consider documenting that this flag is only effective for PyTorch/DPModel (or add an explicit warning/error in non-supporting backends) to avoid a silent no-op configuration. Also, the existing start_pref_pf help text still states atom_pref.npy must be provided when prefactors are non-zero; with use_default_pf=true that statement is no longer universally true and may need to be adjusted.

Suggested change
)
doc_limit_pref_pf = limit_pref("atomic prefactor force")
doc_use_default_pf = (
"If true, use default atom_pref of 1.0 for all atoms when atom_pref data is not provided. "
"This allows using the prefactor force loss (pf) without requiring atom_pref.npy files in training data. "
"When atom_pref.npy is provided, it will be used as-is regardless of this setting."
) + (
" When `use_default_pf` is true, `atom_pref.npy` is not required even when the "
"prefactor is non-zero; a default per-atom prefactor of 1.0 will be used when "
"`atom_pref.npy` is missing. When `use_default_pf` is false, `atom_pref.npy` "
"must still be provided whenever the prefactor is non-zero."
)
doc_limit_pref_pf = limit_pref("atomic prefactor force")
doc_use_default_pf = (
"If true, use default atom_pref of 1.0 for all atoms when atom_pref data is not provided. "
"This allows using the prefactor force loss (pf) without requiring atom_pref.npy files in training data. "
"When atom_pref.npy is provided, it will be used as-is regardless of this setting. "
"Note: at present this option is only effective for the PyTorch/DPModel backend; "
"other backends (e.g. TensorFlow and Paddle) accept this flag but ignore it."

Copilot uses AI. Check for mistakes.
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 31, 2026

Codecov Report

❌ Patch coverage is 78.94737% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.32%. Comparing base (0828604) to head (7d8a307).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
deepmd/dpmodel/loss/ener.py 75.00% 1 Missing ⚠️
deepmd/pd/loss/ener.py 75.00% 1 Missing ⚠️
deepmd/pt/loss/ener.py 66.66% 1 Missing ⚠️
deepmd/tf/loss/ener.py 66.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5356      +/-   ##
==========================================
- Coverage   82.32%   82.32%   -0.01%     
==========================================
  Files         809      810       +1     
  Lines       83161    83226      +65     
  Branches     4067     4066       -1     
==========================================
+ Hits        68462    68514      +52     
- Misses      13484    13497      +13     
  Partials     1215     1215              

☔ View full report in Codecov by Sentry.
📢 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.

Copy link
Copy Markdown
Collaborator

@anyangml anyangml left a comment

Choose a reason for hiding this comment

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

LGTM

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants