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

consistent energy fitting #3286

Merged
merged 18 commits into from
Feb 19, 2024
2 changes: 1 addition & 1 deletion deepmd/dpmodel/fitting/dipole_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def __init__(
raise NotImplementedError("use_aparam_as_mask is not implemented")
if layer_name is not None:
raise NotImplementedError("layer_name is not implemented")
if atom_ener is not None:
if atom_ener is not None and atom_ener != []:
raise NotImplementedError("atom_ener is not implemented")

self.dim_rot_mat = dim_rot_mat
Expand Down
72 changes: 72 additions & 0 deletions deepmd/dpmodel/fitting/ener_fitting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# SPDX-License-Identifier: LGPL-3.0-or-later
import copy
from typing import (
TYPE_CHECKING,
Any,
List,
Optional,
)

from deepmd.dpmodel.common import (
DEFAULT_PRECISION,
)
from deepmd.dpmodel.fitting.invar_fitting import (
InvarFitting,
)

if TYPE_CHECKING:
from deepmd.dpmodel.fitting.general_fitting import (

Check warning on line 18 in deepmd/dpmodel/fitting/ener_fitting.py

View check run for this annotation

Codecov / codecov/patch

deepmd/dpmodel/fitting/ener_fitting.py#L18

Added line #L18 was not covered by tests
GeneralFitting,
)


class EnergyFittingNet(InvarFitting):
def __init__(
self,
ntypes: int,
dim_descrpt: int,
neuron: List[int] = [120, 120, 120],
resnet_dt: bool = True,
numb_fparam: int = 0,
numb_aparam: int = 0,
rcond: Optional[float] = None,
tot_ener_zero: bool = False,
trainable: Optional[List[bool]] = None,
atom_ener: Optional[List[float]] = None,
activation_function: str = "tanh",
precision: str = DEFAULT_PRECISION,
layer_name: Optional[List[Optional[str]]] = None,
use_aparam_as_mask: bool = False,
spin: Any = None,
distinguish_types: bool = False,
exclude_types: List[int] = [],
# not used
seed: Optional[int] = None,
):
super().__init__(
var_name="energy",
ntypes=ntypes,
dim_descrpt=dim_descrpt,
dim_out=1,
neuron=neuron,
resnet_dt=resnet_dt,
numb_fparam=numb_fparam,
numb_aparam=numb_aparam,
rcond=rcond,
tot_ener_zero=tot_ener_zero,
trainable=trainable,
atom_ener=atom_ener,
activation_function=activation_function,
precision=precision,
layer_name=layer_name,
use_aparam_as_mask=use_aparam_as_mask,
spin=spin,
distinguish_types=distinguish_types,
)

@classmethod
def deserialize(cls, data: dict) -> "GeneralFitting":
data = copy.deepcopy(data)
data.pop("var_name")
data.pop("dim_out")
return super().deserialize(data)
4 changes: 4 additions & 0 deletions deepmd/dpmodel/fitting/general_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ def __init__(
self.rcond = rcond
self.tot_ener_zero = tot_ener_zero
self.trainable = trainable
if self.trainable is None:
self.trainable = [True for ii in range(len(self.neuron) + 1)]
if isinstance(self.trainable, bool):
self.trainable = [self.trainable] * (len(self.neuron) + 1)
self.atom_ener = atom_ener
self.activation_function = activation_function
self.precision = precision
Expand Down
2 changes: 1 addition & 1 deletion deepmd/dpmodel/fitting/invar_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def __init__(
raise NotImplementedError("use_aparam_as_mask is not implemented")
if layer_name is not None:
raise NotImplementedError("layer_name is not implemented")
if atom_ener is not None:
if atom_ener is not None and atom_ener != []:
raise NotImplementedError("atom_ener is not implemented")

self.dim_out = dim_out
Expand Down
2 changes: 2 additions & 0 deletions deepmd/pt/model/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def get_zbl_model(model_params):
fitting_net["ntypes"] = descriptor.get_ntypes()
fitting_net["distinguish_types"] = descriptor.distinguish_types()
fitting_net["embedding_width"] = descriptor.get_dim_out()
wanghan-iapcm marked this conversation as resolved.
Show resolved Hide resolved
fitting_net["dim_descrpt"] = descriptor.get_dim_out()
grad_force = "direct" not in fitting_net["type"]
if not grad_force:
fitting_net["out_dim"] = descriptor.get_dim_emb()
Expand Down Expand Up @@ -89,6 +90,7 @@ def get_model(model_params):
fitting_net["ntypes"] = descriptor.get_ntypes()
fitting_net["distinguish_types"] = descriptor.distinguish_types()
fitting_net["embedding_width"] = descriptor.get_dim_out()
fitting_net["dim_descrpt"] = descriptor.get_dim_out()
grad_force = "direct" not in fitting_net["type"]
if not grad_force:
fitting_net["out_dim"] = descriptor.get_dim_emb()
Expand Down
12 changes: 10 additions & 2 deletions deepmd/pt/model/task/ener.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: LGPL-3.0-or-later
import copy
import logging
from typing import (
List,
Expand Down Expand Up @@ -194,7 +195,7 @@ class EnergyFittingNet(InvarFitting):
def __init__(
self,
ntypes: int,
embedding_width: int,
dim_descrpt: int,
neuron: List[int] = [128, 128, 128],
bias_atom_e: Optional[torch.Tensor] = None,
resnet_dt: bool = True,
Expand All @@ -208,7 +209,7 @@ def __init__(
super().__init__(
"energy",
ntypes,
embedding_width,
dim_descrpt,
1,
neuron=neuron,
bias_atom_e=bias_atom_e,
Expand All @@ -221,6 +222,13 @@ def __init__(
**kwargs,
)

@classmethod
def deserialize(cls, data: dict) -> "GeneralFitting":
data = copy.deepcopy(data)
data.pop("var_name")
data.pop("dim_out")
return super().deserialize(data)


@Fitting.register("direct_force")
@Fitting.register("direct_force_ener")
Expand Down
4 changes: 2 additions & 2 deletions deepmd/pt/model/task/fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,8 @@ def serialize(self) -> dict:
# "spin": self.spin ,
## NOTICE: not supported by far
"tot_ener_zero": False,
"trainable": True,
"atom_ener": None,
"trainable": [True] * (len(self.neuron) + 1),
"atom_ener": [],
"layer_name": None,
"use_aparam_as_mask": False,
"spin": None,
Expand Down
27 changes: 16 additions & 11 deletions deepmd/tf/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,25 +140,30 @@ def dlopen_library(module: str, filename: str):
r"filter_type_(all)/(idt)_(\d+)|"
)[:-1]

# subpatterns:
# \1: layer index or "final"
# \2: type of centeral atom, optional
# the last: weight name
FITTING_NET_PATTERN = str(
r"layer_\d+/matrix|"
r"layer_\d+_type_\d+/matrix|"
r"layer_\d+/bias|"
r"layer_\d+_type_\d+/bias|"
r"layer_\d+/idt|"
r"layer_\d+_type_\d+/idt|"
r"final_layer/matrix|"
r"final_layer_type_\d+/matrix|"
r"final_layer/bias|"
r"final_layer_type_\d+/bias|"
r"layer_(\d+)/(matrix)|"
r"layer_(\d+)_type_(\d+)/(matrix)|"
r"layer_(\d+)/(bias)|"
r"layer_(\d+)_type_(\d+)/(bias)|"
r"layer_(\d+)/(idt)|"
r"layer_(\d+)_type_(\d+)/(idt)|"
r"(final)_layer/(matrix)|"
r"(final)_layer_type_(\d+)/(matrix)|"
r"(final)_layer/(bias)|"
r"(final)_layer_type_(\d+)/(bias)|"
# TODO: not sure how to parse for shared layers...
# layer_name
r"share_.+_type_\d/matrix|"
r"share_.+_type_\d/bias|"
r"share_.+_type_\d/idt|"
r"share_.+/matrix|"
r"share_.+/bias|"
r"share_.+/idt|"
)
)[:-1]

TYPE_EMBEDDING_PATTERN = str(
r"type_embed_net+/matrix_\d+|"
Expand Down
103 changes: 94 additions & 9 deletions deepmd/tf/fit/ener.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: LGPL-3.0-or-later
import logging
from typing import (
TYPE_CHECKING,
List,
Optional,
)
Expand Down Expand Up @@ -53,6 +54,9 @@
Spin,
)

if TYPE_CHECKING:
pass

Check warning on line 58 in deepmd/tf/fit/ener.py

View check run for this annotation

Codecov / codecov/patch

deepmd/tf/fit/ener.py#L58

Added line #L58 was not covered by tests

log = logging.getLogger(__name__)


Expand Down Expand Up @@ -130,7 +134,8 @@

def __init__(
self,
descrpt: tf.Tensor,
ntypes: int,
dim_descrpt: int,
neuron: List[int] = [120, 120, 120],
resnet_dt: bool = True,
numb_fparam: int = 0,
Expand All @@ -150,8 +155,8 @@
) -> None:
"""Constructor."""
# model param
self.ntypes = descrpt.get_ntypes()
self.dim_descrpt = descrpt.get_dim_out()
self.ntypes = ntypes
self.dim_descrpt = dim_descrpt
self.use_aparam_as_mask = use_aparam_as_mask
# args = ()\
# .add('numb_fparam', int, default = 0)\
Expand All @@ -176,6 +181,7 @@
self.ntypes_spin = self.spin.get_ntypes_spin() if self.spin is not None else 0
self.seed_shift = one_layer_rand_seed_shift()
self.tot_ener_zero = tot_ener_zero
self.activation_function_name = activation_function
self.fitting_activation_fn = get_activation_func(activation_function)
self.fitting_precision = get_precision(precision)
self.trainable = trainable
Expand All @@ -202,16 +208,16 @@
add_data_requirement(
"fparam", self.numb_fparam, atomic=False, must=True, high_prec=False
)
self.fparam_avg = None
self.fparam_std = None
self.fparam_inv_std = None
self.fparam_avg = None
self.fparam_std = None
self.fparam_inv_std = None
if self.numb_aparam > 0:
add_data_requirement(
"aparam", self.numb_aparam, atomic=True, must=True, high_prec=False
)
self.aparam_avg = None
self.aparam_std = None
self.aparam_inv_std = None
self.aparam_avg = None
self.aparam_std = None
self.aparam_inv_std = None

self.fitting_net_variables = None
self.mixed_prec = None
Expand Down Expand Up @@ -921,3 +927,82 @@
return EnerSpinLoss(**loss, use_spin=self.spin.use_spin)
else:
raise RuntimeError("unknown loss type")

@classmethod
def deserialize(cls, data: dict, suffix: str):
"""Deserialize the model.

Parameters
----------
data : dict
The serialized data

Returns
-------
Model
The deserialized model
"""
fitting = cls(**data)
fitting.fitting_net_variables = cls.deserialize_network(
data["nets"],
suffix=suffix,
)
fitting.bias_atom_e = data["@variables"]["bias_atom_e"]
if fitting.numb_fparam > 0:
fitting.fparam_avg = data["@variables"]["fparam_avg"]
fitting.fparam_inv_std = data["@variables"]["fparam_inv_std"]
if fitting.numb_aparam > 0:
fitting.aparam_avg = data["@variables"]["aparam_avg"]
fitting.aparam_inv_std = data["@variables"]["aparam_inv_std"]

Check warning on line 956 in deepmd/tf/fit/ener.py

View check run for this annotation

Codecov / codecov/patch

deepmd/tf/fit/ener.py#L955-L956

Added lines #L955 - L956 were not covered by tests
return fitting

def serialize(self, suffix: str) -> dict:
"""Serialize the model.

Returns
-------
dict
The serialized data
"""
data = {
"var_name": "energy",
"ntypes": self.ntypes,
"dim_descrpt": self.dim_descrpt,
# very bad design: type embedding is not passed to the class
# TODO: refactor the class
"distinguish_types": True,
"dim_out": 1,
"neuron": self.n_neuron,
"resnet_dt": self.resnet_dt,
"numb_fparam": self.numb_fparam,
"numb_aparam": self.numb_aparam,
"rcond": self.rcond,
"tot_ener_zero": self.tot_ener_zero,
"trainable": self.trainable,
"atom_ener": self.atom_ener,
"activation_function": self.activation_function_name,
"precision": self.fitting_precision.name,
"layer_name": self.layer_name,
"use_aparam_as_mask": self.use_aparam_as_mask,
"spin": self.spin,
"exclude_types": [],
"nets": self.serialize_network(
ntypes=self.ntypes,
# TODO: consider type embeddings
ndim=1,
in_dim=self.dim_descrpt + self.numb_fparam + self.numb_aparam,
neuron=self.n_neuron,
activation_function=self.activation_function_name,
resnet_dt=self.resnet_dt,
variables=self.fitting_net_variables,
suffix=suffix,
),
"@variables": {
"bias_atom_e": self.bias_atom_e,
"fparam_avg": self.fparam_avg,
"fparam_inv_std": self.fparam_inv_std,
"aparam_avg": self.aparam_avg,
"aparam_inv_std": self.aparam_inv_std,
},
}
return data
Loading