Skip to content

Commit

Permalink
delete sub_var_name
Browse files Browse the repository at this point in the history
  • Loading branch information
Chengqian-Zhang committed Dec 18, 2024
1 parent c9b7ab4 commit 15eb6d0
Show file tree
Hide file tree
Showing 14 changed files with 74 additions and 211 deletions.
20 changes: 4 additions & 16 deletions deepmd/dpmodel/fitting/property_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,8 @@ class PropertyFittingNet(InvarFitting):
intensive
Whether the fitting property is intensive.
property_name:
The names of fitting properties, which should be consistent with the property names in the dataset.
If the data file is named `humo.npy`, this parameter should be "humo" or ["humo"].
If you want to fit two properties at the same time, supposing that the data files are named `humo.npy` and `lumo.npy`,
this parameter should be `["humo", "lumo"]`.
property_dim:
The dimensions of fitting properties, which should be consistent with the property dimensions in the dataset.
Note that the order here must be the same as the order of `property_name`.
The name of fitting property, which should be consistent with the property name in the dataset.
If the data file is named `humo.npy`, this parameter should be "humo".
resnet_dt
Time-step `dt` in the resnet construction:
:math:`y = x + dt * \phi (Wx + b)`
Expand Down Expand Up @@ -78,8 +73,7 @@ def __init__(
rcond: Optional[float] = None,
trainable: Union[bool, list[bool]] = True,
intensive: bool = False,
property_name: Union[str, list] = "property",
property_dim: Union[int, list] = 1,
property_name: str = "property",
resnet_dt: bool = True,
numb_fparam: int = 0,
numb_aparam: int = 0,
Expand All @@ -94,14 +88,9 @@ def __init__(
) -> None:
self.task_dim = task_dim
self.intensive = intensive
if isinstance(property_name, str):
property_name = [property_name]
self.property_name = property_name
if isinstance(property_dim, int):
property_dim = [property_dim]
self.property_dim = property_dim
super().__init__(
var_name="property",
var_name=property_name,
ntypes=ntypes,
dim_descrpt=dim_descrpt,
dim_out=task_dim,
Expand Down Expand Up @@ -143,7 +132,6 @@ def serialize(self) -> dict:
"task_dim": self.task_dim,
"intensive": self.intensive,
"property_name": self.property_name,
"property_dim": self.property_dim,
}
dd["@version"] = 4

Expand Down
9 changes: 0 additions & 9 deletions deepmd/dpmodel/output_def.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,6 @@ class OutputVariableDef:
If the derivatives of variable have magnetic parts.
intensive : bool
It indicates whether the fitting property is intensive or extensive.
sub_var_name: Optional[Union[list[str], str]]
It is only useful in the property fitting. When one wants to fit multiple properties,
I need a uniform key "property" to manage these multiple properties, which can be seen as sub-names of "property".
For example, when one wants to fit "humo" and "lumo" which store in "humo.npy" and "lumo.npy",
the `sub_var_name` of "property" is ["humo", "lumo"].
"""

def __init__(
Expand All @@ -206,7 +201,6 @@ def __init__(
r_hessian: bool = False,
magnetic: bool = False,
intensive: bool = False,
sub_var_name: Optional[Union[list[str], str]] = None,
) -> None:
self.name = name
self.shape = list(shape)
Expand All @@ -230,9 +224,6 @@ def __init__(
self.r_hessian = r_hessian
self.magnetic = magnetic
self.intensive = intensive
if isinstance(sub_var_name, str):
sub_var_name = [sub_var_name]
self.sub_var_name = sub_var_name
if self.r_hessian:
if not self.reducible:
raise ValueError("only reducible variable can calculate hessian")
Expand Down
41 changes: 10 additions & 31 deletions deepmd/entrypoints/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -780,17 +780,10 @@ def test_property(
arrays with results and their shapes
"""
property_name = dp.get_property_name()
property_dim = dp.get_property_dim()
assert isinstance(property_name, list)
assert isinstance(property_dim, list)
assert sum(property_dim) == dp.task_dim
assert (
len(property_name) == len(property_dim)
), f"The shape of the `property_name` you provide must be consistent with the `property_dim`, but your `property_name` is {property_name} and your `property_dim` is {property_dim}!"
for name, dim in zip(property_name, property_dim):
data.add(name, dim, atomic=False, must=True, high_prec=True)
if has_atom_property:
data.add(f"atom_{name}", dim, atomic=True, must=False, high_prec=True)
assert isinstance(property_name, str)
data.add(property_name, dp.task_dim, atomic=False, must=True, high_prec=True)
if has_atom_property:
data.add(f"atom_{property_name}", dp.task_dim, atomic=True, must=False, high_prec=True)

if dp.get_dim_fparam() > 0:
data.add(
Expand Down Expand Up @@ -841,26 +834,12 @@ def test_property(
aproperty = ret[1]
aproperty = aproperty.reshape([numb_test, natoms * dp.task_dim])

concat_property = []
concat_aproperty = []
for name, dim in zip(property_name, property_dim):
test_data[name] = test_data[name].reshape([numb_test, dim])
concat_property.append(test_data[name])
if has_atom_property:
test_data[f"atom_{name}"] = test_data[f"atom_{name}"].reshape(
[numb_test, natoms * dim]
)
concat_aproperty.append(test_data[f"atom_{name}"])
test_data["property"] = np.concatenate(concat_property, axis=1)
if has_atom_property:
test_data["atom_property"] = np.concatenate(concat_aproperty, axis=1)

diff_property = property - test_data["property"][:numb_test]
diff_property = property - test_data[property_name][:numb_test]
mae_property = mae(diff_property)
rmse_property = rmse(diff_property)

if has_atom_property:
diff_aproperty = aproperty - test_data["atom_property"][:numb_test]
diff_aproperty = aproperty - test_data[f"atom_{property_name}"][:numb_test]
mae_aproperty = mae(diff_aproperty)
rmse_aproperty = rmse(diff_aproperty)

Expand All @@ -877,27 +856,27 @@ def test_property(
detail_path = Path(detail_file)

for ii in range(numb_test):
test_out = test_data["property"][ii].reshape(-1, 1)
test_out = test_data[property_name][ii].reshape(-1, 1)
pred_out = property[ii].reshape(-1, 1)

frame_output = np.hstack((test_out, pred_out))

save_txt_file(
detail_path.with_suffix(f".property.out.{ii}"),
detail_path.with_suffix(f".{property_name}.out.{ii}"),
frame_output,
header=f"{system} - {ii}: data_property pred_property",
append=append_detail,
)

if has_atom_property:
for ii in range(numb_test):
test_out = test_data["atom_property"][ii].reshape(-1, 1)
test_out = test_data[f"atom_{property_name}"][ii].reshape(-1, 1)
pred_out = aproperty[ii].reshape(-1, 1)

frame_output = np.hstack((test_out, pred_out))

save_txt_file(
detail_path.with_suffix(f".aproperty.out.{ii}"),
detail_path.with_suffix(f".a{property_name}.out.{ii}"),
frame_output,
header=f"{system} - {ii}: data_aproperty pred_aproperty",
append=append_detail,
Expand Down
9 changes: 3 additions & 6 deletions deepmd/infer/deep_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def eval(
The properties of the system, in shape (nframes, num_tasks).
"""
self.change_output_def()

(
coords,
cells,
Expand Down Expand Up @@ -141,13 +142,9 @@ def get_intensive(self) -> bool:
"""Get whether the property is intensive."""
return self.deep_eval.get_intensive()

def get_property_name(self) -> Union[list[str], str]:
"""Get the names of the properties."""
def get_property_name(self) -> str:
"""Get the name of the fitting property."""
return self.deep_eval.get_property_name()

def get_property_dim(self) -> Union[list[int], int]:
"""Get the dimensions of the properties."""
return self.deep_eval.get_property_dim()


__all__ = ["DeepProperty"]
10 changes: 3 additions & 7 deletions deepmd/pt/infer/deep_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,14 +184,10 @@ def get_dim_aparam(self) -> int:
def get_intensive(self) -> bool:
return self.dp.model["Default"].get_intensive()

def get_property_name(self) -> Union[list[str], str]:
"""Get the names of the properties."""
def get_property_name(self) -> str:
"""Get the name of the property."""
return self.dp.model["Default"].get_property_name()

def get_property_dim(self) -> Union[list[int], int]:
"""Get the dimensions of the properties."""
return self.dp.model["Default"].get_property_dim()

@property
def model_type(self) -> type["DeepEvalWrapper"]:
"""The the evaluator of the model type."""
Expand All @@ -208,7 +204,7 @@ def model_type(self) -> type["DeepEvalWrapper"]:
return DeepGlobalPolar
elif "wfc" in model_output_type:
return DeepWFC
elif "property" in model_output_type:
elif self.get_property_name() in model_output_type:
return DeepProperty
else:
raise RuntimeError("Unknown model type")
Expand Down
76 changes: 28 additions & 48 deletions deepmd/pt/loss/property.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ class PropertyLoss(TaskLoss):
def __init__(
self,
task_dim,
property_name: Union[str, list],
property_dim: Union[int, list],
property_name: str,
loss_func: str = "smooth_mae",
metric: list = ["mae"],
beta: float = 1.00,
Expand All @@ -51,16 +50,7 @@ def __init__(
self.loss_func = loss_func
self.metric = metric
self.beta = beta
if isinstance(property_name, str):
property_name = [property_name]
if isinstance(property_dim, int):
property_dim = [property_dim]
self.property_name = property_name
assert self.task_dim == sum(property_dim)
assert (
len(property_name) == len(property_dim)
), f"The shape of the `property_name` you provide must be consistent with the `property_dim`, but your `property_name` is {property_name} and your `property_dim` is {property_dim}!"
self.property_name_dim_mapping = dict(zip(property_name, property_dim))
self.out_bias = out_bias
self.out_std = out_std

Expand Down Expand Up @@ -88,18 +78,9 @@ def forward(self, input_dict, model, label, natoms, learning_rate=0.0, mae=False
Other losses for display.
"""
model_pred = model(**input_dict)
nbz = model_pred["property"].shape[0]
assert model_pred["property"].shape == (nbz, self.task_dim)

concat_property = []
for property_name in self.property_name:
assert label[property_name].shape == (
nbz,
self.property_name_dim_mapping[property_name],
)
concat_property.append(label[property_name])
label["property"] = torch.cat(concat_property, dim=1)
assert label["property"].shape == (nbz, self.task_dim)
nbz = model_pred[self.property_name].shape[0]
assert model_pred[self.property_name].shape == (nbz, self.task_dim)
assert label[self.property_name].shape == (nbz, self.task_dim)

if self.out_std is None:
out_std = model.atomic_model.out_std[0][0]
Expand Down Expand Up @@ -129,28 +110,28 @@ def forward(self, input_dict, model, label, natoms, learning_rate=0.0, mae=False
# loss
if self.loss_func == "smooth_mae":
loss += F.smooth_l1_loss(
(label["property"] - out_bias) / out_std,
(model_pred["property"] - out_bias) / out_std,
(label[self.property_name] - out_bias) / out_std,
(model_pred[self.property_name] - out_bias) / out_std,
reduction="sum",
beta=self.beta,
)
elif self.loss_func == "mae":
loss += F.l1_loss(
(label["property"] - out_bias) / out_std,
(model_pred["property"] - out_bias) / out_std,
(label[self.property_name] - out_bias) / out_std,
(model_pred[self.property_name] - out_bias) / out_std,
reduction="sum",
)
elif self.loss_func == "mse":
loss += F.mse_loss(
(label["property"] - out_bias) / out_std,
(model_pred["property"] - out_bias) / out_std,
(label[self.property_name] - out_bias) / out_std,
(model_pred[self.property_name] - out_bias) / out_std,
reduction="sum",
)
elif self.loss_func == "rmse":
loss += torch.sqrt(
F.mse_loss(
(label["property"] - out_bias) / out_std,
(model_pred["property"] - out_bias) / out_std,
(label[self.property_name] - out_bias) / out_std,
(model_pred[self.property_name] - out_bias) / out_std,
reduction="mean",
)
)
Expand All @@ -160,28 +141,28 @@ def forward(self, input_dict, model, label, natoms, learning_rate=0.0, mae=False
# more loss
if "smooth_mae" in self.metric:
more_loss["smooth_mae"] = F.smooth_l1_loss(
label["property"],
model_pred["property"],
label[self.property_name],
model_pred[self.property_name],
reduction="mean",
beta=self.beta,
).detach()
if "mae" in self.metric:
more_loss["mae"] = F.l1_loss(
label["property"],
model_pred["property"],
label[self.property_name],
model_pred[self.property_name],
reduction="mean",
).detach()
if "mse" in self.metric:
more_loss["mse"] = F.mse_loss(
label["property"],
model_pred["property"],
label[self.property_name],
model_pred[self.property_name],
reduction="mean",
).detach()
if "rmse" in self.metric:
more_loss["rmse"] = torch.sqrt(
F.mse_loss(
label["property"],
model_pred["property"],
label[self.property_name],
model_pred[self.property_name],
reduction="mean",
)
).detach()
Expand All @@ -192,14 +173,13 @@ def forward(self, input_dict, model, label, natoms, learning_rate=0.0, mae=False
def label_requirement(self) -> list[DataRequirementItem]:
"""Return data label requirements needed for this loss calculation."""
label_requirement = []
for property_name in self.property_name:
label_requirement.append(
DataRequirementItem(
property_name,
ndof=self.property_name_dim_mapping[property_name],
atomic=False,
must=True,
high_prec=True,
)
label_requirement.append(
DataRequirementItem(
self.property_name,
ndof=self.task_dim,
atomic=False,
must=True,
high_prec=True,
)
)
return label_requirement
3 changes: 1 addition & 2 deletions deepmd/pt/model/atomic_model/base_atomic_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,6 @@ def change_out_bias(
model_forward=self._get_forward_wrapper_func(),
rcond=self.rcond,
preset_bias=self.preset_out_bias,
atomic_output=self.atomic_output_def(),
)
self._store_out_stat(delta_bias, out_std, add=True)
elif bias_adjust_mode == "set-by-statistic":
Expand All @@ -467,7 +466,7 @@ def change_out_bias(
stat_file_path=stat_file_path,
rcond=self.rcond,
preset_bias=self.preset_out_bias,
atomic_output=self.atomic_output_def(),
property_fitting=("property_name" in vars(self.fitting_net)),
)
self._store_out_stat(bias_out, std_out)
else:
Expand Down
5 changes: 0 additions & 5 deletions deepmd/pt/model/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,6 @@ def _get_standard_model_components(model_params, ntypes):
fitting_net["out_dim"] = descriptor.get_dim_emb()
if "ener" in fitting_net["type"]:
fitting_net["return_energy"] = True
if "property" in fitting_net["type"]:
if isinstance(fitting_net["property_dim"], list):
fitting_net["task_dim"] = sum(fitting_net["property_dim"])
else:
fitting_net["task_dim"] = fitting_net["property_dim"]
fitting = BaseFitting(**fitting_net)
return descriptor, fitting, fitting_net["type"]

Expand Down
Loading

0 comments on commit 15eb6d0

Please sign in to comment.