Skip to content

fix(data): preserve LMDB label availability across batches - #5839

Merged
njzjz merged 3 commits into
deepmodeling:masterfrom
njzjz-bot:fix/lmdb-collate-find-flags-5636
Jul 28, 2026
Merged

fix(data): preserve LMDB label availability across batches#5839
njzjz merged 3 commits into
deepmodeling:masterfrom
njzjz-bot:fix/lmdb-collate-find-flags-5636

Conversation

@njzjz-bot

@njzjz-bot njzjz-bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Fixes #5636

Summary

  • cache each LMDB frame availability signature from lightweight msgpack metadata
  • partition training, statistics, auto-probability, and distributed batches by both atom count and scalar find_* signature
  • allocate each auto-probability block target exactly across all homogeneous groups with deterministic integer largest-remainder apportionment
  • retain the existing scalar loss contract and reject heterogeneous collation defensively
  • reset pt_expt sampling after data requirements change
  • split full LMDB validation by atom count and availability so default-filled labels are excluded from metrics

Simply stacking find_* values would not be safe here. Current PyTorch and dpmodel losses reduce a whole batch before applying scalar availability flags, and display/validation paths convert those flags to booleans. A vector flag would broadcast incorrectly, produce vector-valued losses, or fail boolean conversion. Homogeneous batching is the smaller compatible fix.

Why existing tests missed this

The direct collator test used find_energy=1 in every frame and did not assert the flag value. All LMDB factories stored energy and force in every record, so same-nloc batching was also label-homogeneous by accident. Reader consistency tests inspect individual frames before collation, and loss tests construct homogeneous scalar flags without connecting them to LMDB batches. Auto-probability tests also used one availability signature, so they could not expose independent per-signature rounding that changed a block target of 3 into 4 sampled frames.

Full-validation coverage only varied atom count. LmdbTestData therefore always observed globally present labels, and no test combined real labels with default-filled frames or checked order-independent optional-label metrics.

Validation

  • common dpmodel LMDB, PyTorch LMDB, and full-validation suites: 137 passed, 3 subtests passed
  • isolated pt_expt LMDB data-system suite: 4 passed
  • review-focused common/PT/pt_expt LMDB suites: 36 passed through the pure-Python path (the locally installed optional PyTorch custom-op library has a stale ABI)
  • regression verifies an auto-probability target of 3 remains exactly 3 across two availability groups and sampler length stays exact
  • regression verifies energy and force defaults contribute zero loss when their corresponding find_* flag is zero
  • regression consumes the pre-requirement pt_expt iterator and verifies it is replaced before availability-homogeneous batching
  • regression verifies energy and force full-validation metrics use only their two labeled frames
  • ruff format .
  • ruff check .

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

Summary by CodeRabbit

  • Bug Fixes

    • LMDB training batching now partitions by both atom count and consistent scalar label-availability flags, ensuring batches don’t mix incompatible find_* settings.
    • Batch collation now raises an error when label-availability flags conflict across frames.
    • Full validation now groups evaluation by atom count and label availability so default-filled/missing labels don’t skew metrics.
  • Performance / Behavior

    • LMDB dataset loaders are now built lazily and refresh immediately after adding new label requirements.
  • Tests

    • Added coverage for partially labeled LMDB batching, validator grouping, and block-target distribution across label-availability signatures.

@dosubot dosubot Bot added the bug label Jul 16, 2026
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3c367d97-e6cf-408e-a9b4-242d29c6fb63

📥 Commits

Reviewing files that changed from the base of the PR and between c67d012 and 8c700fa.

📒 Files selected for processing (4)
  • deepmd/dpmodel/utils/lmdb_data.py
  • deepmd/pt_expt/utils/lmdb_dataset.py
  • source/tests/common/dpmodel/test_lmdb_data.py
  • source/tests/pt_expt/test_lmdb_training.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • deepmd/pt_expt/utils/lmdb_dataset.py
  • source/tests/common/dpmodel/test_lmdb_data.py
  • source/tests/pt_expt/test_lmdb_training.py
  • deepmd/dpmodel/utils/lmdb_data.py

📝 Walkthrough

Walkthrough

LMDB batching and validation now group frames by atom count and scalar find_* availability signatures. Readers cache signatures, collators reject mixed flags, datasets rebuild loaders after requirement changes, and validation evaluates homogeneous partial-label subsets.

Changes

LMDB availability-aware batching

Layer / File(s) Summary
Availability-aware reader and batching
deepmd/dpmodel/utils/lmdb_data.py
Readers cache label-availability signatures, samplers partition by (nloc, signature), block expansion preserves those groups, and collation rejects mixed scalar find_* flags.
Homogeneous validation data views
deepmd/dpmodel/utils/lmdb_data.py, deepmd/pt/train/validation.py
Validation frames are grouped by atom count and availability signature, then evaluated through indexed homogeneous views.
Requirement-aware dataset loaders
deepmd/pt/utils/lmdb_dataset.py, deepmd/pt_expt/utils/lmdb_dataset.py
LMDB loaders are rebuilt lazily after data requirements change, and the experimental data system resets its batch iterator.
Partial-label batching and validation tests
source/tests/pt/test_lmdb_dataloader.py, source/tests/pt/test_validation.py, source/tests/pt_expt/test_lmdb_training.py, source/tests/common/dpmodel/test_lmdb_data.py
Tests cover complementary label availability, homogeneous sampler batches, block-target allocation, collate errors, loss masking, iterator refresh, and validation metrics excluding default-filled labels.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant LmdbDataReader
  participant SameNlocBatchSampler
  participant collate_lmdb_frames
  participant FullValidator
  LmdbDataReader->>SameNlocBatchSampler: group frames by nloc and find signature
  SameNlocBatchSampler->>collate_lmdb_frames: emit homogeneous batches
  collate_lmdb_frames->>FullValidator: provide scalar-consistent find flags
  FullValidator->>FullValidator: evaluate grouped validation frames
Loading

Possibly related PRs

Suggested labels: enhancement

Suggested reviewers: njzjz, iprozd

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 67.31% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 is concise and accurately summarizes the main change: preserving LMDB label availability across batches.
Linked Issues check ✅ Passed The PR addresses #5636 by keeping per-frame find_* availability consistent via grouping and collation checks, with regression tests.
Out of Scope Changes check ✅ Passed The changes stay focused on LMDB label-availability handling and related batching/validation support; no unrelated feature work stands out.
✨ 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.

Actionable comments posted: 4

🤖 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 `@deepmd/dpmodel/utils/lmdb_data.py`:
- Around line 1195-1210: Update the sampling flow around
group_indices_by_find_signature and _expand_indices_by_blocks to allocate each
block’s global target across all (nloc, signature) groups before expansion,
using remainder-preserving integer allocation so per-group rounding preserves
the exact block total. Pass each group’s allocated target into expansion, and
update the estimator logic around _block_total_actual to use the same allocation
rather than independently recomputing targets per signature.

In `@source/tests/pt_expt/test_lmdb_training.py`:
- Around line 202-213: Update the test around DataRequirementItem registration
to realize or capture the lazy sampler iterator before calling
ds.add_data_requirements(). Assert that registration replaces the previous
iterator, then obtain subsequent batches and verify they use the newly
registered requirement signatures.

In `@source/tests/pt/test_lmdb_dataloader.py`:
- Around line 388-423: Extend the test around EnergyStdLoss to cover the force
branch using start_pref_f and limit_pref_f. Invoke the loss with a zero-force
model and force/find_force labels, asserting zero loss when find_force is 0.0
and positive loss when it is 1.0, alongside the existing energy assertions.
- Around line 407-408: Update the zero_energy_model closure in the loop so it
binds the current batch value at definition time, avoiding a late-bound
loop-variable closure flagged by Ruff B023 while preserving the existing energy
tensor behavior. Run ruff check . to verify the lint issue is resolved.
🪄 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: 2bd6db4e-0f72-43dd-8c28-134427b8cdbe

📥 Commits

Reviewing files that changed from the base of the PR and between 6c3b985 and 2fa9dae.

📒 Files selected for processing (7)
  • deepmd/dpmodel/utils/lmdb_data.py
  • deepmd/pt/train/validation.py
  • deepmd/pt/utils/lmdb_dataset.py
  • deepmd/pt_expt/utils/lmdb_dataset.py
  • source/tests/pt/test_lmdb_dataloader.py
  • source/tests/pt/test_validation.py
  • source/tests/pt_expt/test_lmdb_training.py

Comment thread deepmd/dpmodel/utils/lmdb_data.py Outdated
Comment thread source/tests/pt_expt/test_lmdb_training.py
Comment thread source/tests/pt/test_lmdb_dataloader.py
Comment thread source/tests/pt/test_lmdb_dataloader.py Outdated
Partition LMDB frames by atom count and scalar find-flag signature before training, statistics, auto-probability, and distributed batching. Allocate auto-probability expansion targets exactly across homogeneous groups so repeated rounding cannot over-sample a block.

Evaluate full LMDB validation in the same homogeneous groups so default-filled optional labels do not bias metrics. Cover standard PyTorch energy and force masking, iterator resets, distributed lengths, statistics loaders, pt_expt batches, and partial-label validation.

Coding-Agent: Codex
Codex-Version: codex-cli 0.144.4
Model: gpt-5.6-sol
Reasoning-Effort: xhigh
@njzjz-bot
njzjz-bot force-pushed the fix/lmdb-collate-find-flags-5636 branch from 2fa9dae to a5d7da6 Compare July 17, 2026 01:33

@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/common/dpmodel/test_lmdb_data.py (1)

752-753: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use batch.count to explicitly count occurrences.

Currently, index in batch evaluates to a boolean. This correctly counts the total frames here because the mock reader's batch size is explicitly set to 1. However, if the batch size were ever increased to pack multiple identical indices, this expression would only count the number of batches containing the index rather than the total occurrences. Using batch.count(index) is more robust and semantically clearer.

♻️ Proposed refactor
         batches = list(sampler)
-        counts = [sum(index in batch for batch in batches) for index in (0, 1)]
+        counts = [sum(batch.count(index) for batch in batches) for index in (0, 1)]
🤖 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/common/dpmodel/test_lmdb_data.py` around lines 752 - 753, Update
the counts comprehension in the sampler test to use batch.count(index) instead
of membership testing, so it sums all occurrences of each index across batches
rather than only counting batches that contain it.
🤖 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/common/dpmodel/test_lmdb_data.py`:
- Around line 752-753: Update the counts comprehension in the sampler test to
use batch.count(index) instead of membership testing, so it sums all occurrences
of each index across batches rather than only counting batches that contain it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2bf6ab22-4ac4-4374-82bd-0d46f30282c7

📥 Commits

Reviewing files that changed from the base of the PR and between 2fa9dae and a5d7da6.

📒 Files selected for processing (8)
  • deepmd/dpmodel/utils/lmdb_data.py
  • deepmd/pt/train/validation.py
  • deepmd/pt/utils/lmdb_dataset.py
  • deepmd/pt_expt/utils/lmdb_dataset.py
  • source/tests/common/dpmodel/test_lmdb_data.py
  • source/tests/pt/test_lmdb_dataloader.py
  • source/tests/pt/test_validation.py
  • source/tests/pt_expt/test_lmdb_training.py
🚧 Files skipped from review as they are similar to previous changes (7)
  • deepmd/pt_expt/utils/lmdb_dataset.py
  • deepmd/pt/train/validation.py
  • deepmd/pt/utils/lmdb_dataset.py
  • source/tests/pt_expt/test_lmdb_training.py
  • source/tests/pt/test_validation.py
  • source/tests/pt/test_lmdb_dataloader.py
  • deepmd/dpmodel/utils/lmdb_data.py

@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.07104% with 20 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.79%. Comparing base (cc908a8) to head (8c700fa).

Files with missing lines Patch % Lines
deepmd/dpmodel/utils/lmdb_data.py 89.17% 17 Missing ⚠️
deepmd/pt/train/validation.py 50.00% 2 Missing ⚠️
deepmd/pt/utils/lmdb_dataset.py 95.23% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5839      +/-   ##
==========================================
- Coverage   79.03%   78.79%   -0.25%     
==========================================
  Files        1055     1055              
  Lines      122233   122357     +124     
  Branches     4401     4401              
==========================================
- Hits        96607    96411     -196     
- Misses      24061    24380     +319     
- Partials     1565     1566       +1     

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

@njzjz

njzjz commented Jul 18, 2026

Copy link
Copy Markdown
Member

Possible reviewers based on changed lines, exact file history, and exact-file review history:

  • @wanghan-iapcm — 4 commits on changed files; 20 reviews on exact changed files (deepmd/dpmodel/utils/lmdb_data.py, deepmd/pt/train/validation.py, deepmd/pt/utils/lmdb_dataset.py, deepmd/pt_expt/utils/lmdb_dataset.py, source/tests/common/dpmodel/test_lmdb_data.py, source/tests/pt/test_lmdb_dataloader.py, source/tests/pt/test_validation.py, source/tests/pt_expt/test_lmdb_training.py).

No review request was made automatically.

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

@njzjz
njzjz requested review from wanghan-iapcm and removed request for wanghan-iapcm July 18, 2026 07:17

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

The core fix for #5636 is correct and well-tested — grouping by (nloc, availability-signature) and splitting validation metrics genuinely resolve the mixed-availability loss/metric contamination, and the new tests fail on pre-fix code. One blocking concern though: the grouping key-set and the collate guard disagree, which turns a previously-silent case into a hard training crash for exactly the merged multi-system LMDBs this PR targets. Detail inline. Plus a matching test-coverage gap.

Comment thread deepmd/dpmodel/utils/lmdb_data.py Outdated
Comment thread deepmd/pt/train/validation.py
Group training and validation frames by every availability field exposed to collation, including unrequested raw labels. Add coverage for optional virials and combined atom-count/label variation.

Coding-Agent: Codex
Codex-Version: codex-cli 0.144.6
Model: gpt-5.6-sol
Reasoning-Effort: xhigh
@njzjz
njzjz requested a review from wanghan-iapcm July 24, 2026 15:07

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

Both findings resolved; clearing my earlier request for changes.

The grouping/collation mismatch is genuinely closed. _availability_signature_keys now unions the registered requirements, the optional model inputs, and every non-structural field actually present in the frame, and because signatures are (find_key, bool) tuples a frame carrying an extra field gains an extra entry and therefore lands in its own group - so the case I raised (two systems merged into one LMDB, differing only by an unrequested virial) is partitioned before collate_lmdb_frames can reject it. test_unrequested_labels_form_homogeneous_batches reproduces exactly that setup and would hit the ValueError on the previous code.

The validation coverage gap is closed too: the new fixture varies both dimensions at once, and the test asserts against what actually reaches _evaluate_system, pinning all four (nloc, find_energy, find_force) groups rather than inferring them.

One consequence worth being aware of rather than acting on: grouping now splits on any differing non-structural field, so a dataset whose frames carry heterogeneous incidental labels will produce more partial batches, which feeds num_steps for epoch-based runs. That is the correct trade - it is precisely the condition collation rejects - but it is a behaviour change in batch counts.

@njzjz
njzjz added this pull request to the merge queue Jul 28, 2026
Merged via the queue into deepmodeling:master with commit e37cc00 Jul 28, 2026
58 checks passed
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.

[Code scan] Preserve per-frame find flags when collating LMDB batches

3 participants