Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
584613b
Add pt2 format for C/C++ inference.
Mar 7, 2026
98fa3fa
fix(dpmodel): fix NoPbc for DPA1 pt2 export and unify test models
Mar 7, 2026
6f7c11f
feat(c++): add DPA2 C++ inference tests and fix mapping bug in all ba…
Mar 8, 2026
f92b408
feat(c++): add DPA3 .pt2 export and C/C++ inference tests
Mar 9, 2026
46908c0
fix(ci): restore pre-committed .pth files and handle missing custom ops
Mar 9, 2026
da5579d
temporarily clears the default device (None) before calling aoti_comp…
Mar 9, 2026
0091315
fix issue of c/c++ ut
Mar 9, 2026
46c56e3
check the size validity
Mar 9, 2026
1ec9b85
fix: zip 64-bit widths
Mar 9, 2026
fbb8a61
rm dead code
Mar 9, 2026
7530a6e
fix: trace on CPU during export to avoid CUDA stream assert in make_fx
Mar 9, 2026
0269ef7
fix: trace on CPU then move to target device for CUDA-compatible export
Mar 9, 2026
f120319
fix(ci): preload LSAN runtime for gen scripts in sanitizer builds
Mar 9, 2026
f60f423
fix(export): use move_to_device_pass for CPU→CUDA device relocation
Mar 10, 2026
f564b1a
fix: harden C++ parser, fix CI gen script failures
Mar 10, 2026
cd90c31
fix(ci): clear LD_PRELOAD before AOTInductor compilation
Mar 10, 2026
914f401
feat(c++): implement has_default_fparam for pt_expt backend
Mar 21, 2026
9f52a35
fix: address coderabbitai review comments on PR #5298
Mar 21, 2026
5b346f6
fix(ci): don't preload LSAN into gen script Python processes
Mar 21, 2026
4b1f897
fix: resolve github-advanced-security alerts
Mar 21, 2026
1aded45
fix(ci): preload LSAN with detect_leaks=0 for gen scripts
Mar 21, 2026
59a3bf7
fix(build): guard pt_expt C++ backend on AOTInductor header availability
Mar 21, 2026
460ccf7
fix: move _load_custom_ops after deepmd.pt import in gen scripts
Mar 22, 2026
dd0b96a
fix(ci): install custom op .so to deepmd/lib before gen scripts
Mar 22, 2026
dd75039
fix(ci): add install prefix to LD_LIBRARY_PATH for gen scripts
Mar 22, 2026
00327cc
fix(ci): use SHARED_LIB_DIR to find correct custom op install path
Mar 22, 2026
7e04ad5
fix(ci): guard gen scripts behind ENABLE_PYTORCH and clean up test_cc…
Mar 22, 2026
f25a800
fix: address CodeQL alerts — integer overflow and duplicate import
Mar 23, 2026
6434c9a
fix(pt): add fallback stub for tabulate_fusion_se_t_tebd custom op
Mar 23, 2026
6d21400
fix: widen all int operands in fold_back to ptrdiff_t
Mar 23, 2026
a2ec6f7
merge upstream/master into feat-pt-expt-c
Mar 23, 2026
f911ee0
refactor: extract common gen script helpers into gen_common.py
Mar 23, 2026
ce9f3dd
refactor: simplify custom op .so install in test_cc_local.sh
Mar 23, 2026
00fcba0
merge upstream/master into feat-pt-expt-c
Mar 24, 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
2 changes: 1 addition & 1 deletion deepmd/backend/pt_expt.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class PyTorchExportableBackend(Backend):
| Backend.Feature.IO
)
"""The features of the backend."""
suffixes: ClassVar[list[str]] = [".pte"]
suffixes: ClassVar[list[str]] = [".pte", ".pt2"]
"""The suffixes of the backend."""

def is_available(self) -> bool:
Expand Down
27 changes: 17 additions & 10 deletions deepmd/dpmodel/descriptor/dpa1.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from deepmd.dpmodel.array_api import (
Array,
xp_take_along_axis,
xp_take_first_n,
)
from deepmd.dpmodel.common import (
cast_precision,
Expand Down Expand Up @@ -536,7 +537,7 @@ def call(
(nf, nall, self.tebd_dim),
)
# nfnl x tebd_dim
atype_embd = atype_embd_ext[:, :nloc, :]
atype_embd = xp_take_first_n(atype_embd_ext, 1, nloc)
grrg, g2, h2, rot_mat, sw = self.se_atten(
nlist,
coord_ext,
Expand Down Expand Up @@ -1086,7 +1087,7 @@ def call(
self.stddev[...],
)
nf, nloc, nnei, _ = dmatrix.shape
atype = atype_ext[:, :nloc]
atype = xp_take_first_n(atype_ext, 1, nloc)
exclude_mask = self.emask.build_type_exclude_mask(nlist, atype_ext)
# nfnl x nnei
exclude_mask = xp.reshape(exclude_mask, (nf * nloc, nnei))
Expand All @@ -1105,6 +1106,12 @@ def call(
nlist_masked = xp.where(nlist_mask, nlist, xp.zeros_like(nlist))
ng = self.neuron[-1]
nt = self.tebd_dim

# Gather neighbor info using xp_take_along_axis along axis=1.
# This avoids flat (nf*nall,) indexing that creates Ne(nall, nloc)
# constraints in torch.export, breaking NoPbc (nall == nloc).
nlist_2d = xp.reshape(nlist_masked, (nf, nloc * nnei)) # (nf, nloc*nnei)

# nfnl x nnei x 4
rr = xp.reshape(dmatrix, (nf * nloc, nnei, 4))
rr = rr * xp.astype(exclude_mask[:, :, None], rr.dtype)
Expand All @@ -1113,15 +1120,16 @@ def call(
if self.tebd_input_mode in ["concat"]:
# nfnl x tebd_dim
atype_embd = xp.reshape(
atype_embd_ext[:, :nloc, :], (nf * nloc, self.tebd_dim)
xp_take_first_n(atype_embd_ext, 1, nloc), (nf * nloc, self.tebd_dim)
)
# nfnl x nnei x tebd_dim
atype_embd_nnei = xp.tile(atype_embd[:, xp.newaxis, :], (1, nnei, 1))
index = xp.tile(
xp.reshape(nlist_masked, (nf, -1, 1)), (1, 1, self.tebd_dim)
# Gather neighbor type embeddings: (nf, nall, tebd_dim) -> (nf, nloc*nnei, tebd_dim)
nlist_idx_tebd = xp.tile(nlist_2d[:, :, xp.newaxis], (1, 1, self.tebd_dim))
atype_embd_nlist = xp_take_along_axis(
atype_embd_ext, nlist_idx_tebd, axis=1
)
# nfnl x nnei x tebd_dim
atype_embd_nlist = xp_take_along_axis(atype_embd_ext, index, axis=1)
atype_embd_nlist = xp.reshape(
atype_embd_nlist, (nf * nloc, nnei, self.tebd_dim)
)
Expand All @@ -1140,10 +1148,9 @@ def call(
assert self.embeddings_strip is not None
assert type_embedding is not None
ntypes_with_padding = type_embedding.shape[0]
# nf x (nl x nnei)
nlist_index = xp.reshape(nlist_masked, (nf, nloc * nnei))
# nf x (nl x nnei)
nei_type = xp_take_along_axis(atype_ext, nlist_index, axis=1)
# Gather neighbor types: (nf, nall) -> (nf, nloc*nnei)
nei_type = xp_take_along_axis(atype_ext, nlist_2d, axis=1)
nei_type = xp.reshape(nei_type, (-1,)) # (nf * nloc * nnei,)
# (nf x nl x nnei) x ng
nei_type_index = xp.tile(xp.reshape(nei_type, (-1, 1)), (1, ng))
if self.type_one_side:
Expand Down
7 changes: 3 additions & 4 deletions deepmd/dpmodel/descriptor/dpa2.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from deepmd.dpmodel.array_api import (
Array,
xp_take_along_axis,
xp_take_first_n,
)
from deepmd.dpmodel.common import (
cast_precision,
Expand Down Expand Up @@ -878,7 +879,7 @@ def call(
xp.take(type_embedding, xp.reshape(atype_ext, (-1,)), axis=0),
(nframes, nall, self.tebd_dim),
)
g1_inp = g1_ext[:, :nloc, :]
g1_inp = xp_take_first_n(g1_ext, 1, nloc)
g1, _, _, _, _ = self.repinit(
nlist_dict[
get_multiple_nlist_key(self.repinit.get_rcut(), self.repinit.get_nsel())
Expand Down Expand Up @@ -912,9 +913,7 @@ def call(
g1 = g1 + self.tebd_transform(g1_inp)
# mapping g1
assert mapping is not None
mapping_ext = xp.tile(
xp.reshape(mapping, (nframes, nall, 1)), (1, 1, g1.shape[-1])
)
mapping_ext = xp.tile(xp.expand_dims(mapping, axis=-1), (1, 1, g1.shape[-1]))
g1_ext = xp_take_along_axis(g1, mapping_ext, axis=1)
# repformer
g1, g2, h2, rot_mat, sw = self.repformers(
Expand Down
9 changes: 7 additions & 2 deletions deepmd/dpmodel/descriptor/dpa3.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
)
from deepmd.dpmodel.array_api import (
Array,
xp_take_first_n,
)
from deepmd.dpmodel.common import (
cast_precision,
Expand Down Expand Up @@ -653,7 +654,11 @@ def call(
type_embedding = self.type_embedding.call()
if self.use_loc_mapping:
node_ebd_ext = xp.reshape(
xp.take(type_embedding, xp.reshape(atype_ext[:, :nloc], (-1,)), axis=0),
xp.take(
type_embedding,
xp.reshape(xp_take_first_n(atype_ext, 1, nloc), (-1,)),
axis=0,
),
(nframes, nloc, self.tebd_dim),
)
else:
Expand Down Expand Up @@ -682,7 +687,7 @@ def call(
sys_cs_embd = self.cs_activation_fn(self.mix_cs_mlp.call(cs_cat))
node_ebd_ext = node_ebd_ext + xp.expand_dims(sys_cs_embd, axis=1)

node_ebd_inp = node_ebd_ext[:, :nloc, :]
node_ebd_inp = xp_take_first_n(node_ebd_ext, 1, nloc)
# repflows
node_ebd, edge_ebd, h2, rot_mat, sw = self.repflows(
nlist,
Expand Down
7 changes: 4 additions & 3 deletions deepmd/dpmodel/descriptor/repflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from deepmd.dpmodel.array_api import (
Array,
xp_take_along_axis,
xp_take_first_n,
)
from deepmd.dpmodel.common import (
to_numpy_array,
Expand Down Expand Up @@ -562,7 +563,7 @@ def call(

# get node embedding
# nb x nloc x tebd_dim
atype_embd = atype_embd_ext[:, :nloc, :]
atype_embd = xp_take_first_n(atype_embd_ext, 1, nloc)
assert list(atype_embd.shape) == [nframes, nloc, self.n_dim]

node_ebd = self.act(atype_embd)
Expand Down Expand Up @@ -641,7 +642,7 @@ def call(
angle_ebd = self.angle_embd(angle_input)

# nb x nall x n_dim
mapping = xp.tile(xp.reshape(mapping, (nframes, -1, 1)), (1, 1, self.n_dim))
mapping = xp.tile(xp.expand_dims(mapping, axis=-1), (1, 1, self.n_dim))
for idx, ll in enumerate(self.layers):
# node_ebd: nb x nloc x n_dim
# node_ebd_ext: nb x nall x n_dim
Expand Down Expand Up @@ -1421,7 +1422,7 @@ def call(
n_edge = (
int(xp.sum(xp.astype(nlist_mask, xp.int32))) if self.use_dynamic_sel else 0
)
node_ebd = node_ebd_ext[:, :nloc, :]
node_ebd = xp_take_first_n(node_ebd_ext, 1, nloc)
assert (nb, nloc) == node_ebd.shape[:2]
if not self.use_dynamic_sel:
assert (nb, nloc, nnei) == h2.shape[:3]
Expand Down
8 changes: 4 additions & 4 deletions deepmd/dpmodel/descriptor/repformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from deepmd.dpmodel.array_api import (
Array,
xp_take_along_axis,
xp_take_first_n,
)
from deepmd.dpmodel.common import (
to_numpy_array,
Expand Down Expand Up @@ -499,7 +500,7 @@ def call(
sw = xp.reshape(sw, (nf, nloc, nnei))
sw = xp.where(nlist_mask, sw, xp.zeros_like(sw))
# nf x nloc x tebd_dim
atype_embd = atype_embd_ext[:, :nloc, :]
atype_embd = xp_take_first_n(atype_embd_ext, 1, nloc)
assert list(atype_embd.shape) == [nf, nloc, self.g1_dim]

g1 = self.act(atype_embd)
Expand All @@ -516,7 +517,7 @@ def call(
# if a neighbor is real or not is indicated by nlist_mask
nlist = xp.where(nlist == -1, xp.zeros_like(nlist), nlist)
# nf x nall x ng1
mapping = xp.tile(xp.reshape(mapping, (nf, -1, 1)), (1, 1, self.g1_dim))
mapping = xp.tile(xp.expand_dims(mapping, axis=-1), (1, 1, self.g1_dim))
for idx, ll in enumerate(self.layers):
# g1: nf x nloc x ng1
# g1_ext: nf x nall x ng1
Expand Down Expand Up @@ -1765,9 +1766,8 @@ def call(
)

nf, nloc, nnei, _ = g2.shape
nall = g1_ext.shape[1]
# g1, _ = xp.split(g1_ext, [nloc], axis=1)
g1 = g1_ext[:, :nloc, :]
g1 = xp_take_first_n(g1_ext, 1, nloc)
assert (nf, nloc) == g1.shape[:2]
assert (nf, nloc, nnei) == h2.shape[:3]

Expand Down
9 changes: 5 additions & 4 deletions deepmd/dpmodel/model/make_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

from deepmd.dpmodel.array_api import (
Array,
xp_take_along_axis,
xp_take_first_n,
)
from deepmd.dpmodel.atomic_model.base_atomic_model import (
BaseAtomicModel,
Expand Down Expand Up @@ -589,7 +591,6 @@ def _format_nlist(
xp = array_api_compat.array_namespace(extended_coord, nlist)
n_nf, n_nloc, n_nnei = nlist.shape
extended_coord = extended_coord.reshape([n_nf, -1, 3])
nall = extended_coord.shape[1]
rcut = self.get_rcut()

if n_nnei < nnei:
Expand All @@ -612,14 +613,14 @@ def _format_nlist(
# make a copy before revise
m_real_nei = nlist >= 0
ret = xp.where(m_real_nei, nlist, 0)
coord0 = extended_coord[:, :n_nloc, :]
coord0 = xp_take_first_n(extended_coord, 1, n_nloc)
index = xp.tile(ret.reshape(n_nf, n_nloc * n_nnei, 1), (1, 1, 3))
coord1 = xp.take_along_axis(extended_coord, index, axis=1)
coord1 = xp_take_along_axis(extended_coord, index, axis=1)
coord1 = coord1.reshape(n_nf, n_nloc, n_nnei, 3)
rr = xp.linalg.norm(coord0[:, :, None, :] - coord1, axis=-1)
rr = xp.where(m_real_nei, rr, float("inf"))
rr, ret_mapping = xp.sort(rr, axis=-1), xp.argsort(rr, axis=-1)
ret = xp.take_along_axis(ret, ret_mapping, axis=2)
ret = xp_take_along_axis(ret, ret_mapping, axis=2)
ret = xp.where(rr > rcut, -1, ret)
ret = ret[..., :nnei]
# not extra_nlist_sort and n_nnei <= nnei:
Expand Down
21 changes: 13 additions & 8 deletions deepmd/dpmodel/utils/exclude_mask.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from deepmd.dpmodel.array_api import (
Array,
xp_take_along_axis,
xp_take_first_n,
)


Expand Down Expand Up @@ -131,18 +132,22 @@ def build_type_exclude_mask(
],
axis=-1,
)
type_i = xp.reshape(atype_ext[:, :nloc], (nf, nloc)) * (self.ntypes + 1)
# nf x nloc x nnei
index = xp.reshape(
xp.where(nlist == -1, xp.full_like(nlist, nall), nlist), (nf, nloc * nnei)
type_i = xp.reshape(xp_take_first_n(atype_ext, 1, nloc), (nf, nloc)) * (
self.ntypes + 1
)
type_j = xp_take_along_axis(ae, index, axis=1)
# Map -1 entries to nall (the virtual atom index in ae)
nlist_for_type = xp.where(nlist == -1, xp.full_like(nlist, nall), nlist)
# Gather neighbor types using xp_take_along_axis along axis=1.
# This avoids flat (nf*(nall+1),) indexing that creates Ne(nall, nloc)
# constraints in torch.export, breaking NoPbc (nall == nloc).
nlist_for_gather = xp.reshape(nlist_for_type, (nf, nloc * nnei))
type_j = xp_take_along_axis(ae, nlist_for_gather, axis=1)
type_j = xp.reshape(type_j, (nf, nloc, nnei))
type_ij = type_i[:, :, None] + type_j
# nf x (nloc x nnei)
type_ij = xp.reshape(type_ij, (nf, nloc * nnei))
# (nf * nloc * nnei,)
type_ij_flat = xp.reshape(type_ij, (-1,))
mask = xp.reshape(
xp.take(self.type_mask[...], xp.reshape(type_ij, (-1,))),
xp.take(self.type_mask[...], type_ij_flat),
(nf, nloc, nnei),
)
return mask
Expand Down
4 changes: 2 additions & 2 deletions deepmd/dpmodel/utils/nlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from deepmd.dpmodel.array_api import (
Array,
xp_take_along_axis,
xp_take_first_n,
)

from .region import (
Expand Down Expand Up @@ -243,8 +244,7 @@ def build_multiple_neighbor_list(
nlist = xp.concat([nlist, pad], axis=-1)
nsel = nsels[-1]
coord1 = xp.reshape(coord, (nb, -1, 3))
nall = coord1.shape[1]
coord0 = coord1[:, :nloc, :]
coord0 = xp_take_first_n(coord1, 1, nloc)
nlist_mask = nlist == -1
tnlist_0 = xp.where(nlist_mask, xp.zeros_like(nlist), nlist)
index = xp.tile(xp.reshape(tnlist_0, (nb, nloc * nsel, 1)), (1, 1, 3))
Expand Down
17 changes: 17 additions & 0 deletions deepmd/pt/model/descriptor/se_t_tebd.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,23 @@
extend_descrpt_stat,
)

if not hasattr(torch.ops.deepmd, "tabulate_fusion_se_t_tebd"):

def tabulate_fusion_se_t_tebd(
argument0: torch.Tensor,
argument1: torch.Tensor,
argument2: torch.Tensor,
argument3: torch.Tensor,
argument4: int,
) -> list[torch.Tensor]:
raise NotImplementedError(
"tabulate_fusion_se_t_tebd is not available since customized PyTorch OP library is not built when freezing the model. "
"See documentation for model compression for details."
)

# Note: this hack cannot actually save a model that can be run using LAMMPS.
torch.ops.deepmd.tabulate_fusion_se_t_tebd = tabulate_fusion_se_t_tebd


@BaseDescriptor.register("se_e3_tebd")
class DescrptSeTTebd(BaseDescriptor, torch.nn.Module):
Expand Down
Loading
Loading