fix(dpmodel): support parameter shorthand in DeepEval#5853
Conversation
Normalize documented frame and atomic parameter shorthand before automatic batching. Add direct-backend coverage for shared inputs, forced batch splits, and invalid parameter sizes. Coding-Agent: Codex Codex-Version: codex-cli 0.144.4 Model: gpt-5.6-sol Reasoning-Effort: xhigh
for more information, see https://pre-commit.ci
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #5853 +/- ##
==========================================
- Coverage 78.58% 78.33% -0.25%
==========================================
Files 1050 1050
Lines 120637 120654 +17
Branches 4356 4356
==========================================
- Hits 94801 94515 -286
- Misses 24278 24579 +301
- Partials 1558 1560 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Possible reviewers based on changed lines, exact file history, and exact-file review history:
No review request was made automatically. Coding agent: Codex |
There was a problem hiding this comment.
Fix is correct. AutoBatchSize.execute_all slices only ndim > 1 args along axis 0, so a (natoms, dim_aparam) shorthand really was being sliced on its atom axis - canonicalizing before the batcher is the right place. I checked the size-dispatch for ambiguity: collisions occur only at n == 1 or natoms == 1, and in each the two branches produce the identical array, so the check order is safe. Predicate order matches _standard_input, so the public path stays idempotent with no double-tiling. All 8 new tests fail pre-fix, verified against an unpatched tree.
Two comments inline.
Merge ordering with #5852. It inserts at this same anchor and rewrites the out = self._eval_func(...) call this diff carries as context; git merge-tree confirms a real conflict, not just adjacency. Both PRs exist for the same reason - AutoBatchSize slices only frame-axis arrays - and spin is likewise unnormalized in _standard_input. Canonicalizing in the shared layer would cover spin, fparam and aparam together and collapse both PRs into one change.
Minor:
-
_standard_inputemits aparam as 2-D(nframes, natoms * dim_aparam); this returns 3-D._eval_modelreshapes either way, but it changes the internal boundary #4285 established without documenting it. -
AutoBatchSize.__init__takescurrent_batch_sizefromDP_INFER_BATCH_SIZEwhen set, overriding the constructor argument. Under that env var theauto_batch_size=6case stops splitting and silently becomes a duplicate ofFalse, so the only batching coverage disappears with no failure.monkeypatch.delenv("DP_INFER_BATCH_SIZE", raising=False)plus an assertion on the_eval_modelcall count would pin it. -
Validation is size-only, so a transposed
(dim_fparam, nframes)array passes and is reinterpreted row-major. Matches_standard_input, so not a regression, but it sits against the stated goal of explicit shape errors.
| natoms, numb_test = self._get_natoms_and_nframes( | ||
| coords, atom_types, len(atom_types.shape) > 1 | ||
| ) | ||
| # Canonicalize documented shorthand before AutoBatchSize sees it. |
There was a problem hiding this comment.
This ladder already exists in DeepEval._standard_input (deepmd/infer/deep_eval.py) - same three-way dispatch, same tiling, same wording. That placement was deliberate: #3213 put canonicalization in _standard_input, #3356 added this ladder there for every backend, and #4285 gave this adapter only the bare reshape because it consumes already-rectangular arrays.
The gap isn't dpmodel-specific. All three siblings reshape without tiling:
deepmd/pt/infer/deep_eval.py:695deepmd/jax/infer/deep_eval.py:411deepmd/pd/infer/deep_eval.py:544
while DeepEvalBackend.eval's docstring - the contract all of them implement - documents all three shorthands. So after this PR deep_eval.eval(fparam=<1-D>) succeeds on .dp and raises on .pth.
I'd rather see this fixed once in the shared layer than per backend: a DeepEvalBackend._canonicalize_params(fparam, aparam, nframes, natoms) called from each backend's eval covers all five at once. As written this is the third copy, and the copies already disagree - _standard_input says "frame param" where this says "atomic param", so the same bad input reports differently depending on entry point.
| ).reshape(len(ATOM_TYPES), 3) | ||
| BOX = np.diag([13.0, 13.0, 13.0]) | ||
| NFRAMES = 2 | ||
| COORDS = np.tile(COORD, (NFRAMES, 1, 1)) |
There was a problem hiding this comment.
COORDS = np.tile(COORD, (NFRAMES, 1, 1)) makes both frames byte-identical, and every test's parameters are frame-invariant, so nothing here distinguishes correct frame-major handling from "use frame 0's parameters everywhere".
The tests do fail pre-fix, but as a crash (cannot reshape array of size 2 into shape (1,6,2)), not as a wrong number - a regression that kept the shapes right while losing per-frame variation would pass all 8.
One case closes it: fparam (NFRAMES, dim) with distinct rows and aparam (NFRAMES, natoms, dim) with distinct frames, split vs unsplit, asserting both that the two agree and that the per-frame energies differ. The second assertion is what makes the first meaningful.
Closes #5662.
Summary
fparamandaparamshorthand into canonical frame-major arrays before automatic batchingWhy existing tests missed this
Normal public
DeepEval/DeepPotcalls pass through_standard_input, which already tiles shorthand before invoking a backend and therefore masks the dpmodel adapter defect. Existing.dpconsistency coverage uses one frame with full parameter shapes. No regression called the low-level dpmodel backend directly with multiple frames, nor forced automatic batching while passing(natoms, dim_aparam), which the batcher otherwise mistakes for a frame-major array and slices along the atom axis.Validation
pytest source/tests/infer/test_dpmodel_deep_eval_params.py -q(8 passed)DeepEvalcompatibility smoke test with forced one-frame batches (passed)ruff format .(1 new test file reformatted; 1663 files unchanged)ruff check .(passed)git diff --check(passed)Coding agent: Codex
Codex version: codex-cli 0.144.4
Model: gpt-5.6-sol
Reasoning effort: xhigh