Skip to content

fix: handle empty iter_data_new_exp in auto_prob generation - #368

Open
SchrodingersCattt wants to merge 5 commits into
deepmodeling:masterfrom
SchrodingersCattt:fix/auto-prob-empty-iter-data
Open

fix: handle empty iter_data_new_exp in auto_prob generation#368
SchrodingersCattt wants to merge 5 commits into
deepmodeling:masterfrom
SchrodingersCattt:fix/auto-prob-empty-iter-data

Conversation

@SchrodingersCattt

@SchrodingersCattt SchrodingersCattt commented Jul 22, 2026

Copy link
Copy Markdown

Problem

When FP labeling fails on all conformations and continue_on_success_ratio allows the workflow to proceed, iter_data contains directory entries that expand to zero systems.

This causes auto_prob to generate prob_sys_size; 0:2:0.6; 2:2:0.4 (empty range 2:2) which crashes with ValueError: probabilities do not sum to 1.

Fix

Guard with if numb_new > numb_old + fallback to plain prob_sys_size + warning log.

Test

Added test_auto_prob_empty_new_iter_data.

Summary by CodeRabbit

  • Bug Fixes

    • Improved automatic training configuration when new systems or existing training data are unavailable.
    • Prevented invalid, empty probability ranges that could cause training failures.
    • Added a warning when ratio-based sampling cannot be applied and a safe fallback is selected.
  • Tests

    • Added coverage for training iterations with empty new or existing data.

When FP labeling fails on all conformations and
continue_on_success_ratio allows the workflow to proceed,
iter_data contains directory entries that expand to zero systems.
This caused auto_prob to generate an empty range like
"prob_sys_size; 0:2:0.6; 2:2:0.4" which crashes dp train with
"ValueError: probabilities do not sum to 1".

Fix: guard with `if numb_new > numb_old` before generating
the two-group auto_prob string. When there is no new data,
fall back to plain "prob_sys_size" and log a warning.

Fixes the scenario: extreme systems (e.g., energetic materials
at high temperature) where teacher model cannot label any
conformations from the first exploration iteration.
@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. bug Something isn't working labels Jul 22, 2026
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@SchrodingersCattt, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 19 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 263d9929-1d8e-4578-87dd-93d2895240ff

📥 Commits

Reviewing files that changed from the base of the PR and between c689e99 and 4ef4258.

📒 Files selected for processing (1)
  • tests/op/test_run_dp_train.py
📝 Walkthrough

Walkthrough

RunDPTrain.execute now avoids empty probability ranges when old data is empty or no new systems are added. Tests verify the fallback configuration for both cases.

Changes

Auto probability fallback

Layer / File(s) Summary
Probability selection and regression coverage
dpgen2/op/run_dp_train.py, tests/op/test_run_dp_train.py
RunDPTrain.execute uses the ratio-based prob_sys_size range only when valid old and new system counts exist. Otherwise, it logs a warning and uses plain "prob_sys_size". Tests cover empty expanded iteration data and empty old training data.

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

🚥 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 describes the main change: handling empty iter_data_new_exp during auto_prob generation.
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.

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

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@tests/op/test_run_dp_train.py`:
- Around line 349-355: Update the test around RunDPTrain.execute to exercise the
production fallback rather than recomputing auto_prob locally. Mock run_command,
invoke execute with iter_data=[empty_iter], then inspect the generated training
script and assert its auto_prob value is "prob_sys_size"; remove the duplicate
numb_new/numb_old conditional and assertion based on it.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0e6873f7-f44c-48b1-a2b0-d1a2d779e58a

📥 Commits

Reviewing files that changed from the base of the PR and between b05af11 and 6e574ea.

📒 Files selected for processing (2)
  • dpgen2/op/run_dp_train.py
  • tests/op/test_run_dp_train.py

Comment thread tests/op/test_run_dp_train.py Outdated
Address review: replace local logic re-computation with an actual
call to RunDPTrain.execute() using mocked run_command, then inspect
the generated training script's auto_prob value.

This ensures the test fails if the production guard is removed.

@njzjz-bot njzjz-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.

Functional finding on the current head.

Comment thread dpgen2/op/run_dp_train.py Outdated
numb_old = len_init + len(iter_data_old_exp)
numb_new = numb_old + len(iter_data_new_exp)
auto_prob_str = f"prob_sys_size; 0:{numb_old}:{old_ratio}; {numb_old}:{numb_new}:{1.-old_ratio:g}"
if numb_new > numb_old:

@njzjz-bot njzjz-bot Aug 10, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 — Handle the symmetric empty-old-data case. If a workflow starts from supplied init_models with no init_data, the first labeled iteration can make numb_old == 0 < numb_new. This branch then emits prob_sys_size; 0:0:0.6; 0:N:0.4; DeePMD assigns only the 0.4 block, so the probabilities still do not sum to 1. Require both ranges to be nonempty before using the two-block form, otherwise fall back to prob_sys_size; please also generalize the warning and add an empty-old regression test.

Suggested change
if numb_new > numb_old:
if numb_old > 0 and numb_new > numb_old:

Codex quota is about to reset, so I am using the remaining token budget to review this PR now.

Coding agent: Codex
Codex version: codex-cli 0.144.6
Model: gpt-5.6-sol
Reasoning effort: xhigh

Comment thread tests/op/test_run_dp_train.py Outdated
Comment on lines +362 to +367
try:
op.execute(ip)
except Exception:
# May fail on freeze/post-process; we only care about
# the generated training script at this point.
pass

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3 — Do not swallow unexpected failures in this regression test. Both external commands are mocked as successful, so an exception from execute() is a test failure. Catching every exception allows the test to pass when execution breaks after writing the input file and weakens the claimed end-to-end coverage.

Suggested change
try:
op.execute(ip)
except Exception:
# May fail on freeze/post-process; we only care about
# the generated training script at this point.
pass
op.execute(ip)

Codex quota is about to reset, so I am using the remaining token budget to review this PR now.

Coding agent: Codex
Codex version: codex-cli 0.144.6
Model: gpt-5.6-sol
Reasoning effort: xhigh

@njzjz-bot njzjz-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.

The empty-new-data fallback works, but the symmetric empty-old-data case still produces an invalid two-range probability expression. I also left a non-blocking inline suggestion to keep the regression test from swallowing unexpected execution failures.

Codex quota is about to reset, so I am using the remaining token budget to review this PR now.

Coding agent: Codex
Codex version: codex-cli 0.144.6
Model: gpt-5.6-sol
Reasoning effort: xhigh

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

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@tests/op/test_run_dp_train.py`:
- Around line 328-376: Make the directory cleanup in this test failure-safe by
registering self.addCleanup for empty_iter_data, task_path, and the generated
task-auto-prob directory immediately after they are created or otherwise
wrapping the test body in try/finally. Remove reliance on the final
shutil.rmtree block, following the cleanup pattern used by
test_auto_prob_empty_old_data.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 13fecdf8-3f54-485a-9679-f6ed0832c4c5

📥 Commits

Reviewing files that changed from the base of the PR and between 6e574ea and c689e99.

📒 Files selected for processing (2)
  • dpgen2/op/run_dp_train.py
  • tests/op/test_run_dp_train.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • dpgen2/op/run_dp_train.py

Comment thread tests/op/test_run_dp_train.py Outdated

@wanghan-iapcm wanghan-iapcm 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.

Code review

Approving. The fix is correct and the tests genuinely prove it.

The production hunk is sound. The counts line up exactly with the systems list write_data_to_input_script emits (init_data + iter_data_old_exp + iter_data_new_exp), so the old block really does occupy [0, numb_old). And in both degenerate cases plain prob_sys_size is the mathematical limit of the intended distribution rather than a different policy — with an empty block there is no old/new mixture left to weight, so no configured init_model_old_ratio is being silently discarded. logging.warning is the right severity: an FP iteration yielding nothing is a legitimate, if suspicious, workflow state, and the training OP should not kill the run over it.

I verified the tests fail pre-fix, rather than reading the diff and assuming. Reverting only the source line in a scratch worktree, with your tests kept verbatim:

FAIL: test_auto_prob_empty_new_iter_data
AssertionError: 'prob_sys_size; 0:2:0.6; 2:2:0.4' != 'prob_sys_size'
FAIL: test_auto_prob_empty_old_data
AssertionError: 'prob_sys_size; 0:0:0.6; 0:2:0.4' != 'prob_sys_size'
Ran 27 tests ... FAILED (failures=2)

Exactly the two malformed strings, no collateral failures, all 27 green at HEAD. Neither test is vacuous — the assertion is a literal string round-tripped through JSON from the input.json that execute() itself wrote, sharing no guard with the code under test, and only run_command is patched so the real code path runs. I also checked test_auto_prob_empty_old_data against the intermediate commit 435b9bb: it still fails there, which confirms the two tests cover genuinely distinct defects and that the second one is what forced c689e99.

Why this survived three years, for the record: the untested cell was init_model_policy="yes" crossed with an iter_data entry expanding to zero systems. TestRunDPTrainNullIterData — the class commit 09e7e2e (#61) added for exactly the empty-dir case — pins init_model_policy="no" in all three of its tests, so decide_init_model returns False and this expression is never evaluated; its test_exec_v2_empty_dir asserts auto_prob == "prob_sys_size" and gets the right answer for the wrong reason. Meanwhile TestRunDPTrain, the only class with the policy on, hardcodes fully populated data (numb_old=4, numb_new=7). The bug lived precisely at the crossing of the two classes' setups. Root cause goes back to 1ca9aaa, which hard-coded numb_old:numb_old+1 and so assumed the last iteration contributes exactly one system; #61 falsified that invariant five months later and nobody revisited the trainer.


Two things to be aware of, neither blocking:

  1. See the inline note on the doubly-empty case.

  2. The unit tests never actually ran on this PR. gh pr checks shows 3 passing checks; merged #343 had 10. Python unit-tests and Type checker are both conclusion=action_required on 4ef4258 — the outside-contributor workflow gate. Someone needs to approve the run before merge; the green checkmarks currently say nothing about the suite. (Also, njzjz-bot's CHANGES_REQUESTED from 435b9bb is stale — both its points were applied in c689e99 and 4ef4258 — and may need dismissing if branch protection requires it.)

Minor: the diff carries some unrelated f-string reformatting ({1.-old_ratio:g} -> {1.0 - old_ratio:g}, and {self.old_data_size-1} in the test). The pinned ruff-format v0.1.3 in .pre-commit-config.yaml does not touch f-string internals, so these came from a newer local formatter and CI will not normalize them either way. Harmless, just diff noise.

Comment thread dpgen2/op/run_dp_train.py
"Cannot build two non-empty auto_prob ranges "
"(numb_old=%d, numb_new=%d). "
"Falling back to auto_prob='prob_sys_size'. "
"Training will proceed with all available data.",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Non-blocking follow-up: there is a third degenerate case this branch catches but does not really handle — numb_old == numb_new == 0.

With init_data: [] in the config (a finetune-style run: pretrained init_model, no initial data) plus an iteration that expands to zero systems, we land here with no data at all. auto_prob becomes "prob_sys_size", but training_data.systems is [] and dp train is still launched. I reproduced it end-to-end against this HEAD:

WARNING  Cannot build two non-empty auto_prob ranges (numb_old=0, numb_new=0)...
training_data: {"systems": [], "batch_size": "auto", "auto_prob": "prob_sys_size"}
command: ['dp', 'train', '--init-frz-model', 'bar.pb', 'input.json']

Before this PR that state produced prob_sys_size; 0:0:0.9; 0:0:0.1 and died fast with the clear "probabilities do not sum to 1". Now it gets further and fails deeper inside deepmd-kit with a murkier message. Note skip_training cannot rescue it either — it tests len(iter_data) == 0 on the unexpanded list, which from iteration 1 onward is never true.

Related, and the reason I am flagging it on this line: the message text is false in that case. "Training will proceed with all available data" is printed when there is no data. Something like "... proceed with all available data (numb_new=0: nothing to train on)", or an explicit early bail when numb_new == 0, would read correctly in all three cases.

Happy for this to be a separate PR — it does not affect the crash you are fixing here.

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.

Thanks for flagging this. Since the fully empty case requires deciding whether to reuse the existing model or fail early, I’ll keep #368 scoped to fixing the invalid auto_prob ranges. I opened #371 to track the behavior and regression test separately: #371

@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Aug 12, 2026
@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.20%. Comparing base (d27efaa) to head (4ef4258).
⚠️ Report is 14 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #368      +/-   ##
==========================================
+ Coverage   84.17%   84.20%   +0.03%     
==========================================
  Files         104      104              
  Lines        6111     6110       -1     
==========================================
+ Hits         5144     5145       +1     
+ Misses        967      965       -2     

☔ 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.

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

Labels

bug Something isn't working lgtm This PR has been approved by a maintainer size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants