Add PET models support - #129
Conversation
Signed-off-by: Arslan Mazitov <arslan.mazitov@phystech.edu>
Signed-off-by: Arslan Mazitov <arslan.mazitov@phystech.edu>
Signed-off-by: Arslan Mazitov <arslan.mazitov@phystech.edu>
Signed-off-by: Arslan Mazitov <arslan.mazitov@phystech.edu>
The pure-torch PETBackend extraction (metatensor/metatrain#1180) has landed on upstream main, so PETWrapper no longer needs the temporary extract-pet-core branch on the abmazitov/metatrain personal fork. Repoint [tool.uv.sources].metatrain at metatensor/metatrain@main. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LSNeCVGKxo2CzWiRpFMY2g
Signed-off-by: Arslan Mazitov <arslan.mazitov@phystech.edu>
Signed-off-by: Arslan Mazitov <arslan.mazitov@phystech.edu>
Signed-off-by: Arslan Mazitov <arslan.mazitov@phystech.edu>
Signed-off-by: Arslan Mazitov <arslan.mazitov@phystech.edu>
Greptile SummaryThis PR adds
Important Files Changed
Reviews (1): Last reviewed commit: "Updated docs" | Re-trigger Greptile |
| elif model is not None and version is not None: | ||
| checkpoint_path = _fetch_pet_checkpoint(model, version) |
There was a problem hiding this comment.
version=None is documented as equivalent to "latest" (see the version parameter docstring and _fetch_pet_checkpoint which maps None → requested_version=None), but the guard version is not None silently rejects it. A user who follows the documented interface — PETWrapper.from_checkpoint(model="pet-mad-s", version=None) — hits the else branch and receives a confusing ValueError telling them to provide checkpoint_path or model, even though they did provide model.
| elif model is not None and version is not None: | |
| checkpoint_path = _fetch_pet_checkpoint(model, version) | |
| elif model is not None: | |
| checkpoint_path = _fetch_pet_checkpoint(model, version) |
| checkpoint_path : Path | str | None | ||
| Path to a local PET checkpoint file (``.ckpt`` / ``.pt``), or a | ||
| named model such as ``"pet-mad-xs-v1.6.0"`` to fetch from | ||
| HuggingFace. If ``None``, *model* must be given instead. |
There was a problem hiding this comment.
The
checkpoint_path parameter docstring states it can be "a named model such as pet-mad-xs-v1.6.0 to fetch from HuggingFace", but the code never acts on a non-file checkpoint_path string — if the path does not exist as a local file, the branch falls straight to elif model is not None, completely ignoring checkpoint_path. A user who passes checkpoint_path="pet-mad-xs-v1.6.0" with model=None hits the else and gets a misleading ValueError. The docstring should be corrected to remove the HuggingFace-fetch promise for checkpoint_path (the model parameter is the correct handle for named HF models).
| checkpoint_path : Path | str | None | |
| Path to a local PET checkpoint file (``.ckpt`` / ``.pt``), or a | |
| named model such as ``"pet-mad-xs-v1.6.0"`` to fetch from | |
| HuggingFace. If ``None``, *model* must be given instead. | |
| checkpoint_path : Path | str | None | |
| Path to a local PET checkpoint file (``.ckpt`` / ``.pt``). | |
| If ``None``, *model* must be given instead to fetch a checkpoint | |
| by name from HuggingFace. |
| raise ValueError( | ||
| "PETWrapper.from_checkpoint requires either `checkpoint_path` (a " | ||
| "local file path, or `model` (e.g. 'pet-mad-s', optionally with `version`). " | ||
| ) |
There was a problem hiding this comment.
The error message has an unclosed opening parenthesis:
"(a local file path, or \model`...". The (anever closes, so the human-readable text reads awkwardly asrequires either `checkpoint_path` (a local file path, or `model` (e.g. …).`
| raise ValueError( | |
| "PETWrapper.from_checkpoint requires either `checkpoint_path` (a " | |
| "local file path, or `model` (e.g. 'pet-mad-s', optionally with `version`). " | |
| ) | |
| raise ValueError( | |
| "PETWrapper.from_checkpoint requires either `checkpoint_path` (a " | |
| "local file path) or `model` (e.g. 'pet-mad-s', optionally with `version`). " | |
| ) |
|
|
||
| import sys | ||
| import types | ||
|
|
||
| if "hostlist" not in sys.modules: | ||
| try: |
There was a problem hiding this comment.
Global
sys.modules mutation even in LJ-fallback path
The hostlist stub is injected unconditionally at module import time, so every user who imports or runs this example — even those who never load PET and fall back to LJ — silently get a fake hostlist entry registered in sys.modules. The guard if "hostlist" not in sys.modules mitigates the most common case, but the whole block could be moved inside the if PET_MODEL_PATH: branch so it only runs when PET is actually needed.
ALCHEMI Toolkit Pull Request
Description
This PR adds support for PET models from the
lab-cosmo/metatrainpackage directly innvalchemi-toolkit. It introduces thePETWrapperclass, which wrapsmetatrain.pet.modules.backend.PETBackend(a pure-torch module) withnvalchemi's systems management and IO handling, exposing it through the standardBaseModelMixininterface.PETWrappersupports all PET-MAD model checkpoints, as well as other PET-based models fromlab-cosmo/upet, and can fetch named checkpoints directly from HuggingFace or load local checkpoint files. The interface is torch-native and torch-compileable (fullgraph=True) for both forward energies and autograd forces.Type of Change
Related Issues
No related issues.
Changes Made
nvalchemi/models/pet.pyimplementingPETWrapper, aBaseModelMixinwrapper around metatrain's pure-torchPETBackend.PETWrapper.from_checkpoint, which loads a checkpoint either from a local path or by fetching a named PET-MAD/upetcheckpoint from thelab-cosmo/upetHuggingFace repository.PETinnvalchemi/_optional.pyas a new optional dependency, and exposedPETWrappervianvalchemi/models/__init__.py.petextra inpyproject.toml(pip install 'nvalchemi-toolkit[pet]'), pulling inmetatrainandupet. Pinnedmetatrainto the upstreammainbranch via[tool.uv.sources]until the pure-torchPETBackend(Extract pure-torch PET backend into a separate module metatensor/metatrain#1180) lands in a tagged PyPI release.filterwarningsentry inpyproject.tomlto suppresstorch.jit.script/torch.jit.script_methoddeprecation warnings emitted bymetatensor.torchat import time.pet.pythat stubs a fakehostlistmodule insys.moduleswhen the real package isn't installed, sincemetatrain.pet.__init__transitively importsmetatrain.utils.distributed.slurm, which requireshostlist— a package explicitly blocked in this toolkit's dependency overrides.test/models/test_pet.pywith unit tests coveringPETWrapperconstruction, forward/backward passes, and checkpoint loading.examples/advanced/10_pet_nvt.py, an example running NVT dynamics with a PET-MAD model, and linked it fromexamples/advanced/README.rst.CHANGELOG.mdwith an entry describing the newPETWrapper.uv.lock.Testing
make pytest)make lint)Checklist
Additional Notes
Known caveats / follow-ups left for later PRs:
hostlistdependency conflict is not resolved.metatrainpullspython-hostlistas a transitive dependency and imports it at first import. This package is explicitly blocked innvalchemi-toolkit's dependency overrides, and even thoughPETWrappernever uses it, we still have to hot-patchsys.modulesto stub it out so the import chain resolves.energyhead and conservative (autograd) forces are supported at the moment.PETWrapper.uv.lockwas regenerated. This was required to pick up the newmetatrain/upetdependencies from thepetextra (and themetatraingit source pin) — without regenerating it, the environment produced dependency conflicts.OptionalDependencyEnum apparently supports only one dependency per model. In the case of PET, at this moment, two dependencies are required:metatrainandupet. This detail requires adding a workaround for a failed import of theupetpackage, which cannot be done using theOptionalDependency.PETutility. It should be possible to get rid of themetatrainand only depend onupetsoon, but we need a release of both packages before that will happen.Tip
This repository uses Greptile, an AI code review service, to help conduct
pull request reviews. We encourage contributors to read and consider suggestions
made by Greptile, but note that human maintainers will provide the necessary
reviews for merging: Greptile's comments are not a qualitative judgement
of your code, nor is it an indication that the PR will be accepted/rejected.
We encourage the use of emoji reactions to Greptile comments, depending on
their usefulness and accuracy.