Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: add se_r descriptor #3338

Merged
merged 23 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
af51721
feat: add se_r descriptor
anyangml Feb 26, 2024
c0af6fa
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 26, 2024
8a8107c
fix: UTs, removed old impl
anyangml Feb 26, 2024
fb6340b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 26, 2024
2eb4041
fix: pre-commit
anyangml Feb 26, 2024
6c5224f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 26, 2024
b771db4
fix: update se_r output
anyangml Feb 26, 2024
8a1a86c
chore: refactor
anyangml Feb 26, 2024
50cdfe0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 26, 2024
84d61da
feat: add numpy impl
anyangml Feb 26, 2024
08a6988
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 26, 2024
1f0fd99
fix: UTs
anyangml Feb 27, 2024
c07e02c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 27, 2024
3485608
Merge branch 'devel' into devel
anyangml Feb 27, 2024
e5b074e
gix: match serialization
anyangml Feb 27, 2024
8265242
Merge branch 'devel' into devel
anyangml Feb 27, 2024
3fe3ed4
chore: refactor device
anyangml Feb 27, 2024
9d23e96
chore: refactor device
anyangml Feb 27, 2024
c073241
fix: UTs
anyangml Feb 27, 2024
ce85c0f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 27, 2024
72d7a37
fix: dtype
anyangml Feb 27, 2024
54375bb
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 27, 2024
184e6a0
Merge branch 'devel' into devel
anyangml Feb 27, 2024
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
4 changes: 4 additions & 0 deletions deepmd/dpmodel/descriptor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
from .se_e2_a import (
DescrptSeA,
)
from .se_r import (
DescrptSeR,
)

__all__ = [
"DescrptSeA",
"DescrptSeR",
"make_base_descriptor",
]
17 changes: 13 additions & 4 deletions deepmd/dpmodel/descriptor/se_e2_a.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

import numpy as np

from deepmd.env import (
GLOBAL_NP_FLOAT_PRECISION,
)
from deepmd.utils.path import (
DPPath,
)
Expand Down Expand Up @@ -183,8 +186,12 @@ def __init__(
)
self.env_mat = EnvMat(self.rcut, self.rcut_smth)
self.nnei = np.sum(self.sel)
self.davg = np.zeros([self.ntypes, self.nnei, 4])
self.dstd = np.ones([self.ntypes, self.nnei, 4])
self.davg = np.zeros(
[self.ntypes, self.nnei, 4], dtype=PRECISION_DICT[self.precision]
)
self.dstd = np.ones(
[self.ntypes, self.nnei, 4], dtype=PRECISION_DICT[self.precision]
)
self.orig_sel = self.sel

def __setitem__(self, key, value):
Expand Down Expand Up @@ -292,7 +299,7 @@ def call(
sec = np.append([0], np.cumsum(self.sel))

ng = self.neuron[-1]
gr = np.zeros([nf * nloc, ng, 4])
gr = np.zeros([nf * nloc, ng, 4], dtype=PRECISION_DICT[self.precision])
exclude_mask = self.emask.build_type_exclude_mask(nlist, atype_ext)
# merge nf and nloc axis, so for type_one_side == False,
# we don't require atype is the same in all frames
Expand Down Expand Up @@ -322,7 +329,9 @@ def call(
# nf x nloc x ng x ng1
grrg = np.einsum("flid,fljd->flij", gr, gr1)
# nf x nloc x (ng x ng1)
grrg = grrg.reshape(nf, nloc, ng * self.axis_neuron)
grrg = grrg.reshape(nf, nloc, ng * self.axis_neuron).astype(
GLOBAL_NP_FLOAT_PRECISION
)
return grrg, gr[..., 1:], None, None, ww

def serialize(self) -> dict:
Expand Down
321 changes: 321 additions & 0 deletions deepmd/dpmodel/descriptor/se_r.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,321 @@
# SPDX-License-Identifier: LGPL-3.0-or-later
import numpy as np

from deepmd.utils.path import (
DPPath,
)

try:
from deepmd._version import version as __version__
except ImportError:
__version__ = "unknown"

Check warning on line 11 in deepmd/dpmodel/descriptor/se_r.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/descriptor/se_r.py#L10-L11

Added lines #L10 - L11 were not covered by tests

import copy
from typing import (
Any,
List,
Optional,
)

from deepmd.dpmodel import (
DEFAULT_PRECISION,
PRECISION_DICT,
NativeOP,
)
from deepmd.dpmodel.utils import (
EmbeddingNet,
EnvMat,
NetworkCollection,
PairExcludeMask,
)
from deepmd.env import (
GLOBAL_NP_FLOAT_PRECISION,
)

from .base_descriptor import (
BaseDescriptor,
)


@BaseDescriptor.register("se_e2_r")
@BaseDescriptor.register("se_r")
class DescrptSeR(NativeOP, BaseDescriptor):
r"""DeepPot-SE_R constructed from only the radial imformation of atomic configurations.


Parameters
----------
rcut
The cut-off radius :math:`r_c`
rcut_smth
From where the environment matrix should be smoothed :math:`r_s`
sel : list[str]
sel[i] specifies the maxmum number of type i atoms in the cut-off radius
neuron : list[int]
Number of neurons in each hidden layers of the embedding net :math:`\mathcal{N}`
resnet_dt
Time-step `dt` in the resnet construction:
y = x + dt * \phi (Wx + b)
trainable
If the weights of embedding net are trainable.
type_one_side
Try to build N_types embedding nets. Otherwise, building N_types^2 embedding nets
exclude_types : List[List[int]]
The excluded pairs of types which have no interaction with each other.
For example, `[[0, 1]]` means no interaction between type 0 and type 1.
set_davg_zero
Set the shift of embedding net input to zero.
activation_function
The activation function in the embedding net. Supported options are |ACTIVATION_FN|
precision
The precision of the embedding net parameters. Supported options are |PRECISION|
multi_task
If the model has multi fitting nets to train.
spin
The deepspin object.

Limitations
-----------
The currently implementation does not support the following features

1. type_one_side == False
2. exclude_types != []
3. spin is not None

References
----------
.. [1] Linfeng Zhang, Jiequn Han, Han Wang, Wissam A. Saidi, Roberto Car, and E. Weinan. 2018.
End-to-end symmetry preserving inter-atomic potential energy model for finite and extended
systems. In Proceedings of the 32nd International Conference on Neural Information Processing
Systems (NIPS'18). Curran Associates Inc., Red Hook, NY, USA, 4441-4451.
"""

def __init__(
self,
rcut: float,
rcut_smth: float,
sel: List[str],
neuron: List[int] = [24, 48, 96],
resnet_dt: bool = False,
trainable: bool = True,
type_one_side: bool = True,
exclude_types: List[List[int]] = [],
set_davg_zero: bool = False,
activation_function: str = "tanh",
precision: str = DEFAULT_PRECISION,
spin: Optional[Any] = None,
# consistent with argcheck, not used though
seed: Optional[int] = None,
) -> None:
## seed, uniform_seed, multi_task, not included.
if not type_one_side:
raise NotImplementedError("type_one_side == False not implemented")

Check warning on line 112 in deepmd/dpmodel/descriptor/se_r.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/descriptor/se_r.py#L112

Added line #L112 was not covered by tests
if spin is not None:
raise NotImplementedError("spin is not implemented")

Check warning on line 114 in deepmd/dpmodel/descriptor/se_r.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/descriptor/se_r.py#L114

Added line #L114 was not covered by tests

self.rcut = rcut
self.rcut_smth = rcut_smth
self.sel = sel
self.ntypes = len(self.sel)
self.neuron = neuron
self.resnet_dt = resnet_dt
self.trainable = trainable
self.type_one_side = type_one_side
self.exclude_types = exclude_types
self.set_davg_zero = set_davg_zero
self.activation_function = activation_function
self.precision = precision
self.spin = spin
self.emask = PairExcludeMask(self.ntypes, self.exclude_types)

in_dim = 1 # not considiering type embedding
self.embeddings = NetworkCollection(
ntypes=self.ntypes,
ndim=(1 if self.type_one_side else 2),
network_type="embedding_network",
)
if not self.type_one_side:
raise NotImplementedError("type_one_side == False not implemented")

Check warning on line 138 in deepmd/dpmodel/descriptor/se_r.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/descriptor/se_r.py#L138

Added line #L138 was not covered by tests
for ii in range(self.ntypes):
self.embeddings[(ii,)] = EmbeddingNet(
in_dim,
self.neuron,
self.activation_function,
self.resnet_dt,
self.precision,
)
self.env_mat = EnvMat(self.rcut, self.rcut_smth)
self.nnei = np.sum(self.sel)
self.davg = np.zeros(
[self.ntypes, self.nnei, 1], dtype=PRECISION_DICT[self.precision]
)
self.dstd = np.ones(
[self.ntypes, self.nnei, 1], dtype=PRECISION_DICT[self.precision]
)
self.orig_sel = self.sel

def __setitem__(self, key, value):
if key in ("avg", "data_avg", "davg"):
self.davg = value
elif key in ("std", "data_std", "dstd"):
self.dstd = value
else:
raise KeyError(key)

Check warning on line 163 in deepmd/dpmodel/descriptor/se_r.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/descriptor/se_r.py#L163

Added line #L163 was not covered by tests

def __getitem__(self, key):
if key in ("avg", "data_avg", "davg"):
return self.davg
elif key in ("std", "data_std", "dstd"):
return self.dstd

Check warning on line 169 in deepmd/dpmodel/descriptor/se_r.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/descriptor/se_r.py#L166-L169

Added lines #L166 - L169 were not covered by tests
else:
raise KeyError(key)

Check warning on line 171 in deepmd/dpmodel/descriptor/se_r.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/descriptor/se_r.py#L171

Added line #L171 was not covered by tests

@property
def dim_out(self):
"""Returns the output dimension of this descriptor."""
return self.get_dim_out()

Check warning on line 176 in deepmd/dpmodel/descriptor/se_r.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/descriptor/se_r.py#L176

Added line #L176 was not covered by tests

def get_dim_out(self):
"""Returns the output dimension of this descriptor."""
return self.neuron[-1]

Check warning on line 180 in deepmd/dpmodel/descriptor/se_r.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/descriptor/se_r.py#L180

Added line #L180 was not covered by tests

def get_dim_emb(self):
"""Returns the embedding (g2) dimension of this descriptor."""
raise NotImplementedError

Check warning on line 184 in deepmd/dpmodel/descriptor/se_r.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/descriptor/se_r.py#L184

Added line #L184 was not covered by tests

def get_rcut(self):
"""Returns cutoff radius."""
return self.rcut

def get_sel(self):
"""Returns cutoff radius."""
return self.sel

def mixed_types(self):
"""Returns if the descriptor requires a neighbor list that distinguish different
atomic types or not.
"""
return False

Check warning on line 198 in deepmd/dpmodel/descriptor/se_r.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/descriptor/se_r.py#L198

Added line #L198 was not covered by tests

def get_ntypes(self) -> int:
"""Returns the number of element types."""
return self.ntypes

Check warning on line 202 in deepmd/dpmodel/descriptor/se_r.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/descriptor/se_r.py#L202

Added line #L202 was not covered by tests

def compute_input_stats(self, merged: List[dict], path: Optional[DPPath] = None):
"""Update mean and stddev for descriptor elements."""
raise NotImplementedError

Check warning on line 206 in deepmd/dpmodel/descriptor/se_r.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/descriptor/se_r.py#L206

Added line #L206 was not covered by tests

def cal_g(
self,
ss,
ll,
):
nf, nloc, nnei = ss.shape[0:3]
ss = ss.reshape(nf, nloc, nnei, 1)
# nf x nloc x nnei x ng
gg = self.embeddings[(ll,)].call(ss)
return gg

def call(
self,
coord_ext,
atype_ext,
nlist,
mapping: Optional[np.ndarray] = None,
):
"""Compute the descriptor.

Parameters
----------
coord_ext
The extended coordinates of atoms. shape: nf x (nallx3)
atype_ext
The extended aotm types. shape: nf x nall
nlist
The neighbor list. shape: nf x nloc x nnei
mapping
The index mapping from extended to lcoal region. not used by this descriptor.

Returns
-------
descriptor
The descriptor. shape: nf x nloc x (ng x axis_neuron)
gr
The rotationally equivariant and permutationally invariant single particle
representation. shape: nf x nloc x ng x 3
g2
The rotationally invariant pair-partical representation.
this descriptor returns None
h2
The rotationally equivariant pair-partical representation.
this descriptor returns None
sw
The smooth switch function.
"""
del mapping
# nf x nloc x nnei x 1
rr, ww = self.env_mat.call(
coord_ext, atype_ext, nlist, self.davg, self.dstd, True
)
nf, nloc, nnei, _ = rr.shape
sec = np.append([0], np.cumsum(self.sel))

ng = self.neuron[-1]
xyz_scatter = np.zeros([nf, nloc, ng], dtype=PRECISION_DICT[self.precision])
exclude_mask = self.emask.build_type_exclude_mask(nlist, atype_ext)
for tt in range(self.ntypes):
mm = exclude_mask[:, :, sec[tt] : sec[tt + 1]]
tr = rr[:, :, sec[tt] : sec[tt + 1], :]
tr = tr * mm[:, :, :, None]
gg = self.cal_g(tr, tt)
gg = np.mean(gg, axis=2)
# nf x nloc x ng x 1
xyz_scatter += gg

res_rescale = 1.0 / 10.0
res = xyz_scatter * res_rescale
res = res.reshape(nf, nloc, -1).astype(GLOBAL_NP_FLOAT_PRECISION)
return res, None, None, None, ww

def serialize(self) -> dict:
"""Serialize the descriptor to dict."""
return {
"@class": "Descriptor",
"type": "se_r",
"rcut": self.rcut,
"rcut_smth": self.rcut_smth,
"sel": self.sel,
"neuron": self.neuron,
"resnet_dt": self.resnet_dt,
"trainable": self.trainable,
"type_one_side": self.type_one_side,
"exclude_types": self.exclude_types,
"set_davg_zero": self.set_davg_zero,
"activation_function": self.activation_function,
# make deterministic
"precision": np.dtype(PRECISION_DICT[self.precision]).name,
"spin": self.spin,
"env_mat": self.env_mat.serialize(),
"embeddings": self.embeddings.serialize(),
"@variables": {
"davg": self.davg,
"dstd": self.dstd,
},
}

@classmethod
def deserialize(cls, data: dict) -> "DescrptSeR":
"""Deserialize from dict."""
data = copy.deepcopy(data)
data.pop("@class", None)
data.pop("type", None)
variables = data.pop("@variables")
embeddings = data.pop("embeddings")
env_mat = data.pop("env_mat")
obj = cls(**data)

obj["davg"] = variables["davg"]
obj["dstd"] = variables["dstd"]
obj.embeddings = NetworkCollection.deserialize(embeddings)
obj.env_mat = EnvMat.deserialize(env_mat)
return obj
Loading