Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
ec2e031
implement pytorch-exportable for se_e2_a descriptor
Feb 5, 2026
b8a48ff
better type for xp.zeros
Feb 5, 2026
1cc001f
implement env, base_descriptor and exclude_mask, remove the dependenc…
Feb 6, 2026
f2fbe88
mv to_torch_tensor to common
Feb 6, 2026
e2afbe9
simplify __init__ of the NaiveLayer
Feb 6, 2026
4ba511a
fix bug
Feb 6, 2026
fb9598a
fix bug
Feb 6, 2026
fa03351
simplify init method of se_e2_a descriptor. fig bug in consistent UT
Feb 6, 2026
09b33f1
restructure the test folders. add test_common.
Feb 6, 2026
67f2e54
add test_exclusion_mask.py
Feb 6, 2026
f7d83dd
fix poitential import issue in test.
Feb 6, 2026
0c96bb6
correct __call__(). fix bug
Feb 6, 2026
9dca912
fix registration issue
Feb 6, 2026
17f0a5d
fix pt-expt file extension
Feb 6, 2026
8ce93ba
fix(pt): expansion of get_default_nthreads()
Feb 6, 2026
3091988
fix bug of intra-inter
Feb 6, 2026
85f0583
fix bug of default dp inter value
Feb 6, 2026
d33324d
fix cicd
Feb 6, 2026
4de9a56
feat: add support for se_r
Feb 6, 2026
f4dc0af
fix device of xp array
Feb 6, 2026
2384835
fix device of xp array
Feb 6, 2026
9646d71
revert extend_coord_with_ghosts
Feb 6, 2026
f270069
raise error for non-implemented methods
Feb 6, 2026
57433d3
restore import torch
Feb 6, 2026
eedcbaf
fix(pt,pt-expt): guard thread setters
Feb 6, 2026
d8b2cf4
make exclusion mask modules
Feb 6, 2026
aeef15a
fix(pt-expt): clear params on None
Feb 6, 2026
8bdb1f8
fix bug
Feb 7, 2026
d3b01da
utility to handel dpmodel -> pt_expt conversion
Feb 8, 2026
3452a2a
fix to_numpy_array device
Feb 8, 2026
ba8e7ab
chore(dpmodel,pt_expt): refactorize the implementation of embedding net
Feb 8, 2026
621c7cc
feat: se_t and se_t_tebd descriptors for the pytroch exportable backend.
Feb 8, 2026
faa4026
fix bug
Feb 8, 2026
e263270
refact: fitting net
Feb 8, 2026
ea61141
fix bug
Feb 8, 2026
de8f156
merge master
Feb 8, 2026
ad83d98
Merge branch 'refact-auto-setattr' into refact-fitting-net
Feb 8, 2026
9311ed5
feat(pt_expt): add fitting
Feb 9, 2026
9472af7
merge master
Feb 10, 2026
6ef9cd8
merge with master
Feb 11, 2026
165d1df
fix the API consistency issue in descriptors
Feb 11, 2026
e76b702
feat: add stat for dpmodel's atomic model. implement atomic model for…
Feb 11, 2026
03974dd
merge master
Feb 12, 2026
fb08ffc
add missing file
Feb 12, 2026
f5171f2
merge master
Feb 12, 2026
a59c18d
fix test
Feb 12, 2026
d057ca1
fix test
Feb 12, 2026
d2e4faa
Merge branch 'feat-fitting' into feat-atomic-model
Feb 12, 2026
4437146
Merge remote-tracking branch 'upstream/master' into feat-atomic-model
Feb 13, 2026
4be000c
Merge branch 'master' into feat-atomic-model
wanghan-iapcm Feb 13, 2026
2ea6b74
simplify the code
Feb 14, 2026
459afa2
Merge remote-tracking branch 'origin/feat-atomic-model' into feat-ato…
Feb 14, 2026
21077bc
fix bug
Feb 14, 2026
bdd015c
fix issues
Feb 14, 2026
a9a924d
fix class level imports
Feb 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 180 additions & 0 deletions deepmd/dpmodel/atomic_model/base_atomic_model.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# SPDX-License-Identifier: LGPL-3.0-or-later
import math
from collections.abc import (
Callable,
)
from typing import (
Any,
)
Expand Down Expand Up @@ -30,6 +33,9 @@
map_atom_exclude_types,
map_pair_exclude_types,
)
from deepmd.utils.path import (
DPPath,
)

from .make_base_atomic_model import (
make_base_atomic_model,
Expand Down Expand Up @@ -246,6 +252,180 @@ def call(
aparam=aparam,
)

def get_intensive(self) -> bool:
"""Whether the fitting property is intensive."""
return False

def get_compute_stats_distinguish_types(self) -> bool:
"""Get whether the fitting net computes stats which are not distinguished between different types of atoms."""
return True
Comment thread
wanghan-iapcm marked this conversation as resolved.

def compute_or_load_out_stat(
self,
merged: Callable[[], list[dict]] | list[dict],
stat_file_path: DPPath | None = None,
) -> None:
"""
Compute the output statistics (e.g. energy bias) for the fitting net from packed data.

Parameters
----------
merged : Union[Callable[[], list[dict]], list[dict]]
- list[dict]: A list of data samples from various data systems.
Each element, `merged[i]`, is a data dictionary containing `keys`: `np.ndarray`
originating from the `i`-th data system.
- Callable[[], list[dict]]: A lazy function that returns data samples in the above format
only when needed. Since the sampling process can be slow and memory-intensive,
the lazy function helps by only sampling once.
stat_file_path : Optional[DPPath]
The path to the stat file.

"""
self.change_out_bias(
merged,
stat_file_path=stat_file_path,
bias_adjust_mode="set-by-statistic",
)

def change_out_bias(
self,
sample_merged: Callable[[], list[dict]] | list[dict],
stat_file_path: DPPath | None = None,
bias_adjust_mode: str = "change-by-statistic",
) -> None:
"""Change the output bias according to the input data and the pretrained model.

Parameters
----------
sample_merged : Union[Callable[[], list[dict]], list[dict]]
- list[dict]: A list of data samples from various data systems.
Each element, `merged[i]`, is a data dictionary containing `keys`: `np.ndarray`
originating from the `i`-th data system.
- Callable[[], list[dict]]: A lazy function that returns data samples in the above format
only when needed. Since the sampling process can be slow and memory-intensive,
the lazy function helps by only sampling once.
bias_adjust_mode : str
The mode for changing output bias : ['change-by-statistic', 'set-by-statistic']
'change-by-statistic' : perform predictions on labels of target dataset,
and do least square on the errors to obtain the target shift as bias.
'set-by-statistic' : directly use the statistic output bias in the target dataset.
stat_file_path : Optional[DPPath]
The path to the stat file.
"""
from deepmd.dpmodel.utils.stat import (
compute_output_stats,
)

if bias_adjust_mode == "change-by-statistic":
delta_bias, out_std = compute_output_stats(
sample_merged,
self.get_ntypes(),
keys=list(self.atomic_output_def().keys()),
stat_file_path=stat_file_path,
model_forward=self._get_forward_wrapper_func(),
rcond=self.rcond,
preset_bias=self.preset_out_bias,
stats_distinguish_types=self.get_compute_stats_distinguish_types(),
intensive=self.get_intensive(),
)
self._store_out_stat(delta_bias, out_std, add=True)
elif bias_adjust_mode == "set-by-statistic":
bias_out, std_out = compute_output_stats(
sample_merged,
self.get_ntypes(),
keys=list(self.atomic_output_def().keys()),
stat_file_path=stat_file_path,
rcond=self.rcond,
preset_bias=self.preset_out_bias,
stats_distinguish_types=self.get_compute_stats_distinguish_types(),
intensive=self.get_intensive(),
)
self._store_out_stat(bias_out, std_out)
else:
raise RuntimeError("Unknown bias_adjust_mode mode: " + bias_adjust_mode)
Comment thread
wanghan-iapcm marked this conversation as resolved.

def _store_out_stat(
self,
out_bias: dict[str, np.ndarray],
out_std: dict[str, np.ndarray],
add: bool = False,
) -> None:
"""Store output bias and std into the model."""
ntypes = self.get_ntypes()
out_bias_data = np.array(to_numpy_array(self.out_bias))
out_std_data = np.array(to_numpy_array(self.out_std))
for kk in out_bias.keys():
assert kk in out_std.keys()
idx = self._get_bias_index(kk)
size = self._varsize(self.atomic_output_def()[kk].shape)
if not add:
out_bias_data[idx, :, :size] = out_bias[kk].reshape(ntypes, size)
else:
out_bias_data[idx, :, :size] += out_bias[kk].reshape(ntypes, size)
out_std_data[idx, :, :size] = out_std[kk].reshape(ntypes, size)
self.out_bias = out_bias_data
self.out_std = out_std_data
Comment thread
wanghan-iapcm marked this conversation as resolved.

def _get_forward_wrapper_func(self) -> Callable[..., dict[str, np.ndarray]]:
"""Get a forward wrapper of the atomic model for output bias calculation."""
import array_api_compat

from deepmd.dpmodel.utils.nlist import (
extend_input_and_build_neighbor_list,
)

def model_forward(
coord: np.ndarray,
atype: np.ndarray,
box: np.ndarray | None,
fparam: np.ndarray | None = None,
aparam: np.ndarray | None = None,
) -> dict[str, np.ndarray]:
# Get reference array to determine the target array type and device
# Use out_bias as reference since it's always present
ref_array = self.out_bias
xp = array_api_compat.array_namespace(ref_array)

# Convert numpy inputs to the model's array type with correct device
device = array_api_compat.device(ref_array)
coord = xp.asarray(coord, device=device)
atype = xp.asarray(atype, device=device)
if box is not None:
if np.allclose(box, 0.0):
box = None
else:
box = xp.asarray(box, device=device)
if fparam is not None:
fparam = xp.asarray(fparam, device=device)
if aparam is not None:
aparam = xp.asarray(aparam, device=device)

(
extended_coord,
extended_atype,
mapping,
nlist,
) = extend_input_and_build_neighbor_list(
coord,
atype,
self.get_rcut(),
self.get_sel(),
mixed_types=self.mixed_types(),
box=box,
)
atomic_ret = self.forward_common_atomic(
extended_coord,
extended_atype,
nlist,
mapping=mapping,
fparam=fparam,
aparam=aparam,
)
# Convert outputs back to numpy arrays
return {kk: to_numpy_array(vv) for kk, vv in atomic_ret.items()}

return model_forward

def serialize(self) -> dict:
return {
"type_map": self.type_map,
Expand Down
3 changes: 2 additions & 1 deletion deepmd/dpmodel/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ def to_numpy_array(x: Optional["Array"]) -> np.ndarray | None:
try:
# asarray is not within Array API standard, so may fail
return np.asarray(x)
except (ValueError, AttributeError, TypeError):
except (ValueError, AttributeError, TypeError, RuntimeError):
# RuntimeError: handles torch tensors with requires_grad=True
xp = array_api_compat.array_namespace(x)
# to fix BufferError: Cannot export readonly array since signalling readonly is unsupported by DLPack.
# Move to CPU device to ensure numpy compatibility
Expand Down
Loading