fix(tf2): reject unsupported custom neighbor lists - #5858
Conversation
Fail fast when TF2 SavedModel inference receives a custom neighbor_list. The exported tensor signatures cannot carry an ASE Python object, so accepting it would silently fall back to native neighbor construction. Coding-Agent: Codex Codex-Version: codex-cli 0.144.4 Model: gpt-5.6-sol Reasoning-Effort: xhigh
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthrough
ChangesTF2 neighbor list validation
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #5858 +/- ##
==========================================
+ Coverage 78.58% 78.96% +0.37%
==========================================
Files 1050 1069 +19
Lines 120637 124072 +3435
Branches 4356 4527 +171
==========================================
+ Hits 94801 97971 +3170
- Misses 24278 24482 +204
- Partials 1558 1619 +61 ☔ 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 |
wanghan-iapcm
left a comment
There was a problem hiding this comment.
The fix itself is good. The guard is correctly ordered (after the extension check, before TF2SavedModelWrapper touches the filesystem), is not None is the right predicate for a keyword-only argument that defaults to None, there is no bypass through DeepPot / DeepEval / deepmd/calculator.py, and NotImplementedError matches both the codebase convention for an unsupported backend feature and what #5667 asked for. I ran the new test against the base commit and it fails there (OSError: SavedModel file does not exist at: sentinel.savedmodeltf/..., i.e. no NotImplementedError and execution reaches the loader) and passes at the head - a real regression test. Using a sentinel filename to prove the raise precedes model loading, without needing a fixture, is a nice touch.
One blocking item, inline: the new test file drops the module guard that isolates this directory, and one CI job collects it without the corresponding --ignore.
Smaller notes, none blocking:
-
The code comment says supporting this "requires an ASE-to-extended-tensors adapter and output fold-back". Both already exist in-tree:
_build_nlist_aseindeepmd/pt_expt/infer/deep_eval.pyis pure NumPy and returns exactly(extended_coord, extended_atype, nlist, mapping);deepmd/tf2/utils/serialization.pyalready tracescall_lower(coord, atype, nlist, mapping, fparam, aparam)with fully dynamicTensorSpecshapes; andcommunicate_extended_outputlives indeepmd/tf2/transform_output.pyand is already used for fold-back indeepmd/tf2/model/make_model.py. Real support is still non-trivial glue -_eval_modelcurrently calls the high-levelcall, notcall_lower, and the adapter's module imports torch at top level so it would need extracting - but it is composition of existing parts, not new architecture. Worth softening the comment so the next maintainer does not read it as blocked. -
The shared docstrings still promise this unconditionally -
DeepEvalBackend.__init__andDeepEval.__init__indeepmd/infer/deep_eval.py, andDeepPotindeepmd/infer/deep_pot.py, all say "The ASE neighbor list class to produce the neighbor list. If None, the neighbor list will be built natively in the model." A one-line backend caveat there would stopDeepPot("model.savedmodeltf", neighbor_list=nl)being a documented call that now raises. -
The test that would prevent this recurring is
TestDeepPotNeighborListinsource/tests/infer/test_models.py, which is parameterized to.pbonly while the baseTestDeepPotruns a four-way matrix. Extending that matrix is what would catch the next backend to copy the signature forward; a tf2-only "it raises" test cannot. -
Out of scope for this PR, but worth a follow-up issue: after this merges the same call behaves three ways - implemented for
.pband.pt2, silently ignored for.pth,.pd,.dpand.savedmodel, and raising for.savedmodeltf. Notedeepmd/pt/infer/deep_eval.pybelongs in the second group despite storing the value: its only read isase_provided = self.neighbor_list is not None, so the ASE object itself is never used to build a neighbor list.pd,jaxanddpmodeladditionally document the parameter while ignoring it.
Address the outstanding requested-change review comments. Coding-Agent: Codex Codex-Version: codex-cli 0.144.6 Model: gpt-5.6-sol Reasoning-Effort: xhigh
wanghan-iapcm
left a comment
There was a problem hiding this comment.
The guard is in the right place -- import pytest, then the DP_TEST_TF2_ONLY skip with allow_module_level=True, then the deepmd imports. That ordering is the whole point, since the import itself is what pulls in TensorFlow, and it now matches test_training.py. The test_cuda.yml job that runs a bare python -m pytest source/tests will skip this module at collection rather than loading the TF2 eager stack into a process that also holds TF1, PyTorch, JAX and Paddle.
Thanks for correcting the implementation comment too. Saying the wrapper "does not yet connect the existing adapter and output fold-back helpers" is accurate, where the original read as though the pieces did not exist.
The guard ordering inside DeepEval.__init__ is unchanged: extension check, then the neighbor_list rejection, then TF2SavedModelWrapper, so nothing touches the filesystem before the raise.
My remaining notes are unaddressed and I am not asking for them here -- the docstrings in deepmd/infer/deep_eval.py still promise the parameter unconditionally, and TestDeepPotNeighborList is still .pb-only. Both are really facets of the wider problem that neighbor_list now behaves three different ways depending on the model extension, so I have opened #5941 to track that rather than expanding this PR.
Closes #5667.
Summary
Why existing tests missed this
Validation
Coding agent: Codex
Codex version: codex-cli 0.144.4
Model: gpt-5.6-sol
Reasoning effort: xhigh
Summary by CodeRabbit