Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
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/atomic_model/base_atomic_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ def get_type_map(self) -> list[str]:
"""Get the type map."""
return self.type_map

def has_default_fparam(self) -> bool:
"""Check if the model has default frame parameters."""
return False

def reinit_atom_exclude(
self,
exclude_types: list[int] = [],
Expand Down
4 changes: 4 additions & 0 deletions deepmd/dpmodel/atomic_model/dp_atomic_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ def get_dim_aparam(self) -> int:
"""Get the number (dimension) of atomic parameters of this atomic model."""
return self.fitting.get_dim_aparam()

def has_default_fparam(self) -> bool:
"""Check if the model has default frame parameters."""
return self.fitting.has_default_fparam()

def get_sel_type(self) -> list[int]:
"""Get the selected atom types of this model.
Expand Down
6 changes: 6 additions & 0 deletions deepmd/dpmodel/descriptor/dpa3.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ def __init__(
use_exp_switch: bool = False,
use_dynamic_sel: bool = False,
sel_reduce_factor: float = 10.0,
update_use_layernorm: bool = False,
use_gated_mlp: bool = False,
gated_mlp_norm: str = "none",
Comment on lines +180 to +182
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if DescrptBlockRepflows accepts these parameters
ast-grep --pattern $'class DescrptBlockRepflows {
  $$$
  def __init__($$$) {
    $$$
  }
  $$$
}'

# Alternative: search for the constructor signature
rg -n "def __init__" deepmd/dpmodel/descriptor/repflows.py -A 30 | head -50

Repository: deepmodeling/deepmd-kit

Length of output: 1725


🏁 Script executed:

# Get the full RepFlowArgs class definition including __init__, serialize, and DescrptBlockRepflows call
sed -n '170,370p' deepmd/dpmodel/descriptor/dpa3.py

Repository: deepmodeling/deepmd-kit

Length of output: 8519


🏁 Script executed:

# Get the full DescrptBlockRepflows.__init__ signature
rg -n "class DescrptBlockRepflows" deepmd/dpmodel/descriptor/repflows.py -A 200 | head -100

Repository: deepmodeling/deepmd-kit

Length of output: 6378


🏁 Script executed:

# Get the complete __init__ signature of DescrptBlockRepflows
sed -n '172,250p' deepmd/dpmodel/descriptor/repflows.py

Repository: deepmodeling/deepmd-kit

Length of output: 3029


Missing serialization and forwarding of three new RepFlowArgs parameters.

The three new parameters (update_use_layernorm, use_gated_mlp, gated_mlp_norm) are stored as instance attributes but:

  1. Not serialized: RepFlowArgs.serialize() omits these parameters. Models will lose them when saved/loaded.

  2. Not forwarded: These parameters are not passed to DescrptBlockRepflows, and DescrptBlockRepflows doesn't accept them in its constructor. This indicates incomplete implementation—either they should be added to DescrptBlockRepflows or they should not be in RepFlowArgs yet.

🔧 Proposed fix for serialization

Add the missing parameters to serialize():

             "use_dynamic_sel": self.use_dynamic_sel,
             "sel_reduce_factor": self.sel_reduce_factor,
+            "update_use_layernorm": self.update_use_layernorm,
+            "use_gated_mlp": self.use_gated_mlp,
+            "gated_mlp_norm": self.gated_mlp_norm,
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deepmd/dpmodel/descriptor/dpa3.py` around lines 180 - 182, RepFlowArgs now
has three new fields (update_use_layernorm, use_gated_mlp, gated_mlp_norm) but
they are not included in RepFlowArgs.serialize() nor forwarded to
DescrptBlockRepflows; update RepFlowArgs.serialize() to include these three keys
so they persist, and then modify the call site where a RepFlowArgs instance is
passed to construct DescrptBlockRepflows to forward these values (or update
DescrptBlockRepflows.__init__ to accept and store them), ensuring the
constructor/attribute names match (update_use_layernorm, use_gated_mlp,
gated_mlp_norm) so saved models round-trip correctly.

) -> None:
self.n_dim = n_dim
self.e_dim = e_dim
Expand Down Expand Up @@ -207,6 +210,9 @@ def __init__(
self.use_exp_switch = use_exp_switch
self.use_dynamic_sel = use_dynamic_sel
self.sel_reduce_factor = sel_reduce_factor
self.update_use_layernorm = update_use_layernorm
self.use_gated_mlp = use_gated_mlp
self.gated_mlp_norm = gated_mlp_norm

def __getitem__(self, key):
if hasattr(self, key):
Expand Down
7 changes: 7 additions & 0 deletions deepmd/dpmodel/descriptor/make_base_descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,13 @@ def compute_input_stats(
"""Update mean and stddev for descriptor elements."""
raise NotImplementedError

def get_norm_fact(self) -> list[float]:
"""Returns the norm factor."""
raise NotImplementedError

def get_additional_output_for_fitting(self):
raise NotImplementedError

def enable_compression(
self,
min_nbor_dist: float,
Expand Down
7 changes: 6 additions & 1 deletion deepmd/dpmodel/fitting/dipole_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class DipoleFitting(GeneralFitting):
Only reducible variable are differentiable.
type_map: list[str], Optional
A list of strings. Give the name to each type of atoms.
default_fparam: list[float], optional
The default frame parameter. If set, when `fparam.npy` files are not included in the data system,
this value will be used as the default value for the frame parameter in the fitting net.
"""

def __init__(
Expand All @@ -110,6 +113,7 @@ def __init__(
c_differentiable: bool = True,
type_map: Optional[list[str]] = None,
seed: Optional[Union[int, list[int]]] = None,
default_fparam: Optional[list[float]] = None,
) -> None:
if tot_ener_zero:
raise NotImplementedError("tot_ener_zero is not implemented")
Expand Down Expand Up @@ -144,6 +148,7 @@ def __init__(
exclude_types=exclude_types,
type_map=type_map,
seed=seed,
default_fparam=default_fparam,
)

def _net_out_dim(self):
Expand All @@ -161,7 +166,7 @@ def serialize(self) -> dict:
@classmethod
def deserialize(cls, data: dict) -> "GeneralFitting":
data = data.copy()
check_version_compatibility(data.pop("@version", 1), 3, 1)
check_version_compatibility(data.pop("@version", 1), 4, 1)
var_name = data.pop("var_name", None)
assert var_name == "dipole"
return super().deserialize(data)
Expand Down
4 changes: 3 additions & 1 deletion deepmd/dpmodel/fitting/dos_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def __init__(
exclude_types: list[int] = [],
type_map: Optional[list[str]] = None,
seed: Optional[Union[int, list[int]]] = None,
default_fparam: Optional[list] = None,
) -> None:
if bias_dos is not None:
self.bias_dos = bias_dos
Expand All @@ -70,12 +71,13 @@ def __init__(
exclude_types=exclude_types,
type_map=type_map,
seed=seed,
default_fparam=default_fparam,
)

@classmethod
def deserialize(cls, data: dict) -> "GeneralFitting":
data = data.copy()
check_version_compatibility(data.pop("@version", 1), 3, 1)
check_version_compatibility(data.pop("@version", 1), 4, 1)
data["numb_dos"] = data.pop("dim_out")
data.pop("tot_ener_zero", None)
data.pop("var_name", None)
Expand Down
4 changes: 3 additions & 1 deletion deepmd/dpmodel/fitting/ener_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def __init__(
exclude_types: list[int] = [],
type_map: Optional[list[str]] = None,
seed: Optional[Union[int, list[int]]] = None,
default_fparam: Optional[list] = None,
) -> None:
super().__init__(
var_name="energy",
Expand All @@ -70,12 +71,13 @@ def __init__(
exclude_types=exclude_types,
type_map=type_map,
seed=seed,
default_fparam=default_fparam,
)

@classmethod
def deserialize(cls, data: dict) -> "GeneralFitting":
data = data.copy()
check_version_compatibility(data.pop("@version", 1), 3, 1)
check_version_compatibility(data.pop("@version", 1), 4, 1)
data.pop("var_name")
data.pop("dim_out")
return super().deserialize(data)
Expand Down
33 changes: 32 additions & 1 deletion deepmd/dpmodel/fitting/general_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ class GeneralFitting(NativeOP, BaseFitting):
A list of strings. Give the name to each type of atoms.
seed: Optional[Union[int, list[int]]]
Random seed for initializing the network parameters.
default_fparam: list[float], optional
The default frame parameter. If set, when `fparam.npy` files are not included in the data system,
this value will be used as the default value for the frame parameter in the fitting net.
"""

def __init__(
Expand All @@ -120,6 +123,7 @@ def __init__(
remove_vaccum_contribution: Optional[list[bool]] = None,
type_map: Optional[list[str]] = None,
seed: Optional[Union[int, list[int]]] = None,
default_fparam: Optional[list[float]] = None,
) -> None:
self.var_name = var_name
self.ntypes = ntypes
Expand All @@ -129,6 +133,7 @@ def __init__(
self.numb_fparam = numb_fparam
self.numb_aparam = numb_aparam
self.dim_case_embd = dim_case_embd
self.default_fparam = default_fparam
self.rcond = rcond
self.tot_ener_zero = tot_ener_zero
self.trainable = trainable
Expand Down Expand Up @@ -177,6 +182,15 @@ def __init__(
self.case_embd = np.zeros(self.dim_case_embd, dtype=self.prec)
else:
self.case_embd = None

if self.default_fparam is not None:
if self.numb_fparam > 0:
assert len(self.default_fparam) == self.numb_fparam, (
"default_fparam length mismatch!"
)
self.default_fparam_tensor = np.array(self.default_fparam, dtype=self.prec)
else:
self.default_fparam_tensor = None
# init networks
in_dim = (
self.dim_descrpt
Expand Down Expand Up @@ -216,6 +230,10 @@ def get_dim_aparam(self) -> int:
"""Get the number (dimension) of atomic parameters of this atomic model."""
return self.numb_aparam

def has_default_fparam(self) -> bool:
"""Check if the fitting has default frame parameters."""
return self.default_fparam is not None

def get_sel_type(self) -> list[int]:
"""Get the selected atom types of this model.

Expand Down Expand Up @@ -273,6 +291,8 @@ def __setitem__(self, key, value) -> None:
self.case_embd = value
elif key in ["scale"]:
self.scale = value
elif key in ["default_fparam_tensor"]:
self.default_fparam_tensor = value
else:
raise KeyError(key)

Expand All @@ -291,6 +311,8 @@ def __getitem__(self, key):
return self.case_embd
elif key in ["scale"]:
return self.scale
elif key in ["default_fparam_tensor"]:
return self.default_fparam_tensor
else:
raise KeyError(key)

Expand All @@ -305,7 +327,7 @@ def serialize(self) -> dict:
"""Serialize the fitting to dict."""
return {
"@class": "Fitting",
"@version": 3,
"@version": 4,
"var_name": self.var_name,
"ntypes": self.ntypes,
"dim_descrpt": self.dim_descrpt,
Expand All @@ -314,6 +336,7 @@ def serialize(self) -> dict:
"numb_fparam": self.numb_fparam,
"numb_aparam": self.numb_aparam,
"dim_case_embd": self.dim_case_embd,
"default_fparam": self.default_fparam,
"rcond": self.rcond,
"activation_function": self.activation_function,
"precision": self.precision,
Expand Down Expand Up @@ -402,6 +425,14 @@ def _call_common(
xx_zeros = xp.zeros_like(xx)
else:
xx_zeros = None

if self.numb_fparam > 0 and fparam is None:
# use default fparam
assert self.default_fparam_tensor is not None
fparam = xp.tile(
xp.reshape(self.default_fparam_tensor, (1, self.numb_fparam)), (nf, 1)
)

# check fparam dim, concate to input descriptor
if self.numb_fparam > 0:
assert fparam is not None, "fparam should not be None"
Expand Down
7 changes: 6 additions & 1 deletion deepmd/dpmodel/fitting/invar_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ class InvarFitting(GeneralFitting):
Atomic contributions of the excluded atom types are set zero.
type_map: list[str], Optional
A list of strings. Give the name to each type of atoms.
default_fparam: list[float], optional
The default frame parameter. If set, when `fparam.npy` files are not included in the data system,
this value will be used as the default value for the frame parameter in the fitting net.
"""

Expand Down Expand Up @@ -138,6 +141,7 @@ def __init__(
exclude_types: list[int] = [],
type_map: Optional[list[str]] = None,
seed: Optional[Union[int, list[int]]] = None,
default_fparam: Optional[list[float]] = None,
) -> None:
if tot_ener_zero:
raise NotImplementedError("tot_ener_zero is not implemented")
Expand Down Expand Up @@ -173,6 +177,7 @@ def __init__(
else [x is not None for x in atom_ener],
type_map=type_map,
seed=seed,
default_fparam=default_fparam,
)

def serialize(self) -> dict:
Expand All @@ -185,7 +190,7 @@ def serialize(self) -> dict:
@classmethod
def deserialize(cls, data: dict) -> "GeneralFitting":
data = data.copy()
check_version_compatibility(data.pop("@version", 1), 3, 1)
check_version_compatibility(data.pop("@version", 1), 4, 1)
return super().deserialize(data)

def _net_out_dim(self):
Expand Down
3 changes: 3 additions & 0 deletions deepmd/dpmodel/fitting/make_base_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ def compute_output_stats(self, merged) -> NoReturn:
"""Update the output bias for fitting net."""
raise NotImplementedError

def need_additional_input(self) -> bool:
return False

@abstractmethod
def get_type_map(self) -> list[str]:
"""Get the name to each type of atoms."""
Expand Down
9 changes: 7 additions & 2 deletions deepmd/dpmodel/fitting/polarizability_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ class PolarFitting(GeneralFitting):
Whether to shift the diagonal part of the polarizability matrix. The shift operation is carried out after scale.
type_map: list[str], Optional
A list of strings. Give the name to each type of atoms.
default_fparam: list[float], optional
The default frame parameter. If set, when `fparam.npy` files are not included in the data system,
this value will be used as the default value for the frame parameter in the fitting net.
"""

def __init__(
Expand Down Expand Up @@ -117,6 +120,7 @@ def __init__(
shift_diag: bool = True,
type_map: Optional[list[str]] = None,
seed: Optional[Union[int, list[int]]] = None,
default_fparam: Optional[list[float]] = None,
) -> None:
if tot_ener_zero:
raise NotImplementedError("tot_ener_zero is not implemented")
Expand Down Expand Up @@ -164,6 +168,7 @@ def __init__(
exclude_types=exclude_types,
type_map=type_map,
seed=seed,
default_fparam=default_fparam,
)

def _net_out_dim(self):
Expand All @@ -189,7 +194,7 @@ def __getitem__(self, key):
def serialize(self) -> dict:
data = super().serialize()
data["type"] = "polar"
data["@version"] = 4
data["@version"] = 5
data["embedding_width"] = self.embedding_width
data["fit_diag"] = self.fit_diag
data["shift_diag"] = self.shift_diag
Expand All @@ -200,7 +205,7 @@ def serialize(self) -> dict:
@classmethod
def deserialize(cls, data: dict) -> "GeneralFitting":
data = data.copy()
check_version_compatibility(data.pop("@version", 1), 4, 1)
check_version_compatibility(data.pop("@version", 1), 5, 1)
var_name = data.pop("var_name", None)
assert var_name == "polar"
return super().deserialize(data)
Expand Down
27 changes: 25 additions & 2 deletions deepmd/dpmodel/fitting/property_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
from deepmd.dpmodel.fitting.invar_fitting import (
InvarFitting,
)
from deepmd.dpmodel.output_def import (
FittingOutputDef,
OutputVariableDef,
)
from deepmd.utils.version import (
check_version_compatibility,
)
Expand Down Expand Up @@ -61,6 +65,9 @@ class PropertyFittingNet(InvarFitting):
Atomic contributions of the excluded atom types are set zero.
type_map: list[str], Optional
A list of strings. Give the name to each type of atoms.
default_fparam: list[float], optional
The default frame parameter. If set, when `fparam.npy` files are not included in the data system,
this value will be used as the default value for the frame parameter in the fitting net.
"""

def __init__(
Expand All @@ -83,6 +90,7 @@ def __init__(
mixed_types: bool = True,
exclude_types: list[int] = [],
type_map: Optional[list[str]] = None,
default_fparam: Optional[list] = None,
# not used
seed: Optional[int] = None,
) -> None:
Expand All @@ -106,12 +114,27 @@ def __init__(
mixed_types=mixed_types,
exclude_types=exclude_types,
type_map=type_map,
default_fparam=default_fparam,
)

def output_def(self) -> FittingOutputDef:
return FittingOutputDef(
[
OutputVariableDef(
self.var_name,
[self.dim_out],
reducible=True,
r_differentiable=False,
c_differentiable=False,
intensive=self.intensive,
),
]
)

@classmethod
def deserialize(cls, data: dict) -> "PropertyFittingNet":
data = data.copy()
check_version_compatibility(data.pop("@version"), 4, 1)
check_version_compatibility(data.pop("@version"), 5, 1)
data.pop("dim_out")
data["property_name"] = data.pop("var_name")
data.pop("tot_ener_zero")
Expand All @@ -131,6 +154,6 @@ def serialize(self) -> dict:
"task_dim": self.task_dim,
"intensive": self.intensive,
}
dd["@version"] = 4
dd["@version"] = 5

return dd
Loading
Loading