From ac6b1845853563af48fbed2508647cab2da3d9d3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Sep 2025 15:18:00 +0000 Subject: [PATCH 1/5] Initial plan From 3a79386aba66eccfbe2494baefd052704c8b501b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Sep 2025 15:39:16 +0000 Subject: [PATCH 2/5] fix(tf): handle dipole model bias reshape in backend conversion Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> --- deepmd/tf/model/model.py | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/deepmd/tf/model/model.py b/deepmd/tf/model/model.py index 3377ed2d51..1022974a95 100644 --- a/deepmd/tf/model/model.py +++ b/deepmd/tf/model/model.py @@ -826,19 +826,30 @@ def deserialize(cls, data: dict, suffix: str = "") -> "Descriptor": # deepcopy is not used for performance reasons data["fitting"] = data["fitting"].copy() data["fitting"]["@variables"] = data["fitting"]["@variables"].copy() - if ( - int(np.any(data["fitting"]["@variables"]["bias_atom_e"])) - + int(np.any(data["@variables"]["out_bias"])) - > 1 - ): - raise ValueError( - "fitting/@variables/bias_atom_e and @variables/out_bias should not be both non-zero" + + # For dipole fitting, out_bias and bias_atom_e have different purposes and shapes + # out_bias: [1, ntypes, 3] for dipole output + # bias_atom_e: [ntypes, embedding_width] for internal fitting network + # They should not be added together for dipole models + fitting_type = data["fitting"].get("type", "energy") + if fitting_type == "dipole": + # For dipole models, keep out_bias separate - don't add to bias_atom_e + pass + else: + # For non-dipole models (e.g., energy), use the original logic + if ( + int(np.any(data["fitting"]["@variables"]["bias_atom_e"])) + + int(np.any(data["@variables"]["out_bias"])) + > 1 + ): + raise ValueError( + "fitting/@variables/bias_atom_e and @variables/out_bias should not be both non-zero" + ) + data["fitting"]["@variables"]["bias_atom_e"] = data["fitting"][ + "@variables" + ]["bias_atom_e"] + data["@variables"]["out_bias"].reshape( + data["fitting"]["@variables"]["bias_atom_e"].shape ) - data["fitting"]["@variables"]["bias_atom_e"] = data["fitting"][ - "@variables" - ]["bias_atom_e"] + data["@variables"]["out_bias"].reshape( - data["fitting"]["@variables"]["bias_atom_e"].shape - ) fitting = Fitting.deserialize(data.pop("fitting"), suffix=suffix) # pass descriptor type embedding to model if descriptor.explicit_ntypes: From eaf5411d2564cd22eede10fb4c4b81ec1251f377 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Sep 2025 07:14:07 +0000 Subject: [PATCH 3/5] fix(tf): extend bias reshape fix to cover all fitting types Handle all GeneralFitting types (dipole, polar) vs InvarFitting types (ener, dos, property) correctly in backend conversion bias reshaping logic. Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com> --- deepmd/tf/model/model.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/deepmd/tf/model/model.py b/deepmd/tf/model/model.py index 1022974a95..ef351d1f87 100644 --- a/deepmd/tf/model/model.py +++ b/deepmd/tf/model/model.py @@ -827,16 +827,19 @@ def deserialize(cls, data: dict, suffix: str = "") -> "Descriptor": data["fitting"] = data["fitting"].copy() data["fitting"]["@variables"] = data["fitting"]["@variables"].copy() - # For dipole fitting, out_bias and bias_atom_e have different purposes and shapes - # out_bias: [1, ntypes, 3] for dipole output - # bias_atom_e: [ntypes, embedding_width] for internal fitting network - # They should not be added together for dipole models + # For InvarFitting types (ener, dos, property), out_bias can be reshaped and added to bias_atom_e + # For GeneralFitting types (dipole, polar), out_bias and bias_atom_e have different purposes and shapes + # and should not be added together fitting_type = data["fitting"].get("type", "energy") - if fitting_type == "dipole": - # For dipole models, keep out_bias separate - don't add to bias_atom_e - pass - else: - # For non-dipole models (e.g., energy), use the original logic + if fitting_type in [ + "ener", + "energy", + "dos", + "property", + "direct_force", + "direct_force_ener", + ]: + # For InvarFitting types, use the original logic to reshape and add out_bias to bias_atom_e if ( int(np.any(data["fitting"]["@variables"]["bias_atom_e"])) + int(np.any(data["@variables"]["out_bias"])) @@ -850,6 +853,10 @@ def deserialize(cls, data: dict, suffix: str = "") -> "Descriptor": ]["bias_atom_e"] + data["@variables"]["out_bias"].reshape( data["fitting"]["@variables"]["bias_atom_e"].shape ) + else: + # For GeneralFitting types (dipole, polar), keep out_bias separate - don't add to bias_atom_e + # These fitting types have different bias structures that are incompatible + pass fitting = Fitting.deserialize(data.pop("fitting"), suffix=suffix) # pass descriptor type embedding to model if descriptor.explicit_ntypes: From 95aef5da85906725cd2b15c92c0f66ce1d99d3db Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Thu, 4 Sep 2025 15:32:11 +0800 Subject: [PATCH 4/5] Update model.py Signed-off-by: Jinzhe Zeng --- deepmd/tf/model/model.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/deepmd/tf/model/model.py b/deepmd/tf/model/model.py index ef351d1f87..ae6047cecb 100644 --- a/deepmd/tf/model/model.py +++ b/deepmd/tf/model/model.py @@ -830,14 +830,11 @@ def deserialize(cls, data: dict, suffix: str = "") -> "Descriptor": # For InvarFitting types (ener, dos, property), out_bias can be reshaped and added to bias_atom_e # For GeneralFitting types (dipole, polar), out_bias and bias_atom_e have different purposes and shapes # and should not be added together - fitting_type = data["fitting"].get("type", "energy") + fitting_type = data["fitting"].get("type", "ener") if fitting_type in [ "ener", - "energy", "dos", "property", - "direct_force", - "direct_force_ener", ]: # For InvarFitting types, use the original logic to reshape and add out_bias to bias_atom_e if ( @@ -853,10 +850,8 @@ def deserialize(cls, data: dict, suffix: str = "") -> "Descriptor": ]["bias_atom_e"] + data["@variables"]["out_bias"].reshape( data["fitting"]["@variables"]["bias_atom_e"].shape ) - else: - # For GeneralFitting types (dipole, polar), keep out_bias separate - don't add to bias_atom_e - # These fitting types have different bias structures that are incompatible - pass + # For GeneralFitting types (dipole, polar), keep out_bias separate - don't add to bias_atom_e + # These fitting types have different bias structures that are incompatible fitting = Fitting.deserialize(data.pop("fitting"), suffix=suffix) # pass descriptor type embedding to model if descriptor.explicit_ntypes: From afc4c382860167ccae411c6fb18f57400954497b Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Fri, 5 Sep 2025 18:31:41 +0800 Subject: [PATCH 5/5] fix serialize Signed-off-by: Jinzhe Zeng --- deepmd/tf/model/model.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/deepmd/tf/model/model.py b/deepmd/tf/model/model.py index ae6047cecb..5e26569524 100644 --- a/deepmd/tf/model/model.py +++ b/deepmd/tf/model/model.py @@ -900,7 +900,10 @@ def serialize(self, suffix: str = "") -> dict: ntypes = len(self.get_type_map()) dict_fit = self.fitting.serialize(suffix=suffix) - if dict_fit.get("@variables", {}).get("bias_atom_e") is not None: + if ( + dict_fit.get("@variables", {}).get("bias_atom_e") is not None + and dict_fit["dim_out"] == dict_fit["embedding_width"] + ): out_bias = dict_fit["@variables"]["bias_atom_e"].reshape( [1, ntypes, dict_fit["dim_out"]] )