Skip to content

Commit 637cf68

Browse files
authored
Merge branch 'master' into 0225-lmdb-dataloader
2 parents 3e2e77b + efc27cf commit 637cf68

230 files changed

Lines changed: 25141 additions & 1607 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build_wheel.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ jobs:
187187
steps:
188188
- name: Deploy to GitHub Pages
189189
id: deployment
190-
uses: actions/deploy-pages@v4
190+
uses: actions/deploy-pages@v5
191191

192192
pass:
193193
name: Pass testing build wheels

.github/workflows/test_cc.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ jobs:
9898
ENABLE_JAX: ${{ matrix.enable_tensorflow && '1' || '0' }}
9999
ENABLE_PADDLE: ${{ matrix.enable_paddle && '1' || '0' }}
100100
if: ${{ !matrix.check_memleak }}
101-
- uses: codecov/codecov-action@v5
101+
- uses: codecov/codecov-action@v6
102102
with:
103103
use_oidc: true
104104
permissions:

.github/workflows/test_python.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ jobs:
7676
name: split-${{ matrix.python }}-${{ matrix.group }}
7777
path: .test_durations_${{ matrix.group }}
7878
include-hidden-files: true
79-
- uses: codecov/codecov-action@v5
79+
- uses: codecov/codecov-action@v6
8080
with:
8181
use_oidc: true
8282
permissions:

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ test_dp_test_*.out
6262

6363
# Training and model output files
6464
*.pth
65+
*.pte
66+
*.pt2
6567
*.ckpt*
6668
checkpoint
6769
lcurve.out

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ repos:
3030
exclude: ^source/3rdparty
3131
- repo: https://github.com/astral-sh/ruff-pre-commit
3232
# Ruff version.
33-
rev: v0.15.6
33+
rev: v0.15.8
3434
hooks:
3535
- id: ruff
3636
args: ["--fix"]
@@ -62,7 +62,7 @@ repos:
6262
- mdformat-gfm-alerts==2.0.0
6363
# C++
6464
- repo: https://github.com/pre-commit/mirrors-clang-format
65-
rev: v22.1.1
65+
rev: v22.1.2
6666
hooks:
6767
- id: clang-format
6868
exclude: ^(source/3rdparty|source/lib/src/gpu/cudart/.+\.inc|.+\.ipynb$|source/tests/infer/.+\.json$)
@@ -76,7 +76,7 @@ repos:
7676
exclude: ^(source/3rdparty|\.clang-format)
7777
# Shell
7878
- repo: https://github.com/scop/pre-commit-shfmt
79-
rev: v3.12.0-2
79+
rev: v3.13.0-1
8080
hooks:
8181
- id: shfmt
8282
# CMake

deepmd/backend/pt_expt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class PyTorchExportableBackend(Backend):
4141
| Backend.Feature.IO
4242
)
4343
"""The features of the backend."""
44-
suffixes: ClassVar[list[str]] = [".pte"]
44+
suffixes: ClassVar[list[str]] = [".pte", ".pt2"]
4545
"""The suffixes of the backend."""
4646

4747
def is_available(self) -> bool:

deepmd/dpmodel/atomic_model/base_atomic_model.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,20 @@ def change_type_map(
206206
self.reinit_pair_exclude(
207207
map_pair_exclude_types(self.pair_exclude_types, remap_index)
208208
)
209+
if has_new_type:
210+
xp = array_api_compat.array_namespace(self.out_bias)
211+
extend_shape = [
212+
self.out_bias.shape[0],
213+
len(type_map),
214+
*list(self.out_bias.shape[2:]),
215+
]
216+
device = array_api_compat.device(self.out_bias)
217+
extend_bias = xp.zeros(
218+
extend_shape, dtype=self.out_bias.dtype, device=device
219+
)
220+
self.out_bias = xp.concat([self.out_bias, extend_bias], axis=1)
221+
extend_std = xp.ones(extend_shape, dtype=self.out_std.dtype, device=device)
222+
self.out_std = xp.concat([self.out_std, extend_std], axis=1)
209223
self.out_bias = self.out_bias[:, remap_index, :]
210224
self.out_std = self.out_std[:, remap_index, :]
211225

deepmd/dpmodel/atomic_model/linear_atomic_model.py

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@
1717
get_multiple_nlist_key,
1818
nlist_distinguish_types,
1919
)
20-
from deepmd.env import (
21-
GLOBAL_NP_FLOAT_PRECISION,
22-
)
2320
from deepmd.utils.path import (
2421
DPPath,
2522
)
@@ -70,6 +67,7 @@ def __init__(
7067
self,
7168
models: list[BaseAtomicModel],
7269
type_map: list[str],
70+
weights: str | list[float] = "mean",
7371
**kwargs: Any,
7472
) -> None:
7573
super().__init__(type_map, **kwargs)
@@ -100,6 +98,15 @@ def __init__(
10098
self.mapping_list = mapping_list
10199
assert len(err_msg) == 0, "\n".join(err_msg)
102100
self.mixed_types_list = [model.mixed_types() for model in self.models]
101+
if isinstance(weights, str):
102+
assert weights in ["sum", "mean"]
103+
elif isinstance(weights, list):
104+
assert len(weights) == len(models)
105+
else:
106+
raise ValueError(
107+
f"'weights' must be a string ('sum' or 'mean') or a list of float of length {len(models)}."
108+
)
109+
self.weights = weights
103110

104111
def mixed_types(self) -> bool:
105112
"""If true, the model
@@ -241,7 +248,7 @@ def forward_atomic(
241248
the result dict, defined by the fitting net output def.
242249
"""
243250
xp = array_api_compat.array_namespace(extended_coord, extended_atype, nlist)
244-
nframes, nloc, nnei = nlist.shape
251+
nframes, _nloc, _nnei = nlist.shape
245252
extended_coord = xp.reshape(extended_coord, (nframes, -1, 3))
246253
sorted_rcuts, sorted_sels = self._sort_rcuts_sels()
247254
nlists = build_multiple_neighbor_list(
@@ -323,20 +330,23 @@ def serialize(self) -> dict:
323330
dd.update(
324331
{
325332
"@class": "Model",
326-
"@version": 2,
333+
"@version": 3,
327334
"type": "linear",
328335
"models": [model.serialize() for model in self.models],
329336
"type_map": self.type_map,
337+
"weights": self.weights,
330338
}
331339
)
332340
return dd
333341

334342
@classmethod
335343
def deserialize(cls, data: dict) -> "LinearEnergyAtomicModel":
336344
data = data.copy()
337-
check_version_compatibility(data.pop("@version", 2), 2, 2)
345+
check_version_compatibility(data.pop("@version", 2), 3, 2)
338346
data.pop("@class", None)
339347
data.pop("type", None)
348+
if "weights" not in data:
349+
data["weights"] = "mean"
340350
models = [
341351
BaseAtomicModel.get_class_by_type(model["type"]).deserialize(model)
342352
for model in data["models"]
@@ -396,16 +406,33 @@ def _compute_weight(
396406
nlists_: list[Array],
397407
) -> list[Array]:
398408
"""This should be a list of user defined weights that matches the number of models to be combined."""
399-
xp = array_api_compat.array_namespace(extended_coord, extended_atype, nlists_)
409+
xp = array_api_compat.array_namespace(extended_coord, extended_atype)
400410
nmodels = len(self.models)
401411
nframes, nloc, _ = nlists_[0].shape
402412
dev = array_api_compat.device(extended_coord)
403-
# the dtype of weights is the interface data type.
404-
return [
405-
xp.ones((nframes, nloc, 1), dtype=GLOBAL_NP_FLOAT_PRECISION, device=dev)
406-
/ nmodels
407-
for _ in range(nmodels)
408-
]
413+
if isinstance(self.weights, str):
414+
if self.weights == "sum":
415+
return [
416+
xp.ones((nframes, nloc, 1), dtype=extended_coord.dtype, device=dev)
417+
for _ in range(nmodels)
418+
]
419+
elif self.weights == "mean":
420+
return [
421+
xp.ones((nframes, nloc, 1), dtype=extended_coord.dtype, device=dev)
422+
/ nmodels
423+
for _ in range(nmodels)
424+
]
425+
else:
426+
raise ValueError(
427+
"`weights` must be 'sum' or 'mean' when provided as a string."
428+
)
429+
elif isinstance(self.weights, list):
430+
return [
431+
xp.ones((nframes, nloc, 1), dtype=extended_coord.dtype, device=dev) * w
432+
for w in self.weights
433+
]
434+
else:
435+
raise NotImplementedError
409436

410437
def get_dim_fparam(self) -> int:
411438
"""Get the number (dimension) of frame parameters of this atomic model."""

deepmd/dpmodel/atomic_model/property_atomic_model.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def __init__(
2727

2828
def get_compute_stats_distinguish_types(self) -> bool:
2929
"""Get whether the fitting net computes stats which are not distinguished between different types of atoms."""
30-
return False
30+
return self.fitting_net.get_distinguish_types()
3131

3232
def get_intensive(self) -> bool:
3333
"""Whether the fitting property is intensive."""
@@ -51,6 +51,10 @@ def apply_out_stat(
5151
5252
"""
5353
out_bias, out_std = self._fetch_out_stat(self.bias_keys)
54-
for kk in self.bias_keys:
55-
ret[kk] = ret[kk] * out_std[kk][0] + out_bias[kk][0]
54+
if self.get_compute_stats_distinguish_types():
55+
for kk in self.bias_keys:
56+
ret[kk] = ret[kk] * out_std[kk][atype] + out_bias[kk][atype]
57+
else:
58+
for kk in self.bias_keys:
59+
ret[kk] = ret[kk] * out_std[kk][0] + out_bias[kk][0]
5660
return ret

deepmd/dpmodel/descriptor/dpa1.py

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from deepmd.dpmodel.array_api import (
2121
Array,
2222
xp_take_along_axis,
23+
xp_take_first_n,
2324
)
2425
from deepmd.dpmodel.common import (
2526
cast_precision,
@@ -344,6 +345,7 @@ def __init__(
344345
self.concat_output_tebd = concat_output_tebd
345346
self.trainable = trainable
346347
self.precision = precision
348+
self.compress = False
347349

348350
def get_rcut(self) -> float:
349351
"""Returns the cut-off radius."""
@@ -535,7 +537,7 @@ def call(
535537
(nf, nall, self.tebd_dim),
536538
)
537539
# nfnl x tebd_dim
538-
atype_embd = atype_embd_ext[:, :nloc, :]
540+
atype_embd = xp_take_first_n(atype_embd_ext, 1, nloc)
539541
grrg, g2, h2, rot_mat, sw = self.se_atten(
540542
nlist,
541543
coord_ext,
@@ -557,7 +559,7 @@ def serialize(self) -> dict:
557559
data = {
558560
"@class": "Descriptor",
559561
"type": "dpa1",
560-
"@version": 2,
562+
"@version": 3 if self.compress else 2,
561563
"rcut": obj.rcut,
562564
"rcut_smth": obj.rcut_smth,
563565
"sel": obj.sel,
@@ -602,20 +604,36 @@ def serialize(self) -> dict:
602604
}
603605
if obj.tebd_input_mode in ["strip"]:
604606
data.update({"embeddings_strip": obj.embeddings_strip.serialize()})
607+
if self.compress:
608+
compress_dict: dict = {
609+
"@variables": {
610+
"type_embd_data": to_numpy_array(self.type_embd_data),
611+
},
612+
"geo_compress": self.geo_compress,
613+
}
614+
if self.geo_compress:
615+
compress_dict["@variables"]["compress_data"] = [
616+
to_numpy_array(d) for d in self.compress_data
617+
]
618+
compress_dict["@variables"]["compress_info"] = [
619+
to_numpy_array(i) for i in self.compress_info
620+
]
621+
data["compress"] = compress_dict
605622
return data
606623

607624
@classmethod
608625
def deserialize(cls, data: dict) -> "DescrptDPA1":
609626
"""Deserialize from dict."""
610627
data = data.copy()
611-
check_version_compatibility(data.pop("@version"), 2, 1)
628+
check_version_compatibility(data.pop("@version"), 3, 1)
612629
data.pop("@class")
613630
data.pop("type")
614631
variables = data.pop("@variables")
615632
embeddings = data.pop("embeddings")
616633
type_embedding = data.pop("type_embedding")
617634
attention_layers = data.pop("attention_layers")
618635
env_mat = data.pop("env_mat")
636+
compress = data.pop("compress", None)
619637
tebd_input_mode = data["tebd_input_mode"]
620638
if tebd_input_mode in ["strip"]:
621639
embeddings_strip = data.pop("embeddings_strip")
@@ -637,8 +655,20 @@ def deserialize(cls, data: dict) -> "DescrptDPA1":
637655
obj.se_atten.dpa1_attention = NeighborGatedAttention.deserialize(
638656
attention_layers
639657
)
658+
if compress is not None:
659+
obj._load_compress_data(compress)
640660
return obj
641661

662+
def _load_compress_data(self, compress: dict) -> None:
663+
"""Load compression state from serialized data."""
664+
variables = compress["@variables"]
665+
self.type_embd_data = variables["type_embd_data"]
666+
self.geo_compress = compress.get("geo_compress", False)
667+
if self.geo_compress:
668+
self.compress_data = variables["compress_data"]
669+
self.compress_info = variables["compress_info"]
670+
self.compress = True
671+
642672
@classmethod
643673
def update_sel(
644674
cls,
@@ -1057,7 +1087,7 @@ def call(
10571087
self.stddev[...],
10581088
)
10591089
nf, nloc, nnei, _ = dmatrix.shape
1060-
atype = atype_ext[:, :nloc]
1090+
atype = xp_take_first_n(atype_ext, 1, nloc)
10611091
exclude_mask = self.emask.build_type_exclude_mask(nlist, atype_ext)
10621092
# nfnl x nnei
10631093
exclude_mask = xp.reshape(exclude_mask, (nf * nloc, nnei))
@@ -1076,6 +1106,12 @@ def call(
10761106
nlist_masked = xp.where(nlist_mask, nlist, xp.zeros_like(nlist))
10771107
ng = self.neuron[-1]
10781108
nt = self.tebd_dim
1109+
1110+
# Gather neighbor info using xp_take_along_axis along axis=1.
1111+
# This avoids flat (nf*nall,) indexing that creates Ne(nall, nloc)
1112+
# constraints in torch.export, breaking NoPbc (nall == nloc).
1113+
nlist_2d = xp.reshape(nlist_masked, (nf, nloc * nnei)) # (nf, nloc*nnei)
1114+
10791115
# nfnl x nnei x 4
10801116
rr = xp.reshape(dmatrix, (nf * nloc, nnei, 4))
10811117
rr = rr * xp.astype(exclude_mask[:, :, None], rr.dtype)
@@ -1084,15 +1120,16 @@ def call(
10841120
if self.tebd_input_mode in ["concat"]:
10851121
# nfnl x tebd_dim
10861122
atype_embd = xp.reshape(
1087-
atype_embd_ext[:, :nloc, :], (nf * nloc, self.tebd_dim)
1123+
xp_take_first_n(atype_embd_ext, 1, nloc), (nf * nloc, self.tebd_dim)
10881124
)
10891125
# nfnl x nnei x tebd_dim
10901126
atype_embd_nnei = xp.tile(atype_embd[:, xp.newaxis, :], (1, nnei, 1))
1091-
index = xp.tile(
1092-
xp.reshape(nlist_masked, (nf, -1, 1)), (1, 1, self.tebd_dim)
1127+
# Gather neighbor type embeddings: (nf, nall, tebd_dim) -> (nf, nloc*nnei, tebd_dim)
1128+
nlist_idx_tebd = xp.tile(nlist_2d[:, :, xp.newaxis], (1, 1, self.tebd_dim))
1129+
atype_embd_nlist = xp_take_along_axis(
1130+
atype_embd_ext, nlist_idx_tebd, axis=1
10931131
)
10941132
# nfnl x nnei x tebd_dim
1095-
atype_embd_nlist = xp_take_along_axis(atype_embd_ext, index, axis=1)
10961133
atype_embd_nlist = xp.reshape(
10971134
atype_embd_nlist, (nf * nloc, nnei, self.tebd_dim)
10981135
)
@@ -1111,10 +1148,9 @@ def call(
11111148
assert self.embeddings_strip is not None
11121149
assert type_embedding is not None
11131150
ntypes_with_padding = type_embedding.shape[0]
1114-
# nf x (nl x nnei)
1115-
nlist_index = xp.reshape(nlist_masked, (nf, nloc * nnei))
1116-
# nf x (nl x nnei)
1117-
nei_type = xp_take_along_axis(atype_ext, nlist_index, axis=1)
1151+
# Gather neighbor types: (nf, nall) -> (nf, nloc*nnei)
1152+
nei_type = xp_take_along_axis(atype_ext, nlist_2d, axis=1)
1153+
nei_type = xp.reshape(nei_type, (-1,)) # (nf * nloc * nnei,)
11181154
# (nf x nl x nnei) x ng
11191155
nei_type_index = xp.tile(xp.reshape(nei_type, (-1, 1)), (1, ng))
11201156
if self.type_one_side:

0 commit comments

Comments
 (0)