Skip to content

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

Open
njzjz-bot wants to merge 1 commit into
deepmodeling:masterfrom
njzjz-bot:fix/lmdb-collate-find-flags-5636
Open

fix(data): preserve LMDB label availability across batches#5839
njzjz-bot wants to merge 1 commit 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 now batches frames by both atom count and label-availability consistency, avoiding mixed scalar label flags.
    • Validation now groups evaluation by consistent label availability so default-filled/missing labels are excluded from computed metrics.
    • Collation now detects and rejects batches where label-availability flags are inconsistent across frames (raises a clear error).
    • LMDB dataset loaders now refresh appropriately after adding data requirements and are created lazily.
  • Tests
    • Added coverage for partially labeled LMDBs, homogeneous loss-batch formation, validator behavior, and sampler 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

📝 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, 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 reviewers: njzjz

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.37% 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
Linked Issues check ✅ Passed The changes address #5636 by preserving per-frame find flags through homogeneous batching and adding regression tests for partial labels.
Out of Scope Changes check ✅ Passed The modified files stay focused on LMDB label-availability handling, batching, validation, and related regression coverage.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: preserving LMDB label availability semantics across batches.
✨ 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 88.88889% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.33%. Comparing base (6c3b985) to head (a5d7da6).

Files with missing lines Patch % Lines
deepmd/dpmodel/utils/lmdb_data.py 88.96% 16 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   78.58%   78.33%   -0.26%     
==========================================
  Files        1050     1050              
  Lines      120637   120751     +114     
  Branches     4356     4357       +1     
==========================================
- Hits        94801    94586     -215     
- Misses      24278    24593     +315     
- Partials     1558     1572      +14     

☔ 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 a review from wanghan-iapcm July 18, 2026 07:17
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

2 participants