From 81182318611d3e65b716b61b78bb6daa73d17c14 Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Tue, 10 Jun 2025 21:31:24 +0800 Subject: [PATCH 01/13] update adaptive CINN --- deepmd/pd/train/training.py | 43 ++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/deepmd/pd/train/training.py b/deepmd/pd/train/training.py index d72c270667..07cd738a1c 100644 --- a/deepmd/pd/train/training.py +++ b/deepmd/pd/train/training.py @@ -607,6 +607,35 @@ def warm_up_linear(step, warmup_steps): ) backend = "CINN" if CINN else None + + # NOTE: This is a trick to decide the right input_spec for wrapper.forward + _, label_dict, _ = self.get_data(is_train=True, task_key="Default") + label_dict_spec = { + "find_box": np.float32(1.0), + "find_coord": np.float32(1.0), + "find_numb_copy": np.float32(0.0), + "numb_copy": static.InputSpec([1, 1], "int64", name="numb_copy"), + "find_energy": np.float32(1.0), + "energy": static.InputSpec([1, 1], "float64", name="energy"), + "find_force": np.float32(1.0), + "force": static.InputSpec([1, -1, 3], "float64", name="force"), + "find_virial": np.float32(0.0), + "virial": static.InputSpec([1, 9], "float64", name="virial"), + "natoms": static.InputSpec([1, -1], "int32", name="natoms"), + } + if "virial" not in label_dict: + label_dict_spec.pop("virial") + if "find_virial" not in label_dict: + label_dict_spec.pop("find_virial") + if "energy" not in label_dict: + label_dict_spec.pop("energy") + if "find_energy" not in label_dict: + label_dict_spec.pop("find_energy") + if "force" not in label_dict: + label_dict_spec.pop("force") + if "find_force" not in label_dict: + label_dict_spec.pop("find_force") + self.wrapper.forward = jit.to_static( backend=backend, input_spec=[ @@ -615,19 +644,7 @@ def warm_up_linear(step, warmup_steps): None, # spin static.InputSpec([1, 9], "float64", name="box"), # box static.InputSpec([], "float64", name="cur_lr"), # cur_lr - { - "find_box": np.float32(1.0), - "find_coord": np.float32(1.0), - "find_numb_copy": np.float32(0.0), - "numb_copy": static.InputSpec( - [1, 1], "int64", name="numb_copy" - ), - "find_energy": np.float32(1.0), - "energy": static.InputSpec([1, 1], "float64", name="energy"), - "find_force": np.float32(1.0), - "force": static.InputSpec([1, -1, 3], "float64", name="force"), - "natoms": static.InputSpec([1, -1], "int32", name="natoms"), - }, # label, + label_dict_spec, # label, # None, # task_key # False, # inference_only # False, # do_atomic_virial From 29bedd3ddf91d304eab2f52762e38edc3931b479 Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Wed, 11 Jun 2025 02:07:47 +0800 Subject: [PATCH 02/13] support loc_mapping in pd bkd --- .pre-commit-config.yaml | 52 +- deepmd/pd/entrypoints/main.py | 4 + deepmd/pd/model/descriptor/dpa3.py | 14 +- deepmd/pd/model/descriptor/env_mat.py | 14 +- deepmd/pd/model/descriptor/repflow_layer.py | 506 +++++++++++++++++--- deepmd/pd/model/descriptor/repflows.py | 174 +++++-- deepmd/pd/model/descriptor/repformers.py | 8 +- deepmd/pd/utils/env.py | 2 + deepmd/pd/utils/preprocess.py | 21 +- deepmd/pd/utils/spin.py | 1 - deepmd/pd/utils/utils.py | 128 ++++- 11 files changed, 769 insertions(+), 155 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cee3d7f2ce..77dab6f3aa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -65,13 +65,13 @@ repos: - id: clang-format exclude: ^(source/3rdparty|source/lib/src/gpu/cudart/.+\.inc|.+\.ipynb$|.+\.json$) # markdown, yaml, CSS, javascript - - repo: https://github.com/pre-commit/mirrors-prettier - rev: v4.0.0-alpha.8 - hooks: - - id: prettier - types_or: [markdown, yaml, css] - # workflow files cannot be modified by pre-commit.ci - exclude: ^(source/3rdparty|\.github/workflows|\.clang-format) + # - repo: https://github.com/pre-commit/mirrors-prettier + # rev: v4.0.0-alpha.8 + # hooks: + # - id: prettier + # types_or: [markdown, yaml, css] + # # workflow files cannot be modified by pre-commit.ci + # exclude: ^(source/3rdparty|\.github/workflows|\.clang-format) # Shell - repo: https://github.com/scop/pre-commit-shfmt rev: v3.11.0-1 @@ -83,25 +83,25 @@ repos: hooks: - id: cmake-format #- id: cmake-lint - - repo: https://github.com/njzjz/mirrors-bibtex-tidy - rev: v1.13.0 - hooks: - - id: bibtex-tidy - args: - - --curly - - --numeric - - --align=13 - - --blank-lines - # disable sort: the order of keys and fields has explict meanings - #- --sort=key - - --duplicates=key,doi,citation,abstract - - --merge=combine - #- --sort-fields - #- --strip-comments - - --trailing-commas - - --encode-urls - - --remove-empty-fields - - --wrap=80 + # - repo: https://github.com/njzjz/mirrors-bibtex-tidy + # rev: v1.13.0 + # hooks: + # - id: bibtex-tidy + # args: + # - --curly + # - --numeric + # - --align=13 + # - --blank-lines + # # disable sort: the order of keys and fields has explict meanings + # #- --sort=key + # - --duplicates=key,doi,citation,abstract + # - --merge=combine + # #- --sort-fields + # #- --strip-comments + # - --trailing-commas + # - --encode-urls + # - --remove-empty-fields + # - --wrap=80 # license header - repo: https://github.com/Lucas-C/pre-commit-hooks rev: v1.5.5 diff --git a/deepmd/pd/entrypoints/main.py b/deepmd/pd/entrypoints/main.py index 8d96c4e6f2..c0a7cb769a 100644 --- a/deepmd/pd/entrypoints/main.py +++ b/deepmd/pd/entrypoints/main.py @@ -41,6 +41,9 @@ from deepmd.pd.train.wrapper import ( ModelWrapper, ) +from deepmd.pd.utils import ( + env, +) from deepmd.pd.utils.dataloader import ( DpLoaderSet, ) @@ -233,6 +236,7 @@ def train( output: str = "out.json", ) -> None: log.info("Configuration path: %s", input_file) + env.CUSTOM_OP_USE_JIT = False if LOCAL_RANK == 0: SummaryPrinter()() with open(input_file) as fin: diff --git a/deepmd/pd/model/descriptor/dpa3.py b/deepmd/pd/model/descriptor/dpa3.py index 0f1a8f4c2f..eed4d8a385 100644 --- a/deepmd/pd/model/descriptor/dpa3.py +++ b/deepmd/pd/model/descriptor/dpa3.py @@ -91,7 +91,7 @@ class DescrptDPA3(BaseDescriptor, paddle.nn.Layer): Whether to use bias in the type embedding layer. use_loc_mapping : bool, Optional Whether to use local atom index mapping in training or non-parallel inference. - Not supported yet in Paddle. + When True, local indexing and mapping are applied to neighbor lists and embeddings during descriptor computation. type_map : list[str], Optional A list of strings. Give the name to each type of atoms. @@ -117,7 +117,7 @@ def __init__( seed: Optional[Union[int, list[int]]] = None, use_econf_tebd: bool = False, use_tebd_bias: bool = False, - use_loc_mapping: bool = False, + use_loc_mapping: bool = True, type_map: Optional[list[str]] = None, ) -> None: super().__init__() @@ -160,6 +160,8 @@ def init_subclass_params(sub_data, sub_class): fix_stat_std=self.repflow_args.fix_stat_std, optim_update=self.repflow_args.optim_update, smooth_edge_update=self.repflow_args.smooth_edge_update, + edge_init_use_dist=self.repflow_args.edge_init_use_dist, + use_exp_switch=self.repflow_args.use_exp_switch, use_dynamic_sel=self.repflow_args.use_dynamic_sel, sel_reduce_factor=self.repflow_args.sel_reduce_factor, use_loc_mapping=use_loc_mapping, @@ -170,8 +172,8 @@ def init_subclass_params(sub_data, sub_class): ) self.use_econf_tebd = use_econf_tebd - self.use_tebd_bias = use_tebd_bias self.use_loc_mapping = use_loc_mapping + self.use_tebd_bias = use_tebd_bias self.type_map = type_map self.tebd_dim = self.repflow_args.n_dim self.type_embedding = TypeEmbedNet( @@ -487,12 +489,16 @@ def forward( The smooth switch function. shape: nf x nloc x nnei """ + parallel_mode = comm_dict is not None # cast the input to internal precsion extended_coord = extended_coord.to(dtype=self.prec) nframes, nloc, nnei = nlist.shape nall = extended_coord.reshape([nframes, -1]).shape[1] // 3 - node_ebd_ext = self.type_embedding(extended_atype) + if not parallel_mode and self.use_loc_mapping: + node_ebd_ext = self.type_embedding(extended_atype[:, :nloc]) + else: + node_ebd_ext = self.type_embedding(extended_atype) node_ebd_inp = node_ebd_ext[:, :nloc, :] # repflows node_ebd, edge_ebd, h2, rot_mat, sw = self.repflows( diff --git a/deepmd/pd/model/descriptor/env_mat.py b/deepmd/pd/model/descriptor/env_mat.py index 9b72da0b16..214fb593de 100644 --- a/deepmd/pd/model/descriptor/env_mat.py +++ b/deepmd/pd/model/descriptor/env_mat.py @@ -3,6 +3,7 @@ import paddle from deepmd.pd.utils.preprocess import ( + compute_exp_sw, compute_smooth_weight, ) @@ -14,6 +15,7 @@ def _make_env_mat( ruct_smth: float, radial_only: bool = False, protection: float = 0.0, + use_exp_switch: bool = False, ): """Make smooth environment matrix.""" bsz, natoms, nnei = nlist.shape @@ -24,7 +26,8 @@ def _make_env_mat( nlist = paddle.where(mask, nlist, nall - 1) coord_l = coord[:, :natoms].reshape([bsz, -1, 1, 3]) index = nlist.reshape([bsz, -1]).unsqueeze(-1).expand([-1, -1, 3]) - coord_r = paddle.take_along_axis(coord, axis=1, indices=index) + coord_pad = paddle.concat([coord, coord[:, -1:, :] + rcut], axis=1) + coord_r = paddle.take_along_axis(coord_pad, axis=1, indices=index) coord_r = coord_r.reshape([bsz, natoms, nnei, 3]) diff = coord_r - coord_l length = paddle.linalg.norm(diff, axis=-1, keepdim=True) @@ -32,7 +35,11 @@ def _make_env_mat( length = length + (~mask.unsqueeze(-1)).astype(length.dtype) t0 = 1 / (length + protection) t1 = diff / (length + protection) ** 2 - weight = compute_smooth_weight(length, ruct_smth, rcut) + weight = ( + compute_smooth_weight(length, ruct_smth, rcut) + if not use_exp_switch + else compute_exp_sw(length, ruct_smth, rcut) + ) weight = weight * mask.unsqueeze(-1).astype(weight.dtype) if radial_only: env_mat = t0 * weight @@ -51,6 +58,7 @@ def prod_env_mat( rcut_smth: float, radial_only: bool = False, protection: float = 0.0, + use_exp_switch: bool = False, ): """Generate smooth environment matrix from atom coordinates and other context. @@ -63,6 +71,7 @@ def prod_env_mat( - rcut_smth: Smooth hyper-parameter for pair force & energy. - radial_only: Whether to return a full description or a radial-only descriptor. - protection: Protection parameter to prevent division by zero errors during calculations. + - use_exp_switch: Whether to use the exponential switch function. Returns ------- @@ -75,6 +84,7 @@ def prod_env_mat( rcut_smth, radial_only, protection=protection, + use_exp_switch=use_exp_switch, ) # shape [n_atom, dim, 4 or 1] t_avg = mean[atype] # [n_atom, dim, 4 or 1] t_std = stddev[atype] # [n_atom, dim, 4 or 1] diff --git a/deepmd/pd/model/descriptor/repflow_layer.py b/deepmd/pd/model/descriptor/repflow_layer.py index f1bdd0439d..78cfa7a56d 100644 --- a/deepmd/pd/model/descriptor/repflow_layer.py +++ b/deepmd/pd/model/descriptor/repflow_layer.py @@ -19,6 +19,9 @@ from deepmd.pd.model.network.mlp import ( MLPLayer, ) +from deepmd.pd.model.network.utils import ( + aggregate, +) from deepmd.pd.utils.env import ( PRECISION_DICT, ) @@ -326,6 +329,61 @@ def _cal_hg( h2g2 = paddle.matmul(paddle.matrix_transpose(h2), edge_ebd) * invnnei return h2g2 + @staticmethod + def _cal_hg_dynamic( + flat_edge_ebd: paddle.Tensor, + flat_h2: paddle.Tensor, + flat_sw: paddle.Tensor, + owner: paddle.Tensor, + num_owner: int, + nb: int, + nloc: int, + scale_factor: float, + ) -> paddle.Tensor: + """ + Calculate the transposed rotation matrix. + + Parameters + ---------- + flat_edge_ebd + Flatted neighbor-wise/pair-wise invariant rep tensors, with shape n_edge x e_dim. + flat_h2 + Flatted neighbor-wise/pair-wise equivariant rep tensors, with shape n_edge x 3. + flat_sw + Flatted switch function, which equals 1 within the rcut_smth range, smoothly decays from 1 to 0 between rcut_smth and rcut, + and remains 0 beyond rcut, with shape n_edge. + owner + The owner index of the neighbor to reduce on. + num_owner : int + The total number of the owner. + nb : int + The number of batches. + nloc : int + The number of local atoms. + scale_factor : float + The scale factor to apply after reduce. + + Returns + ------- + hg + The transposed rotation matrix, with shape nf x nloc x 3 x e_dim. + """ + n_edge, e_dim = flat_edge_ebd.shape + # n_edge x e_dim + flat_edge_ebd = flat_edge_ebd * flat_sw.unsqueeze(-1) + # n_edge x 3 x e_dim + flat_h2g2 = (flat_h2[..., None] * flat_edge_ebd[:, None, :]).reshape( + [-1, 3 * e_dim] + ) + # nf x nloc x 3 x e_dim + h2g2 = ( + aggregate(flat_h2g2, owner, average=False, num_owner=num_owner).reshape( + [nb, nloc, 3, e_dim] + ) + * scale_factor + ) + return h2g2 + @staticmethod def _cal_grrg(h2g2: paddle.Tensor, axis_neuron: int) -> paddle.Tensor: """ @@ -398,6 +456,63 @@ def symmetrization_op( g1_13 = self._cal_grrg(h2g2, axis_neuron) return g1_13 + def symmetrization_op_dynamic( + self, + flat_edge_ebd: paddle.Tensor, + flat_h2: paddle.Tensor, + flat_sw: paddle.Tensor, + owner: paddle.Tensor, + num_owner: int, + nb: int, + nloc: int, + scale_factor: float, + axis_neuron: int, + ) -> paddle.Tensor: + """ + Symmetrization operator to obtain atomic invariant rep. + + Parameters + ---------- + flat_edge_ebd + Flatted neighbor-wise/pair-wise invariant rep tensors, with shape n_edge x e_dim. + flat_h2 + Flatted neighbor-wise/pair-wise equivariant rep tensors, with shape n_edge x 3. + flat_sw + Flatted switch function, which equals 1 within the rcut_smth range, smoothly decays from 1 to 0 between rcut_smth and rcut, + and remains 0 beyond rcut, with shape n_edge. + owner + The owner index of the neighbor to reduce on. + num_owner : int + The total number of the owner. + nb : int + The number of batches. + nloc : int + The number of local atoms. + scale_factor : float + The scale factor to apply after reduce. + axis_neuron + Size of the submatrix. + + Returns + ------- + grrg + Atomic invariant rep, with shape nb x nloc x (axis_neuron x e_dim) + """ + # nb x nloc x 3 x e_dim + h2g2 = self._cal_hg_dynamic( + flat_edge_ebd, + flat_h2, + flat_sw, + owner, + num_owner, + nb, + nloc, + scale_factor, + ) + # nb x nloc x (axis x e_dim) + grrg = self._cal_grrg(h2g2, axis_neuron) + return grrg + def optim_angle_update( self, angle_ebd: paddle.Tensor, @@ -419,7 +534,7 @@ def optim_angle_update( node_dim = node_ebd.shape[-1] edge_dim = edge_ebd.shape[-1] # angle_dim, node_dim, edge_dim, edge_dim - sub_angle, sub_node, sub_edge_ij, sub_edge_ik = paddle.split( + sub_angle, sub_node, sub_edge_ik, sub_edge_ij = paddle.split( matrix, [angle_dim, node_dim, edge_dim, edge_dim] ) @@ -428,14 +543,64 @@ def optim_angle_update( # nf * nloc * angle_dim sub_node_update = paddle.matmul(node_ebd, sub_node) # nf * nloc * a_nnei * angle_dim - sub_edge_update_ij = paddle.matmul(edge_ebd, sub_edge_ij) sub_edge_update_ik = paddle.matmul(edge_ebd, sub_edge_ik) + sub_edge_update_ij = paddle.matmul(edge_ebd, sub_edge_ij) result_update = ( bias + sub_node_update.unsqueeze(2).unsqueeze(3) - + sub_edge_update_ij.unsqueeze(2) - + sub_edge_update_ik.unsqueeze(3) + + sub_edge_update_ik.unsqueeze(2) + + sub_edge_update_ij.unsqueeze(3) + + sub_angle_update + ) + return result_update + + def optim_angle_update_dynamic( + self, + flat_angle_ebd: paddle.Tensor, + node_ebd: paddle.Tensor, + flat_edge_ebd: paddle.Tensor, + n2a_index: paddle.Tensor, + eij2a_index: paddle.Tensor, + eik2a_index: paddle.Tensor, + feat: str = "edge", + ) -> paddle.Tensor: + if feat == "edge": + matrix, bias = self.edge_angle_linear1.matrix, self.edge_angle_linear1.bias + elif feat == "angle": + matrix, bias = self.angle_self_linear.matrix, self.angle_self_linear.bias + else: + raise NotImplementedError + nf, nloc, node_dim = node_ebd.shape + edge_dim = flat_edge_ebd.shape[-1] + angle_dim = flat_angle_ebd.shape[-1] + # angle_dim, node_dim, edge_dim, edge_dim + sub_angle, sub_node, sub_edge_ik, sub_edge_ij = paddle.split( + matrix, [angle_dim, node_dim, edge_dim, edge_dim] + ) + + # n_angle * angle_dim + sub_angle_update = paddle.matmul(flat_angle_ebd, sub_angle) + + # nf * nloc * angle_dim + sub_node_update = paddle.matmul(node_ebd, sub_node) + # n_angle * angle_dim + sub_node_update = paddle.index_select( + sub_node_update.reshape(nf * nloc, sub_node_update.shape[-1]), n2a_index, 0 + ) + + # n_edge * angle_dim + sub_edge_update_ik = paddle.matmul(flat_edge_ebd, sub_edge_ik) + sub_edge_update_ij = paddle.matmul(flat_edge_ebd, sub_edge_ij) + # n_angle * angle_dim + sub_edge_update_ik = paddle.index_select(sub_edge_update_ik, eik2a_index, 0) + sub_edge_update_ij = paddle.index_select(sub_edge_update_ij, eij2a_index, 0) + + result_update = ( + bias + + sub_node_update + + sub_edge_update_ik + + sub_edge_update_ij + sub_angle_update ) return result_update @@ -475,9 +640,55 @@ def optim_edge_update( ) return result_update + def optim_edge_update_dynamic( + self, + node_ebd: paddle.Tensor, + node_ebd_ext: paddle.Tensor, + flat_edge_ebd: paddle.Tensor, + n2e_index: paddle.Tensor, + n_ext2e_index: paddle.Tensor, + feat: str = "node", + ) -> paddle.Tensor: + if feat == "node": + matrix, bias = self.node_edge_linear.matrix, self.node_edge_linear.bias + elif feat == "edge": + matrix, bias = self.edge_self_linear.matrix, self.edge_self_linear.bias + else: + raise NotImplementedError + assert bias is not None + nf, nall, node_dim = node_ebd_ext.shape + _, nloc, _ = node_ebd.shape + edge_dim = flat_edge_ebd.shape[-1] + # node_dim, node_dim, edge_dim + node, node_ext, edge = paddle.split(matrix, [node_dim, node_dim, edge_dim]) + + # nf * nloc * node/edge_dim + sub_node_update = paddle.matmul(node_ebd, node) + # n_edge * node/edge_dim + sub_node_update = paddle.index_select( + sub_node_update.reshape(nf * nloc, sub_node_update.shape[-1]), + n2e_index, + 0, + ) + + # nf * nall * node/edge_dim + sub_node_ext_update = paddle.matmul(node_ebd_ext, node_ext) + # n_edge * node/edge_dim + sub_node_ext_update = paddle.index_select( + sub_node_ext_update.reshape(nf * nall, sub_node_update.shape[-1]), + n_ext2e_index, + 0, + ) + + # n_edge * node/edge_dim + sub_edge_update = paddle.matmul(flat_edge_ebd, edge) + + result_update = bias + sub_node_update + sub_edge_update + sub_node_ext_update + return result_update + def forward( self, - node_ebd_ext: paddle.Tensor, # nf x nall x n_dim + node_ebd_ext: paddle.Tensor, # nf x nall x n_dim [OR] nf x nloc x n_dim when not parallel_mode edge_ebd: paddle.Tensor, # nf x nloc x nnei x e_dim h2: paddle.Tensor, # nf x nloc x nnei x 3 angle_ebd: paddle.Tensor, # nf x nloc x a_nnei x a_nnei x a_dim @@ -487,6 +698,8 @@ def forward( a_nlist: paddle.Tensor, # nf x nloc x a_nnei a_nlist_mask: paddle.Tensor, # nf x nloc x a_nnei a_sw: paddle.Tensor, # switch func, nf x nloc x a_nnei + edge_index: paddle.Tensor, # n_edge x 2 + angle_index: paddle.Tensor, # n_angle x 3 ): """ Parameters @@ -511,6 +724,18 @@ def forward( Masks of the neighbor list for angle. real nei 1 otherwise 0 a_sw : nf x nloc x a_nnei Switch function for angle. + edge_index : Optional for dynamic sel, n_edge x 2 + n2e_index : n_edge + Broadcast indices from node(i) to edge(ij), or reduction indices from edge(ij) to node(i). + n_ext2e_index : n_edge + Broadcast indices from extended node(j) to edge(ij). + angle_index : Optional for dynamic sel, n_angle x 3 + n2a_index : n_angle + Broadcast indices from extended node(j) to angle(ijk). + eij2a_index : n_angle + Broadcast indices from extended edge(ij) to angle(ijk), or reduction indices from angle(ijk) to edge(ij). + eik2a_index : n_angle + Broadcast indices from extended edge(ik) to angle(ijk). Returns ------- @@ -524,12 +749,35 @@ def forward( nb, nloc, nnei, _ = edge_ebd.shape nall = node_ebd_ext.shape[1] node_ebd = node_ebd_ext[:, :nloc, :] + n_edge = int(nlist_mask.sum().item()) if paddle.in_dynamic_mode(): assert [nb, nloc] == node_ebd.shape[:2] - if paddle.in_dynamic_mode(): - assert [nb, nloc, nnei] == h2.shape[:3] + if not self.use_dynamic_sel: + if paddle.in_dynamic_mode(): + assert [nb, nloc, nnei, 3] == h2.shape + else: + if paddle.in_dynamic_mode(): + assert [n_edge, 3] == h2.shape del a_nlist # may be used in the future + n2e_index, n_ext2e_index = edge_index[:, 0], edge_index[:, 1] + n2a_index, eij2a_index, eik2a_index = ( + angle_index[:, 0], + angle_index[:, 1], + angle_index[:, 2], + ) + + # nb x nloc x nnei x n_dim [OR] n_edge x n_dim + nei_node_ebd = ( + _make_nei_g1(node_ebd_ext, nlist) + if not self.use_dynamic_sel + else paddle.index_select( + node_ebd_ext.reshape([-1, self.n_dim]), + n_ext2e_index, + 0, + ) + ) + n_update_list: list[paddle.Tensor] = [node_ebd] e_update_list: list[paddle.Tensor] = [edge_ebd] a_update_list: list[paddle.Tensor] = [angle_ebd] @@ -538,8 +786,6 @@ def forward( node_self_mlp = self.act(self.node_self_mlp(node_ebd)) n_update_list.append(node_self_mlp) - nei_node_ebd = _make_nei_g1(node_ebd_ext, nlist) - # node sym (grrg + drrd) node_sym_list: list[paddle.Tensor] = [] node_sym_list.append( @@ -550,6 +796,18 @@ def forward( sw, self.axis_neuron, ) + if not self.use_dynamic_sel + else self.symmetrization_op_dynamic( + edge_ebd, + h2, + sw, + owner=n2e_index, + num_owner=nb * nloc, + nb=nb, + nloc=nloc, + scale_factor=self.dynamic_e_sel ** (-0.5), + axis_neuron=self.axis_neuron, + ) ) node_sym_list.append( self.symmetrization_op( @@ -559,20 +817,47 @@ def forward( sw, self.axis_neuron, ) + if not self.use_dynamic_sel + else self.symmetrization_op_dynamic( + nei_node_ebd, + h2, + sw, + owner=n2e_index, + num_owner=nb * nloc, + nb=nb, + nloc=nloc, + scale_factor=self.dynamic_e_sel ** (-0.5), + axis_neuron=self.axis_neuron, + ) ) node_sym = self.act(self.node_sym_linear(paddle.concat(node_sym_list, axis=-1))) n_update_list.append(node_sym) if not self.optim_update: - # nb x nloc x nnei x (n_dim * 2 + e_dim) - edge_info = paddle.concat( - [ - paddle.tile(node_ebd.unsqueeze(-2), [1, 1, self.nnei, 1]), - nei_node_ebd, - edge_ebd, - ], - axis=-1, - ) + if not self.use_dynamic_sel: + # nb x nloc x nnei x (n_dim * 2 + e_dim) + edge_info = paddle.concat( + [ + paddle.tile(node_ebd.unsqueeze(-2), [1, 1, self.nnei, 1]), + nei_node_ebd, + edge_ebd, + ], + axis=-1, + ) + else: + # n_edge x (n_dim * 2 + e_dim) + edge_info = paddle.concat( + [ + paddle.index_select( + node_ebd.reshape(-1, self.n_dim), + n2e_index, + 0, + ), + nei_node_ebd, + edge_ebd, + ], + axis=-1, + ) else: edge_info = None @@ -592,16 +877,37 @@ def forward( nlist, "node", ) + if not self.use_dynamic_sel + else self.optim_edge_update_dynamic( + node_ebd, + node_ebd_ext, + edge_ebd, + n2e_index, + n_ext2e_index, + "node", + ) ) * sw.unsqueeze(-1) + node_edge_update = ( + (paddle.sum(node_edge_update, axis=-2) / self.nnei) + if not self.use_dynamic_sel + else ( + aggregate( + node_edge_update, + n2e_index, + average=False, + num_owner=nb * nloc, + ).reshape(nb, nloc, node_edge_update.shape[-1]) + / self.dynamic_e_sel + ) + ) - node_edge_update = paddle.sum(node_edge_update, axis=-2) / self.nnei if self.n_multi_edge_message > 1: - # nb x nloc x nnei x h x n_dim + # nb x nloc x h x n_dim node_edge_update_mul_head = node_edge_update.reshape( [nb, nloc, self.n_multi_edge_message, self.n_dim] ) for head_index in range(self.n_multi_edge_message): - n_update_list.append(node_edge_update_mul_head[:, :, head_index, :]) + n_update_list.append(node_edge_update_mul_head[..., head_index, :]) else: n_update_list.append(node_edge_update) # update node_ebd @@ -620,6 +926,15 @@ def forward( nlist, "edge", ) + if not self.use_dynamic_sel + else self.optim_edge_update_dynamic( + node_ebd, + node_ebd_ext, + edge_ebd, + n2e_index, + n_ext2e_index, + "edge", + ) ) e_update_list.append(edge_self_update) @@ -641,48 +956,66 @@ def forward( edge_ebd_for_angle = self.a_compress_e_linear(edge_ebd) else: # use the first a_compress_dim dim for node and edge - node_ebd_for_angle = node_ebd[:, :, : self.n_a_compress_dim] - edge_ebd_for_angle = edge_ebd[:, :, :, : self.e_a_compress_dim] + node_ebd_for_angle = node_ebd[..., : self.n_a_compress_dim] + edge_ebd_for_angle = edge_ebd[..., : self.e_a_compress_dim] else: node_ebd_for_angle = node_ebd edge_ebd_for_angle = edge_ebd - # nb x nloc x a_nnei x e_dim - edge_for_angle = edge_ebd_for_angle[:, :, : self.a_sel, :] - # nb x nloc x a_nnei x e_dim - edge_for_angle = paddle.where( - a_nlist_mask.unsqueeze(-1), - edge_for_angle, - paddle.zeros_like(edge_for_angle), - ).astype(edge_for_angle.dtype) + if not self.use_dynamic_sel: + # nb x nloc x a_nnei x e_dim + edge_ebd_for_angle = edge_ebd_for_angle[..., : self.a_sel, :] + # nb x nloc x a_nnei x e_dim + edge_ebd_for_angle = edge_ebd_for_angle.masked_fill( + ~a_nlist_mask.unsqueeze(-1), 0.0 + ) if not self.optim_update: - # nb x nloc x a_nnei x a_nnei x n_dim - node_for_angle_info = paddle.tile( - node_ebd_for_angle.unsqueeze(2).unsqueeze(2), - [1, 1, self.a_sel, self.a_sel, 1], + # nb x nloc x a_nnei x a_nnei x n_dim [OR] n_angle x n_dim + node_for_angle_info = ( + paddle.tile( + node_ebd_for_angle.unsqueeze(2).unsqueeze(2), + (1, 1, self.a_sel, self.a_sel, 1), + ) + if not self.use_dynamic_sel + else paddle.index_select( + node_ebd_for_angle.reshape([-1, self.n_a_compress_dim]), + n2a_index, + 0, + ) ) - # nb x nloc x (a_nnei) x a_nnei x edge_ebd - edge_for_angle_i = paddle.tile( - edge_for_angle.unsqueeze(2), (1, 1, self.a_sel, 1, 1) + + # nb x nloc x (a_nnei) x a_nnei x e_dim [OR] n_angle x e_dim + edge_for_angle_k = ( + paddle.tile( + edge_ebd_for_angle.unsqueeze(2), (1, 1, self.a_sel, 1, 1) + ) + if not self.use_dynamic_sel + else paddle.index_select(edge_ebd_for_angle, eik2a_index, 0) ) - # nb x nloc x a_nnei x (a_nnei) x e_dim - edge_for_angle_j = paddle.tile( - edge_for_angle.unsqueeze(3), (1, 1, 1, self.a_sel, 1) + # nb x nloc x a_nnei x (a_nnei) x e_dim [OR] n_angle x e_dim + edge_for_angle_j = ( + paddle.tile( + edge_ebd_for_angle.unsqueeze(3), (1, 1, 1, self.a_sel, 1) + ) + if not self.use_dynamic_sel + else paddle.index_select(edge_ebd_for_angle, eij2a_index, 0) ) - # nb x nloc x a_nnei x a_nnei x (e_dim + e_dim) + # nb x nloc x a_nnei x a_nnei x (e_dim + e_dim) [OR] n_angle x (e_dim + e_dim) edge_for_angle_info = paddle.concat( - [edge_for_angle_i, edge_for_angle_j], axis=-1 + [edge_for_angle_k, edge_for_angle_j], axis=1 ) angle_info_list = [angle_ebd] angle_info_list.append(node_for_angle_info) angle_info_list.append(edge_for_angle_info) # nb x nloc x a_nnei x a_nnei x (a + n_dim + e_dim*2) or (a + a/c + a/c) - angle_info = paddle.concat(angle_info_list, axis=-1) + # [OR] + # n_angle x (a + n_dim + e_dim*2) or (a + a/c + a/c) + angle_info = paddle.cat(angle_info_list, axis=1) else: angle_info = None # edge angle message - # nb x nloc x a_nnei x a_nnei x e_dim + # nb x nloc x a_nnei x a_nnei x e_dim [OR] n_angle x e_dim if not self.optim_update: assert angle_info is not None edge_angle_update = self.act(self.edge_angle_linear1(angle_info)) @@ -691,32 +1024,59 @@ def forward( self.optim_angle_update( angle_ebd, node_ebd_for_angle, - edge_for_angle, + edge_ebd_for_angle, + "edge", + ) + if not self.use_dynamic_sel + else self.optim_angle_update_dynamic( + angle_ebd, + node_ebd_for_angle, + edge_ebd_for_angle, + n2a_index, + eij2a_index, + eik2a_index, "edge", ) ) - # nb x nloc x a_nnei x a_nnei x e_dim - weighted_edge_angle_update = ( - a_sw[..., None, None] * a_sw[..., None, :, None] * edge_angle_update - ) - # nb x nloc x a_nnei x e_dim - reduced_edge_angle_update = paddle.sum( - weighted_edge_angle_update, axis=-2 - ) / (self.a_sel**0.5) - # nb x nloc x nnei x e_dim - padding_edge_angle_update = paddle.concat( - [ - reduced_edge_angle_update, - paddle.zeros( - [nb, nloc, self.nnei - self.a_sel, self.e_dim], - dtype=edge_ebd.dtype, - ).to(device=edge_ebd.place), - ], - axis=2, - ) + if not self.use_dynamic_sel: + # nb x nloc x a_nnei x a_nnei x e_dim + weighted_edge_angle_update = ( + a_sw[..., None, None] * a_sw[..., None, :, None] * edge_angle_update + ) + # nb x nloc x a_nnei x e_dim + reduced_edge_angle_update = paddle.sum( + weighted_edge_angle_update, axis=-2 + ) / (self.a_sel**0.5) + # nb x nloc x nnei x e_dim + padding_edge_angle_update = paddle.concat( + [ + reduced_edge_angle_update, + paddle.zeros( + [nb, nloc, self.nnei - self.a_sel, self.e_dim], + dtype=edge_ebd.dtype, + ), + ], + axis=2, + ) + else: + # n_angle x e_dim + weighted_edge_angle_update = edge_angle_update * a_sw.unsqueeze(-1) + # n_edge x e_dim + padding_edge_angle_update = aggregate( + weighted_edge_angle_update, + eij2a_index, + average=False, + num_owner=n_edge, + ) / (self.dynamic_a_sel**0.5) + if not self.smooth_edge_update: # will be deprecated in the future + # not support dynamic index, will pass anyway + if self.use_dynamic_sel: + raise NotImplementedError( + "smooth_edge_update must be True when use_dynamic_sel is True!" + ) full_mask = paddle.concat( [ a_nlist_mask, @@ -727,8 +1087,8 @@ def forward( ], axis=-1, ) - padding_edge_angle_update = paddle.where( - full_mask.unsqueeze(-1), padding_edge_angle_update, edge_ebd + padding_edge_angle_update = padding_edge_angle_update.masked_fill( + ~full_mask.unsqueeze(-1), edge_ebd ) e_update_list.append( self.act(self.edge_angle_linear2(padding_edge_angle_update)) @@ -746,7 +1106,17 @@ def forward( self.optim_angle_update( angle_ebd, node_ebd_for_angle, - edge_for_angle, + edge_ebd_for_angle, + "angle", + ) + if not self.use_dynamic_sel + else self.optim_angle_update_dynamic( + angle_ebd, + node_ebd_for_angle, + edge_ebd_for_angle, + n2a_index, + eij2a_index, + eik2a_index, "angle", ) ) diff --git a/deepmd/pd/model/descriptor/repflows.py b/deepmd/pd/model/descriptor/repflows.py index 3200c26dba..2214116bbc 100644 --- a/deepmd/pd/model/descriptor/repflows.py +++ b/deepmd/pd/model/descriptor/repflows.py @@ -19,6 +19,9 @@ from deepmd.pd.model.network.mlp import ( MLPLayer, ) +from deepmd.pd.model.network.utils import ( + get_graph_index, +) from deepmd.pd.utils import ( env, ) @@ -109,12 +112,35 @@ class DescrptBlockRepflows(DescriptorBlock): smooth_edge_update : bool, optional Whether to make edge update smooth. If True, the edge update from angle message will not use self as padding. + edge_init_use_dist : bool, optional + Whether to use direct distance r to initialize the edge features instead of 1/r. + Note that when using this option, the activation function will not be used when initializing edge features. + use_exp_switch : bool, optional + Whether to use an exponential switch function instead of a polynomial one in the neighbor update. + The exponential switch function ensures neighbor contributions smoothly diminish as the interatomic distance + `r` approaches the cutoff radius `rcut`. Specifically, the function is defined as: + s(r) = \\exp(-\\exp(20 * (r - rcut_smth) / rcut_smth)) for 0 < r \\leq rcut, and s(r) = 0 for r > rcut. + Here, `rcut_smth` is an adjustable smoothing factor and `rcut_smth` should be chosen carefully + according to `rcut`, ensuring s(r) approaches zero smoothly at the cutoff. + Typical recommended values are `rcut_smth` = 5.3 for `rcut` = 6.0, and 3.5 for `rcut` = 4.0. + use_dynamic_sel : bool, optional + Whether to dynamically select neighbors within the cutoff radius. + If True, the exact number of neighbors within the cutoff radius is used + without padding to a fixed selection numbers. + When enabled, users can safely set larger values for `e_sel` or `a_sel` (e.g., 1200 or 300, respectively) + to guarantee capturing all neighbors within the cutoff radius. + Note that when using dynamic selection, the `smooth_edge_update` must be True. + sel_reduce_factor : float, optional + Reduction factor applied to neighbor-scale normalization when `use_dynamic_sel` is True. + In the dynamic selection case, neighbor-scale normalization will use `e_sel / sel_reduce_factor` + or `a_sel / sel_reduce_factor` instead of the raw `e_sel` or `a_sel` values, + accommodating larger selection numbers. + use_loc_mapping : bool, Optional + Whether to use local atom index mapping in training or non-parallel inference. + When True, local indexing and mapping are applied to neighbor lists and embeddings during descriptor computation. optim_update : bool, optional Whether to enable the optimized update method. Uses a more efficient process when enabled. Defaults to True - use_loc_mapping : bool, Optional - Whether to use local atom index mapping in training or non-parallel inference. - Not supported yet in Paddle. ntypes : int Number of element types activation_function : str, optional @@ -162,9 +188,11 @@ def __init__( precision: str = "float64", fix_stat_std: float = 0.3, smooth_edge_update: bool = False, + edge_init_use_dist: bool = False, + use_exp_switch: bool = False, use_dynamic_sel: bool = False, sel_reduce_factor: float = 10.0, - use_loc_mapping: bool = False, + use_loc_mapping: bool = True, optim_update: bool = True, seed: Optional[Union[int, list[int]]] = None, ) -> None: @@ -195,13 +223,21 @@ def __init__( self.fix_stat_std = fix_stat_std self.set_stddev_constant = fix_stat_std != 0.0 self.a_compress_use_split = a_compress_use_split + self.use_loc_mapping = use_loc_mapping self.optim_update = optim_update self.smooth_edge_update = smooth_edge_update - self.use_dynamic_sel = use_dynamic_sel # not supported yet + self.edge_init_use_dist = edge_init_use_dist + self.use_exp_switch = use_exp_switch + self.use_dynamic_sel = use_dynamic_sel self.sel_reduce_factor = sel_reduce_factor - assert not self.use_dynamic_sel, "Dynamic selection is not supported yet." - self.use_loc_mapping = use_loc_mapping - assert not self.use_loc_mapping, "Local mapping is not supported yet." + if self.use_dynamic_sel and not self.smooth_edge_update: + raise NotImplementedError( + "smooth_edge_update must be True when use_dynamic_sel is True!" + ) + if self.sel_reduce_factor <= 0: + raise ValueError( + f"`sel_reduce_factor` must be > 0, got {self.sel_reduce_factor}" + ) self.n_dim = n_dim self.e_dim = e_dim @@ -366,9 +402,9 @@ def forward( mapping: Optional[paddle.Tensor] = None, comm_dict: Optional[dict[str, paddle.Tensor]] = None, ): - if comm_dict is None: + parallel_mode = comm_dict is not None + if not parallel_mode: assert mapping is not None - assert extended_atype_embd is not None nframes, nloc, nnei = nlist.shape nall = extended_coord.reshape([nframes, -1]).shape[1] // 3 atype = extended_atype[:, :nloc] @@ -385,30 +421,13 @@ def forward( self.e_rcut, self.e_rcut_smth, protection=self.env_protection, + use_exp_switch=self.use_exp_switch, ) nlist_mask = nlist != -1 sw = paddle.squeeze(sw, -1) # beyond the cutoff sw should be 0.0 sw = sw.masked_fill(~nlist_mask, 0.0) - # [nframes, nloc, tebd_dim] - if comm_dict is None: - if paddle.in_dynamic_mode(): - assert isinstance(extended_atype_embd, paddle.Tensor) - atype_embd = extended_atype_embd[:, :nloc, :] - if paddle.in_dynamic_mode(): - assert atype_embd.shape == [nframes, nloc, self.n_dim] - else: - atype_embd = extended_atype_embd - if paddle.in_dynamic_mode(): - assert isinstance(atype_embd, paddle.Tensor) - node_ebd = self.act(atype_embd) - n_dim = node_ebd.shape[-1] - # nb x nloc x nnei x 1, nb x nloc x nnei x 3 - edge_input, h2 = paddle.split(dmatrix, [1, 3], axis=-1) - # nb x nloc x nnei x e_dim - edge_ebd = self.act(self.edge_embd(edge_input)) - # get angle nlist (maybe smaller) a_dist_mask = (paddle.linalg.norm(diff, axis=-1) < self.a_rcut)[ :, :, : self.a_sel @@ -424,13 +443,34 @@ def forward( self.a_rcut, self.a_rcut_smth, protection=self.env_protection, + use_exp_switch=self.use_exp_switch, ) a_nlist_mask = a_nlist != -1 a_sw = paddle.squeeze(a_sw, -1) # beyond the cutoff sw should be 0.0 a_sw = a_sw.masked_fill(~a_nlist_mask, 0.0) + # set all padding positions to index of 0 + # if the a neighbor is real or not is indicated by nlist_mask + nlist[nlist == -1] = 0 a_nlist[a_nlist == -1] = 0 + # get node embedding + # [nframes, nloc, tebd_dim] + assert extended_atype_embd is not None + atype_embd = extended_atype_embd[:, :nloc, :] + if paddle.in_dynamic_mode(): + assert list(atype_embd.shape) == [nframes, nloc, self.n_dim] + assert isinstance(atype_embd, paddle.Tensor) # for jit + node_ebd = self.act(atype_embd) + n_dim = node_ebd.shape[-1] + + # get edge and angle embedding input + # nb x nloc x nnei x 1, nb x nloc x nnei x 3 + edge_input, h2 = paddle.split(dmatrix, [1, 3], axis=-1) + if self.edge_init_use_dist: + # nb x nloc x nnei x 1 + edge_input = paddle.linalg.norm(diff, axis=-1, keepdim=True) + # nf x nloc x a_nnei x 3 normalized_diff_i = a_diff / ( paddle.linalg.norm(a_diff, axis=-1, keepdim=True) + 1e-6 @@ -440,18 +480,53 @@ def forward( # nf x nloc x a_nnei x a_nnei # 1 - 1e-6 for paddle.acos stability cosine_ij = paddle.matmul(normalized_diff_i, normalized_diff_j) * (1 - 1e-6) - # nf x nloc x a_nnei x a_nnei x 1 - cosine_ij = cosine_ij.unsqueeze(-1) / (paddle.pi**0.5) - # nf x nloc x a_nnei x a_nnei x a_dim - angle_ebd = self.angle_embd(cosine_ij).reshape( - [nframes, nloc, self.a_sel, self.a_sel, self.a_dim] - ) + angle_input = cosine_ij.unsqueeze(-1) / (paddle.pi**0.5) + + if not parallel_mode and self.use_loc_mapping: + assert mapping is not None + # convert nlist from nall to nloc index + nlist = paddle.take_along_axis( + mapping, + nlist.reshape([nframes, -1]), + 1, + broadcast=False, + ).reshape(nlist.shape) + if self.use_dynamic_sel: + # get graph index + edge_index, angle_index = get_graph_index( + nlist, + nlist_mask, + a_nlist_mask, + nall, + use_loc_mapping=self.use_loc_mapping, + ) + # flat all the tensors + # n_edge x 1 + edge_input = edge_input[nlist_mask] + # n_edge x 3 + h2 = h2[nlist_mask] + # n_edge x 1 + sw = sw[nlist_mask] + # nb x nloc x a_nnei x a_nnei + a_nlist_mask = a_nlist_mask[:, :, :, None] & a_nlist_mask[:, :, None, :] + # n_angle x 1 + angle_input = angle_input[a_nlist_mask] + # n_angle x 1 + a_sw = (a_sw[:, :, :, None] * a_sw[:, :, None, :])[a_nlist_mask] + else: + # avoid jit assertion + edge_index = angle_index = paddle.zeros([1, 3], dtype=nlist.dtype) + # get edge and angle embedding + # nb x nloc x nnei x e_dim [OR] n_edge x e_dim + if not self.edge_init_use_dist: + edge_ebd = self.act(self.edge_embd(edge_input)) + else: + edge_ebd = self.edge_embd(edge_input) + # nf x nloc x a_nnei x a_nnei x a_dim [OR] n_angle x a_dim + angle_ebd = self.angle_embd(angle_input) - # set all padding positions to index of 0 - # if the a neighbor is real or not is indicated by nlist_mask - nlist[nlist == -1] = 0 # nb x nall x n_dim - if comm_dict is None: + if not parallel_mode: assert mapping is not None mapping = ( mapping.reshape([nframes, nall]) @@ -460,8 +535,8 @@ def forward( ) for idx, ll in enumerate(self.layers): # node_ebd: nb x nloc x n_dim - # node_ebd_ext: nb x nall x n_dim - if comm_dict is None: + # node_ebd_ext: nb x nall x n_dim [OR] nb x nloc x n_dim when not parallel_mode + if not parallel_mode: assert mapping is not None node_ebd_ext = paddle.take_along_axis( node_ebd, mapping, 1, broadcast=False @@ -479,12 +554,27 @@ def forward( a_nlist, a_nlist_mask, a_sw, + edge_index=edge_index, + angle_index=angle_index, ) # nb x nloc x 3 x e_dim - h2g2 = RepFlowLayer._cal_hg(edge_ebd, h2, nlist_mask, sw) + h2g2 = ( + RepFlowLayer._cal_hg(edge_ebd, h2, nlist_mask, sw) + if not self.use_dynamic_sel + else RepFlowLayer._cal_hg_dynamic( + edge_ebd, + h2, + sw, + owner=edge_index[:, 0], + num_owner=nframes * nloc, + nb=nframes, + nloc=nloc, + scale_factor=(self.nnei / self.sel_reduce_factor) ** (-0.5), + ) + ) # (nb x nloc) x e_dim x 3 - rot_mat = paddle.transpose(h2g2, (0, 1, 3, 2)) + rot_mat = paddle.transpose(h2g2, [0, 1, 3, 2]) return ( node_ebd, diff --git a/deepmd/pd/model/descriptor/repformers.py b/deepmd/pd/model/descriptor/repformers.py index 32f88dd1d3..bf97dfec5e 100644 --- a/deepmd/pd/model/descriptor/repformers.py +++ b/deepmd/pd/model/descriptor/repformers.py @@ -267,10 +267,10 @@ def __init__( wanted_shape = (self.ntypes, self.nnei, 4) mean = paddle.zeros(wanted_shape, dtype=env.GLOBAL_PD_FLOAT_PRECISION).to( - device=env.DEVICE + env.DEVICE ) stddev = paddle.ones(wanted_shape, dtype=env.GLOBAL_PD_FLOAT_PRECISION).to( - device=env.DEVICE + env.DEVICE ) self.register_buffer("mean", mean) self.register_buffer("stddev", stddev) @@ -503,11 +503,11 @@ def compute_input_stats( mean, stddev = env_mat_stat() if not self.set_davg_zero: paddle.assign( - paddle.to_tensor(mean, dtype=self.mean.dtype).to(device=env.DEVICE), + paddle.to_tensor(mean, dtype=self.mean.dtype).to(env.DEVICE), self.mean, ) # pylint: disable=no-explicit-dtype paddle.assign( - paddle.to_tensor(stddev, dtype=self.stddev.dtype).to(device=env.DEVICE), + paddle.to_tensor(stddev, dtype=self.stddev.dtype).to(env.DEVICE), self.stddev, ) # pylint: disable=no-explicit-dtype diff --git a/deepmd/pd/utils/env.py b/deepmd/pd/utils/env.py index cf5b1f835c..3f45910392 100644 --- a/deepmd/pd/utils/env.py +++ b/deepmd/pd/utils/env.py @@ -71,6 +71,7 @@ def to_bool(flag: int | bool | str) -> bool: CACHE_PER_SYS = 5 # keep at most so many sets per sys in memory ENERGY_BIAS_TRAINABLE = True +CUSTOM_OP_USE_JIT = False PRECISION_DICT = { "float16": paddle.float16, @@ -198,6 +199,7 @@ def enable_prim(enable: bool = True): __all__ = [ "CACHE_PER_SYS", "CINN", + "CUSTOM_OP_USE_JIT", "DEFAULT_PRECISION", "DEVICE", "ENERGY_BIAS_TRAINABLE", diff --git a/deepmd/pd/utils/preprocess.py b/deepmd/pd/utils/preprocess.py index 3e047c1b8b..3be42b522e 100644 --- a/deepmd/pd/utils/preprocess.py +++ b/deepmd/pd/utils/preprocess.py @@ -10,9 +10,20 @@ def compute_smooth_weight(distance, rmin: float, rmax: float): """Compute smooth weight for descriptor elements.""" if rmin >= rmax: raise ValueError("rmin should be less than rmax.") - min_mask = distance <= rmin - max_mask = distance >= rmax - mid_mask = paddle.logical_not(paddle.logical_or(min_mask, max_mask)) + distance = paddle.clip(distance, min=rmin, max=rmax) uu = (distance - rmin) / (rmax - rmin) - vv = uu * uu * uu * (-6 * uu * uu + 15 * uu - 10) + 1 - return vv * mid_mask.astype(vv.dtype) + min_mask.astype(vv.dtype) + uu2 = uu * uu + vv = uu2 * uu * (-6 * uu2 + 15 * uu - 10) + 1 + return vv + + +def compute_exp_sw(distance, rmin: float, rmax: float): + """Compute the exponential switch function for neighbor update.""" + if rmin >= rmax: + raise ValueError("rmin should be less than rmax.") + distance = paddle.clip(distance, min=0.0, max=rmax) + C = 20 + a = C / rmin + b = rmin + exp_sw = paddle.exp(-paddle.exp(a * (distance - b))) + return exp_sw diff --git a/deepmd/pd/utils/spin.py b/deepmd/pd/utils/spin.py index 934fb3762a..27bc355877 100644 --- a/deepmd/pd/utils/spin.py +++ b/deepmd/pd/utils/spin.py @@ -21,7 +21,6 @@ def concat_switch_virtual( extended_tensor_updated = paddle.zeros( out_shape, dtype=extended_tensor.dtype, - device=extended_tensor.place, ) extended_tensor_updated[:, :nloc] = extended_tensor[:, :nloc] extended_tensor_updated[:, nloc : nloc + nloc] = extended_tensor_virtual[:, :nloc] diff --git a/deepmd/pd/utils/utils.py b/deepmd/pd/utils/utils.py index a756491a8d..eeda778b37 100644 --- a/deepmd/pd/utils/utils.py +++ b/deepmd/pd/utils/utils.py @@ -20,6 +20,9 @@ ) from deepmd.dpmodel.common import PRECISION_DICT as NP_PRECISION_DICT +from deepmd.pd.utils import ( + env, +) from .env import ( DEVICE, @@ -32,15 +35,129 @@ ) +def silut_forward( + x: paddle.Tensor, threshold: float, slope: float, const_val: float +) -> paddle.Tensor: + sig = F.sigmoid(x) + silu = x * sig + tanh = paddle.tanh(slope * (x - threshold)) + const_val + return paddle.where(x >= threshold, tanh, silu) + + +def silut_backward( + x: paddle.Tensor, grad_output: paddle.Tensor, threshold: float, slope: float +) -> paddle.Tensor: + sig = F.sigmoid(x) + grad_silu = sig * (1 + x * (1 - sig)) + + tanh = paddle.tanh(slope * (x - threshold)) + grad_tanh = slope * (1 - tanh * tanh) + + grad = paddle.where(x >= threshold, grad_tanh, grad_silu) + return grad * grad_output + + +def silut_double_backward( + x: paddle.Tensor, + grad_grad_output: paddle.Tensor, + grad_output: paddle.Tensor, + threshold: float, + slope: float, +) -> tuple[paddle.Tensor, paddle.Tensor]: + # SiLU branch + sig = F.sigmoid(x) + + sig_prime = sig * (1 - sig) + grad_silu = sig + x * sig_prime + grad_grad_silu = sig_prime * (2 + x * (1 - 2 * sig)) + + # Tanh branch + tanh = paddle.tanh(slope * (x - threshold)) + tanh_square = tanh * tanh # .square is slow for jit.script! + grad_tanh = slope * (1 - tanh_square) + grad_grad_tanh = -2 * slope * tanh * grad_tanh + + grad = paddle.where(x >= threshold, grad_tanh, grad_silu) + grad_grad = paddle.where(x >= threshold, grad_grad_tanh, grad_grad_silu) + return grad_output * grad_grad * grad_grad_output, grad * grad_grad_output + + +class SiLUTScript(paddle.nn.Layer): + def __init__(self, threshold: float = 3.0): + super().__init__() + self.threshold = threshold + + # Precompute parameters for the tanh replacement + sigmoid_threshold = 1 / (1 + np.exp(-threshold)) + self.slope = float( + sigmoid_threshold + threshold * sigmoid_threshold * (1 - sigmoid_threshold) + ) + self.const_val = float(threshold * sigmoid_threshold) + self.get_script_code() + + def get_script_code(self): + silut_forward_script = paddle.jit.to_static(silut_forward, full_graph=True) + # silut_forward_script = (silut_forward) + silut_backward_script = paddle.jit.to_static(silut_backward, full_graph=True) + # silut_backward_script = (silut_backward) + silut_double_backward_script = paddle.jit.to_static( + silut_double_backward, full_graph=True + ) + # silut_double_backward_script = (silut_double_backward) + + class SiLUTFunction(paddle.autograd.PyLayer): + @staticmethod + def forward(ctx, x, threshold, slope, const_val): + ctx.save_for_backward(x) + ctx.threshold = threshold + ctx.slope = slope + ctx.const_val = const_val + return silut_forward_script(x, threshold, slope, const_val) + + @staticmethod + def backward(ctx, grad_output): + (x,) = ctx.saved_tensor() + threshold = ctx.threshold + slope = ctx.slope + + grad_input = SiLUTGradFunction.apply(x, grad_output, threshold, slope) + return grad_input + + class SiLUTGradFunction(paddle.autograd.PyLayer): + @staticmethod + def forward(ctx, x, grad_output, threshold, slope): + ctx.threshold = threshold + ctx.slope = slope + grad_input = silut_backward_script(x, grad_output, threshold, slope) + ctx.save_for_backward(x, grad_output) + return grad_input + + @staticmethod + def backward(ctx, grad_grad_output): + (x, grad_output) = ctx.saved_tensor() + threshold = ctx.threshold + slope = ctx.slope + + grad_input, grad_mul_grad_grad_output = silut_double_backward_script( + x, grad_grad_output, grad_output, threshold, slope + ) + return grad_input, grad_mul_grad_grad_output + + self.SiLUTFunction = SiLUTFunction + + def forward(self, x): + return self.SiLUTFunction.apply(x, self.threshold, self.slope, self.const_val) + + class SiLUT(paddle.nn.Layer): def __init__(self, threshold=3.0): super().__init__() def sigmoid(x): - return paddle.nn.functional.sigmoid(x) + return F.sigmoid(x) def silu(x): - return paddle.nn.functional.silu(x) + return F.silu(x) def silu_grad(x): sig = sigmoid(x) @@ -76,7 +193,12 @@ def __init__(self, activation: str | None): threshold = ( float(self.activation.split(":")[-1]) if ":" in self.activation else 3.0 ) - self.silut = SiLUT(threshold=threshold) + if env.CUSTOM_OP_USE_JIT: + # for efficient training but can not be jit + self.silut = SiLUTScript(threshold=threshold) + # self.silut = paddle.nn.Identity() + else: + self.silut = SiLUT(threshold=threshold) else: self.silut = None From 7e07126e7c41f92dc25e9758f58aa90791c09375 Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Wed, 11 Jun 2025 10:32:12 +0800 Subject: [PATCH 03/13] fix typo --- .pre-commit-config.yaml | 52 ++++++++++----------- deepmd/pd/model/descriptor/repflow_layer.py | 2 +- deepmd/pd/utils/utils.py | 4 -- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 77dab6f3aa..cee3d7f2ce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -65,13 +65,13 @@ repos: - id: clang-format exclude: ^(source/3rdparty|source/lib/src/gpu/cudart/.+\.inc|.+\.ipynb$|.+\.json$) # markdown, yaml, CSS, javascript - # - repo: https://github.com/pre-commit/mirrors-prettier - # rev: v4.0.0-alpha.8 - # hooks: - # - id: prettier - # types_or: [markdown, yaml, css] - # # workflow files cannot be modified by pre-commit.ci - # exclude: ^(source/3rdparty|\.github/workflows|\.clang-format) + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v4.0.0-alpha.8 + hooks: + - id: prettier + types_or: [markdown, yaml, css] + # workflow files cannot be modified by pre-commit.ci + exclude: ^(source/3rdparty|\.github/workflows|\.clang-format) # Shell - repo: https://github.com/scop/pre-commit-shfmt rev: v3.11.0-1 @@ -83,25 +83,25 @@ repos: hooks: - id: cmake-format #- id: cmake-lint - # - repo: https://github.com/njzjz/mirrors-bibtex-tidy - # rev: v1.13.0 - # hooks: - # - id: bibtex-tidy - # args: - # - --curly - # - --numeric - # - --align=13 - # - --blank-lines - # # disable sort: the order of keys and fields has explict meanings - # #- --sort=key - # - --duplicates=key,doi,citation,abstract - # - --merge=combine - # #- --sort-fields - # #- --strip-comments - # - --trailing-commas - # - --encode-urls - # - --remove-empty-fields - # - --wrap=80 + - repo: https://github.com/njzjz/mirrors-bibtex-tidy + rev: v1.13.0 + hooks: + - id: bibtex-tidy + args: + - --curly + - --numeric + - --align=13 + - --blank-lines + # disable sort: the order of keys and fields has explict meanings + #- --sort=key + - --duplicates=key,doi,citation,abstract + - --merge=combine + #- --sort-fields + #- --strip-comments + - --trailing-commas + - --encode-urls + - --remove-empty-fields + - --wrap=80 # license header - repo: https://github.com/Lucas-C/pre-commit-hooks rev: v1.5.5 diff --git a/deepmd/pd/model/descriptor/repflow_layer.py b/deepmd/pd/model/descriptor/repflow_layer.py index 78cfa7a56d..73748943f8 100644 --- a/deepmd/pd/model/descriptor/repflow_layer.py +++ b/deepmd/pd/model/descriptor/repflow_layer.py @@ -849,7 +849,7 @@ def forward( edge_info = paddle.concat( [ paddle.index_select( - node_ebd.reshape(-1, self.n_dim), + node_ebd.reshape([-1, self.n_dim]), n2e_index, 0, ), diff --git a/deepmd/pd/utils/utils.py b/deepmd/pd/utils/utils.py index eeda778b37..175ac5019b 100644 --- a/deepmd/pd/utils/utils.py +++ b/deepmd/pd/utils/utils.py @@ -97,13 +97,10 @@ def __init__(self, threshold: float = 3.0): def get_script_code(self): silut_forward_script = paddle.jit.to_static(silut_forward, full_graph=True) - # silut_forward_script = (silut_forward) silut_backward_script = paddle.jit.to_static(silut_backward, full_graph=True) - # silut_backward_script = (silut_backward) silut_double_backward_script = paddle.jit.to_static( silut_double_backward, full_graph=True ) - # silut_double_backward_script = (silut_double_backward) class SiLUTFunction(paddle.autograd.PyLayer): @staticmethod @@ -196,7 +193,6 @@ def __init__(self, activation: str | None): if env.CUSTOM_OP_USE_JIT: # for efficient training but can not be jit self.silut = SiLUTScript(threshold=threshold) - # self.silut = paddle.nn.Identity() else: self.silut = SiLUT(threshold=threshold) else: From 5103f5ded158e4452e087b2b593cc88a5acdc6c9 Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Wed, 11 Jun 2025 10:39:22 +0800 Subject: [PATCH 04/13] upload missing file --- deepmd/pd/model/descriptor/repflow_layer.py | 2 +- deepmd/pd/model/network/utils.py | 135 ++++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 deepmd/pd/model/network/utils.py diff --git a/deepmd/pd/model/descriptor/repflow_layer.py b/deepmd/pd/model/descriptor/repflow_layer.py index 73748943f8..40e7a35e6e 100644 --- a/deepmd/pd/model/descriptor/repflow_layer.py +++ b/deepmd/pd/model/descriptor/repflow_layer.py @@ -1010,7 +1010,7 @@ def forward( # nb x nloc x a_nnei x a_nnei x (a + n_dim + e_dim*2) or (a + a/c + a/c) # [OR] # n_angle x (a + n_dim + e_dim*2) or (a + a/c + a/c) - angle_info = paddle.cat(angle_info_list, axis=1) + angle_info = paddle.concat(angle_info_list, axis=1) else: angle_info = None diff --git a/deepmd/pd/model/network/utils.py b/deepmd/pd/model/network/utils.py new file mode 100644 index 0000000000..f09686a264 --- /dev/null +++ b/deepmd/pd/model/network/utils.py @@ -0,0 +1,135 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +from typing import ( + Optional, +) + +import paddle + + +def aggregate( + data: paddle.Tensor, + owners: paddle.Tensor, + average: bool = True, + num_owner: Optional[int] = None, +) -> paddle.Tensor: + """ + Aggregate rows in data by specifying the owners. + + Parameters + ---------- + data : data tensor to aggregate [n_row, feature_dim] + owners : specify the owner of each row [n_row, 1] + average : if True, average the rows, if False, sum the rows. + Default = True + num_owner : the number of owners, this is needed if the + max idx of owner is not presented in owners tensor + Default = None + + Returns + ------- + output: [num_owner, feature_dim] + """ + bin_count = paddle.bincount(owners) + bin_count = bin_count.where(bin_count != 0, paddle.ones_like(bin_count)) + + if (num_owner is not None) and (bin_count.shape[0] != num_owner): + difference = num_owner - bin_count.shape[0] + bin_count = paddle.concat([bin_count, paddle.ones_like(difference)]) + + # make sure this operation is done on the same device of data and owners + output = paddle.zeros([bin_count.shape[0], data.shape[1]]) + output = output.index_add_(owners, 0, data) + if average: + output = (output.T / bin_count).T + return output + + +def get_graph_index( + nlist: paddle.Tensor, + nlist_mask: paddle.Tensor, + a_nlist_mask: paddle.Tensor, + nall: int, +): + """ + Get the index mapping for edge graph and angle graph, ready in `aggregate` or `index_select`. + + Parameters + ---------- + nlist : nf x nloc x nnei + Neighbor list. (padded neis are set to 0) + nlist_mask : nf x nloc x nnei + Masks of the neighbor list. real nei 1 otherwise 0 + a_nlist_mask : nf x nloc x a_nnei + Masks of the neighbor list for angle. real nei 1 otherwise 0 + nall + The number of extended atoms. + + Returns + ------- + edge_index : n_edge x 2 + n2e_index : n_edge + Broadcast indices from node(i) to edge(ij), or reduction indices from edge(ij) to node(i). + n_ext2e_index : n_edge + Broadcast indices from extended node(j) to edge(ij). + angle_index : n_angle x 3 + n2a_index : n_angle + Broadcast indices from extended node(j) to angle(ijk). + eij2a_index : n_angle + Broadcast indices from extended edge(ij) to angle(ijk), or reduction indices from angle(ijk) to edge(ij). + eik2a_index : n_angle + Broadcast indices from extended edge(ik) to angle(ijk). + """ + nf, nloc, nnei = nlist.shape + _, _, a_nnei = a_nlist_mask.shape + # nf x nloc x nnei x nnei + # nlist_mask_3d = nlist_mask[:, :, :, None] & nlist_mask[:, :, None, :] + a_nlist_mask_3d = a_nlist_mask[:, :, :, None] & a_nlist_mask[:, :, None, :] + n_edge = nlist_mask.sum().item() + # n_angle = a_nlist_mask_3d.sum().item() + + # following: get n2e_index, n_ext2e_index, n2a_index, eij2a_index, eik2a_index + + # 1. atom graph + # node(i) to edge(ij) index_select; edge(ij) to node aggregate + nlist_loc_index = paddle.arange(0, nf * nloc, dtype=nlist.dtype).to(nlist.place) + # nf x nloc x nnei + n2e_index = nlist_loc_index.reshape([nf, nloc, 1]).expand([-1, -1, nnei]) + # n_edge + n2e_index = n2e_index[nlist_mask] # graph node index, atom_graph[:, 0] + + # node_ext(j) to edge(ij) index_select + frame_shift = paddle.arange(0, nf, dtype=nlist.dtype) * nall + shifted_nlist = nlist + frame_shift[:, None, None] + # n_edge + n_ext2e_index = shifted_nlist[nlist_mask] # graph neighbor index, atom_graph[:, 1] + + # 2. edge graph + # node(i) to angle(ijk) index_select + n2a_index = nlist_loc_index.reshape([nf, nloc, 1, 1]).expand( + [-1, -1, a_nnei, a_nnei] + ) + # n_angle + n2a_index = n2a_index[a_nlist_mask_3d] + + # edge(ij) to angle(ijk) index_select; angle(ijk) to edge(ij) aggregate + edge_id = paddle.arange(0, n_edge, dtype=nlist.dtype) + # nf x nloc x nnei + edge_index = paddle.zeros([nf, nloc, nnei], dtype=nlist.dtype) + edge_index[nlist_mask] = edge_id + # only cut a_nnei neighbors, to avoid nnei x nnei + edge_index = edge_index[:, :, :a_nnei] + edge_index_ij = edge_index.unsqueeze(-1).expand([-1, -1, -1, a_nnei]) + # n_angle + eij2a_index = edge_index_ij[a_nlist_mask_3d] + + # edge(ik) to angle(ijk) index_select + edge_index_ik = edge_index.unsqueeze(-2).expand([-1, -1, a_nnei, -1]) + # n_angle + eik2a_index = edge_index_ik[a_nlist_mask_3d] + + return paddle.concat( + [n2e_index.unsqueeze(-1), n_ext2e_index.unsqueeze(-1)], axis=-1 + ), paddle.concat( + [n2a_index.unsqueeze(-1), eij2a_index.unsqueeze(-1), eik2a_index.unsqueeze(-1)], + axis=-1, + ) From 90bd05bba97c1b6d1fc221175a0dbca48a143f18 Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Wed, 11 Jun 2025 13:29:53 +0800 Subject: [PATCH 05/13] fix --- deepmd/pd/model/descriptor/repflow_layer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deepmd/pd/model/descriptor/repflow_layer.py b/deepmd/pd/model/descriptor/repflow_layer.py index 40e7a35e6e..7de88d8bd9 100644 --- a/deepmd/pd/model/descriptor/repflow_layer.py +++ b/deepmd/pd/model/descriptor/repflow_layer.py @@ -1002,7 +1002,7 @@ def forward( ) # nb x nloc x a_nnei x a_nnei x (e_dim + e_dim) [OR] n_angle x (e_dim + e_dim) edge_for_angle_info = paddle.concat( - [edge_for_angle_k, edge_for_angle_j], axis=1 + [edge_for_angle_k, edge_for_angle_j], axis=-1 ) angle_info_list = [angle_ebd] angle_info_list.append(node_for_angle_info) @@ -1010,7 +1010,7 @@ def forward( # nb x nloc x a_nnei x a_nnei x (a + n_dim + e_dim*2) or (a + a/c + a/c) # [OR] # n_angle x (a + n_dim + e_dim*2) or (a + a/c + a/c) - angle_info = paddle.concat(angle_info_list, axis=1) + angle_info = paddle.concat(angle_info_list, axis=-1) else: angle_info = None From d264faef4fccc8d20d86540844ab8d251558b6ed Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Fri, 13 Jun 2025 11:18:24 +0800 Subject: [PATCH 06/13] Update deepmd/pd/train/training.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: HydrogenSulfate <490868991@qq.com> --- deepmd/pd/train/training.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/deepmd/pd/train/training.py b/deepmd/pd/train/training.py index 07cd738a1c..984535b5d7 100644 --- a/deepmd/pd/train/training.py +++ b/deepmd/pd/train/training.py @@ -607,10 +607,13 @@ def warm_up_linear(step, warmup_steps): ) backend = "CINN" if CINN else None - # NOTE: This is a trick to decide the right input_spec for wrapper.forward - _, label_dict, _ = self.get_data(is_train=True, task_key="Default") - label_dict_spec = { + # Use appropriate task_key for multi-task scenarios + sample_task_key = self.model_keys[0] if self.multi_task else "Default" + _, label_dict, _ = self.get_data(is_train=True, task_key=sample_task_key) + + # Define specification templates + spec_templates = { "find_box": np.float32(1.0), "find_coord": np.float32(1.0), "find_numb_copy": np.float32(0.0), @@ -623,19 +626,8 @@ def warm_up_linear(step, warmup_steps): "virial": static.InputSpec([1, 9], "float64", name="virial"), "natoms": static.InputSpec([1, -1], "int32", name="natoms"), } - if "virial" not in label_dict: - label_dict_spec.pop("virial") - if "find_virial" not in label_dict: - label_dict_spec.pop("find_virial") - if "energy" not in label_dict: - label_dict_spec.pop("energy") - if "find_energy" not in label_dict: - label_dict_spec.pop("find_energy") - if "force" not in label_dict: - label_dict_spec.pop("force") - if "find_force" not in label_dict: - label_dict_spec.pop("find_force") - + # Build spec only for keys present in sample data + label_dict_spec = {k: spec_templates[k] for k in label_dict.keys() if k in spec_templates} self.wrapper.forward = jit.to_static( backend=backend, input_spec=[ From 6528a85b31bf178fb158845800ec8abc0b39bb88 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 03:20:01 +0000 Subject: [PATCH 07/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- deepmd/pd/train/training.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deepmd/pd/train/training.py b/deepmd/pd/train/training.py index 984535b5d7..ca9e28726c 100644 --- a/deepmd/pd/train/training.py +++ b/deepmd/pd/train/training.py @@ -627,7 +627,9 @@ def warm_up_linear(step, warmup_steps): "natoms": static.InputSpec([1, -1], "int32", name="natoms"), } # Build spec only for keys present in sample data - label_dict_spec = {k: spec_templates[k] for k in label_dict.keys() if k in spec_templates} + label_dict_spec = { + k: spec_templates[k] for k in label_dict.keys() if k in spec_templates + } self.wrapper.forward = jit.to_static( backend=backend, input_spec=[ From 3a6438e973c1de5c94e937cf839679005ab3090e Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Fri, 13 Jun 2025 11:34:37 +0800 Subject: [PATCH 08/13] fix --- deepmd/pd/train/training.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/deepmd/pd/train/training.py b/deepmd/pd/train/training.py index ca9e28726c..bb0a8987b8 100644 --- a/deepmd/pd/train/training.py +++ b/deepmd/pd/train/training.py @@ -608,9 +608,7 @@ def warm_up_linear(step, warmup_steps): backend = "CINN" if CINN else None # NOTE: This is a trick to decide the right input_spec for wrapper.forward - # Use appropriate task_key for multi-task scenarios - sample_task_key = self.model_keys[0] if self.multi_task else "Default" - _, label_dict, _ = self.get_data(is_train=True, task_key=sample_task_key) + _, label_dict, _ = self.get_data(is_train=True) # Define specification templates spec_templates = { From d236285db5e754de871d10b640a590ebb1f6a68d Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Thu, 19 Jun 2025 13:40:24 +0800 Subject: [PATCH 09/13] refine code --- .pre-commit-config.yaml | 52 ++++++++++++++++++------------------- deepmd/pd/train/training.py | 31 +++++++++++++++------- deepmd/pd/utils/env.py | 3 ++- 3 files changed, 50 insertions(+), 36 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cee3d7f2ce..77dab6f3aa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -65,13 +65,13 @@ repos: - id: clang-format exclude: ^(source/3rdparty|source/lib/src/gpu/cudart/.+\.inc|.+\.ipynb$|.+\.json$) # markdown, yaml, CSS, javascript - - repo: https://github.com/pre-commit/mirrors-prettier - rev: v4.0.0-alpha.8 - hooks: - - id: prettier - types_or: [markdown, yaml, css] - # workflow files cannot be modified by pre-commit.ci - exclude: ^(source/3rdparty|\.github/workflows|\.clang-format) + # - repo: https://github.com/pre-commit/mirrors-prettier + # rev: v4.0.0-alpha.8 + # hooks: + # - id: prettier + # types_or: [markdown, yaml, css] + # # workflow files cannot be modified by pre-commit.ci + # exclude: ^(source/3rdparty|\.github/workflows|\.clang-format) # Shell - repo: https://github.com/scop/pre-commit-shfmt rev: v3.11.0-1 @@ -83,25 +83,25 @@ repos: hooks: - id: cmake-format #- id: cmake-lint - - repo: https://github.com/njzjz/mirrors-bibtex-tidy - rev: v1.13.0 - hooks: - - id: bibtex-tidy - args: - - --curly - - --numeric - - --align=13 - - --blank-lines - # disable sort: the order of keys and fields has explict meanings - #- --sort=key - - --duplicates=key,doi,citation,abstract - - --merge=combine - #- --sort-fields - #- --strip-comments - - --trailing-commas - - --encode-urls - - --remove-empty-fields - - --wrap=80 + # - repo: https://github.com/njzjz/mirrors-bibtex-tidy + # rev: v1.13.0 + # hooks: + # - id: bibtex-tidy + # args: + # - --curly + # - --numeric + # - --align=13 + # - --blank-lines + # # disable sort: the order of keys and fields has explict meanings + # #- --sort=key + # - --duplicates=key,doi,citation,abstract + # - --merge=combine + # #- --sort-fields + # #- --strip-comments + # - --trailing-commas + # - --encode-urls + # - --remove-empty-fields + # - --wrap=80 # license header - repo: https://github.com/Lucas-C/pre-commit-hooks rev: v1.5.5 diff --git a/deepmd/pd/train/training.py b/deepmd/pd/train/training.py index bb0a8987b8..5cd60716c0 100644 --- a/deepmd/pd/train/training.py +++ b/deepmd/pd/train/training.py @@ -1,4 +1,5 @@ # SPDX-License-Identifier: LGPL-3.0-or-later +import contextlib import functools import logging import time @@ -18,6 +19,7 @@ from paddle.distributed import ( fleet, ) +from paddle.distributed.fleet.utils import hybrid_parallel_util as hpu from paddle.framework import ( core, ) @@ -741,16 +743,27 @@ def step(_step_id, task_key="Default") -> None: pref_lr = _lr.start_lr else: pref_lr = cur_lr - with nvprof_context(enable_profiling, "Forward pass"): - model_pred, loss, more_loss = self.wrapper( - **input_dict, - cur_lr=paddle.full([], pref_lr, DEFAULT_PRECISION), - label=label_dict, - task_key=task_key, - ) + sync_context = ( + self.wrapper.no_sync + if self.world_size > 1 + else contextlib.nullcontext + ) + with sync_context(): + with nvprof_context(enable_profiling, "Forward pass"): + model_pred, loss, more_loss = self.wrapper( + **input_dict, + cur_lr=paddle.full([], pref_lr, DEFAULT_PRECISION), + label=label_dict, + task_key=task_key, + ) + + with nvprof_context(enable_profiling, "Backward pass"): + loss.backward() - with nvprof_context(enable_profiling, "Backward pass"): - loss.backward() + if self.world_size > 1: + # fuse + allreduce manually before optimization if use DDP + no_sync + # details in https://github.com/PaddlePaddle/Paddle/issues/48898#issuecomment-1343838622 + hpu.fused_allreduce_gradients(list(self.wrapper.parameters()), None) if self.gradient_max_norm > 0.0: with nvprof_context(enable_profiling, "Gradient clip"): diff --git a/deepmd/pd/utils/env.py b/deepmd/pd/utils/env.py index 3f45910392..4c34c551b4 100644 --- a/deepmd/pd/utils/env.py +++ b/deepmd/pd/utils/env.py @@ -27,7 +27,8 @@ ncpus = os.cpu_count() NUM_WORKERS = int(os.environ.get("NUM_WORKERS", min(0, ncpus))) # Make sure DDP uses correct device if applicable -LOCAL_RANK = paddle.distributed.get_rank() +LOCAL_RANK = os.environ.get("PADDLE_LOCAL_RANK") +LOCAL_RANK = int(0 if LOCAL_RANK is None else LOCAL_RANK) if os.environ.get("DEVICE") == "cpu" or paddle.device.cuda.device_count() <= 0: DEVICE = "cpu" From 7ce9af1eb18c2c5ae450e78bfc0169d6332ed612 Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Thu, 19 Jun 2025 14:04:17 +0800 Subject: [PATCH 10/13] update parallel test code --- examples/water/dpa3/input_torch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/water/dpa3/input_torch.json b/examples/water/dpa3/input_torch.json index 90e81b5403..e84f11821c 100644 --- a/examples/water/dpa3/input_torch.json +++ b/examples/water/dpa3/input_torch.json @@ -85,7 +85,7 @@ "batch_size": 1, "_comment": "that's all" }, - "numb_steps": 1000000, + "numb_steps": 2000, "warmup_steps": 0, "gradient_max_norm": 5.0, "seed": 10, From 78fe1b8ce957b9786ea0150f47460822cacd5c42 Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Fri, 8 Aug 2025 17:52:02 +0800 Subject: [PATCH 11/13] update code --- examples/water/dpa3/run.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 examples/water/dpa3/run.sh diff --git a/examples/water/dpa3/run.sh b/examples/water/dpa3/run.sh new file mode 100644 index 0000000000..db9d895ac6 --- /dev/null +++ b/examples/water/dpa3/run.sh @@ -0,0 +1,17 @@ +# unset PADDLE_ELASTIC_JOB_ID +# unset PADDLE_TRAINER_ENDPOINTS +# unset DISTRIBUTED_TRAINER_ENDPOINTS +# unset FLAGS_START_PORT +# unset PADDLE_ELASTIC_TIMEOUT +# export NNODES=1 +# export PADDLE_TRAINERS_NUM=1 +unset CUDA_DEVICE_MAX_CONNECTIONS + +HDFS_USE_FILE_LOCKING=0 python -m paddle.distributed.launch --gpus="0,1,2,3,4,5,6,7" --log_dir "logs" dp --pd train input_torch.json -l dp_train.log + +# NUM_WORKERS=0 HDFS_USE_FILE_LOCKING=0 python -m paddle.distributed.launch + +# python -m paddle.distributed.launch \ +# --gpus=0,1,2,3 \ +# --ips=10.67.200.17,10.67.200.11,10.67.200.13,10.67.200.15 \ +# dp --pd train input_torch.json -l dp_train.log \ No newline at end of file From 35783bbeddff4470ec23c68b9f8afcb91419aade Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Wed, 13 Aug 2025 20:32:11 +0800 Subject: [PATCH 12/13] update auto ddp code --- deepmd/pd/model/model/make_model.py | 56 +++++++++++++++++++++++------ deepmd/pd/train/training.py | 56 ++++++++++++++++++++--------- 2 files changed, 85 insertions(+), 27 deletions(-) diff --git a/deepmd/pd/model/model/make_model.py b/deepmd/pd/model/model/make_model.py index acb237b5ac..6474157865 100644 --- a/deepmd/pd/model/model/make_model.py +++ b/deepmd/pd/model/model/make_model.py @@ -37,6 +37,9 @@ from deepmd.utils.path import ( DPPath, ) +import paddle.distributed as dist +from paddle.distributed import fleet +import functools def make_model(T_AtomicModel: type[BaseAtomicModel]): @@ -163,29 +166,60 @@ def forward_common( coord, box=box, fparam=fparam, aparam=aparam ) del coord, box, fparam, aparam + # ( + # extended_coord, + # extended_atype, + # mapping, + # nlist, + # ) = extend_input_and_build_neighbor_list( + # cc, + # atype, + # self.get_rcut(), + # self.get_sel(), + # # types will be distinguished in the lower interface, + # # so it doesn't need to be distinguished here + # mixed_types=True, + # box=bb, + # ) + wrapped_func_1 = dist.local_map( + func=lambda a,b,c: extend_input_and_build_neighbor_list(a,b,self.get_rcut(), self.get_sel(), True, c), + in_placements=[ele.placements for ele in [cc, atype, bb]], + out_placements=[[dist.Shard(0)] for _ in range(4)], + process_mesh=fleet.auto.get_mesh() + ) + ( extended_coord, extended_atype, mapping, nlist, - ) = extend_input_and_build_neighbor_list( + ) = wrapped_func_1( cc, atype, - self.get_rcut(), - self.get_sel(), - # types will be distinguished in the lower interface, - # so it doesn't need to be distinguished here - mixed_types=True, - box=bb, + bb, + ) + # model_predict_lower = self.forward_common_lower( + # extended_coord, + # extended_atype, + # nlist, + # mapping, + # do_atomic_virial=do_atomic_virial, + # fparam=fp, + # aparam=ap, + # ) + + wrapped_func_2 = dist.local_map( + func=functools.partial(self.forward_common_lower, do_atomic_virial=do_atomic_virial, fparam=fp, aparam=ap), + in_placements=[ele.placements for ele in [extended_coord, extended_atype, nlist, mapping]], + out_placements=[[dist.Shard(0)] for _ in range(6)], + process_mesh=fleet.auto.get_mesh(), + reshard_inputs=True ) - model_predict_lower = self.forward_common_lower( + model_predict_lower = wrapped_func_2( extended_coord, extended_atype, nlist, mapping, - do_atomic_virial=do_atomic_virial, - fparam=fp, - aparam=ap, ) model_predict = communicate_extended_output( model_predict_lower, diff --git a/deepmd/pd/train/training.py b/deepmd/pd/train/training.py index 5cd60716c0..782070a57e 100644 --- a/deepmd/pd/train/training.py +++ b/deepmd/pd/train/training.py @@ -26,7 +26,9 @@ from paddle.io import ( DataLoader, ) - +import paddle.distributed as dist +from paddle.distributed import fleet +import functools from deepmd.common import ( symlink_prefix_files, ) @@ -101,6 +103,11 @@ def __init__( Args: - config: The Dict-like configuration with training options. """ + from paddle.distributed import fleet + mesh_dims = [("dp", 32)] + fleet.auto.create_mesh(mesh_dims) + fleet.init(is_collective=True) + enable_prim(True) if init_model is not None: resume_model = init_model @@ -748,22 +755,39 @@ def step(_step_id, task_key="Default") -> None: if self.world_size > 1 else contextlib.nullcontext ) - with sync_context(): - with nvprof_context(enable_profiling, "Forward pass"): - model_pred, loss, more_loss = self.wrapper( - **input_dict, - cur_lr=paddle.full([], pref_lr, DEFAULT_PRECISION), - label=label_dict, - task_key=task_key, - ) - - with nvprof_context(enable_profiling, "Backward pass"): - loss.backward() + + # with sync_context(): + # with nvprof_context(enable_profiling, "Forward pass"): + # model_pred, loss, more_loss = self.wrapper( + # **input_dict, + # cur_lr=paddle.full([], pref_lr, DEFAULT_PRECISION), + # label=label_dict, + # task_key=task_key, + # ) + + # with nvprof_context(enable_profiling, "Backward pass"): + # loss.backward() + + # if self.world_size > 1: + # # fuse + allreduce manually before optimization if use DDP + no_sync + # # details in https://github.com/PaddlePaddle/Paddle/issues/48898#issuecomment-1343838622 + # hpu.fused_allreduce_gradients(list(self.wrapper.parameters()), None) + + with nvprof_context(enable_profiling, "Forward pass"): + for __key in ('coord', 'atype', 'box'): + input_dict[__key] = dist.shard_tensor(input_dict[__key], mesh=dist.get_mesh(), placements=[dist.Shard(0)]) + for __key, _ in label_dict.items(): + if isinstance(label_dict[__key], paddle.Tensor): + label_dict[__key] = dist.shard_tensor(label_dict[__key], mesh=dist.get_mesh(), placements=[dist.Shard(0)]) + model_pred, loss, more_loss = self.wrapper( + **input_dict, + cur_lr=paddle.full([], pref_lr, DEFAULT_PRECISION), + label=label_dict, + task_key=task_key, + ) - if self.world_size > 1: - # fuse + allreduce manually before optimization if use DDP + no_sync - # details in https://github.com/PaddlePaddle/Paddle/issues/48898#issuecomment-1343838622 - hpu.fused_allreduce_gradients(list(self.wrapper.parameters()), None) + with nvprof_context(enable_profiling, "Backward pass"): + loss.backward() if self.gradient_max_norm > 0.0: with nvprof_context(enable_profiling, "Gradient clip"): From e79ab47932d1702ae1b21c1e58aae487ed06e493 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 25 Aug 2025 15:14:59 +0800 Subject: [PATCH 13/13] run auto-parallel --- deepmd/pd/loss/ener.py | 11 +- deepmd/pd/train/training.py | 230 +++++++++++++------------ deepmd/pd/utils/dataloader.py | 42 ++--- examples/water/dpa3/input_atype.pd | Bin 0 -> 24773 bytes examples/water/dpa3/input_box.pd | Bin 0 -> 2501 bytes examples/water/dpa3/input_coord.pd | Bin 0 -> 147664 bytes examples/water/dpa3/input_torch.json | 4 +- examples/water/dpa3/label_energy.pd | Bin 0 -> 453 bytes examples/water/dpa3/label_force.pd | Bin 0 -> 147664 bytes examples/water/dpa3/label_natoms.pd | Bin 0 -> 709 bytes examples/water/dpa3/label_numb_copy.pd | Bin 0 -> 453 bytes examples/water/dpa3/label_virial.pd | Bin 0 -> 2501 bytes examples/water/dpa3/run.sh | 10 +- 13 files changed, 157 insertions(+), 140 deletions(-) create mode 100644 examples/water/dpa3/input_atype.pd create mode 100644 examples/water/dpa3/input_box.pd create mode 100644 examples/water/dpa3/input_coord.pd create mode 100644 examples/water/dpa3/label_energy.pd create mode 100644 examples/water/dpa3/label_force.pd create mode 100644 examples/water/dpa3/label_natoms.pd create mode 100644 examples/water/dpa3/label_numb_copy.pd create mode 100644 examples/water/dpa3/label_virial.pd diff --git a/deepmd/pd/loss/ener.py b/deepmd/pd/loss/ener.py index 09ec5ff49e..83f6949c52 100644 --- a/deepmd/pd/loss/ener.py +++ b/deepmd/pd/loss/ener.py @@ -21,6 +21,7 @@ from deepmd.utils.version import ( check_version_compatibility, ) +import paddle.distributed as dist def custom_huber_loss(predictions, targets, delta=1.0): @@ -205,7 +206,11 @@ def forward(self, input_dict, model, label, natoms, learning_rate, mae=False): find_energy = label.get("find_energy", 0.0) pref_e = pref_e * find_energy if not self.use_l1_all: - l2_ener_loss = paddle.mean(paddle.square(energy_pred - energy_label)) + + tmp = energy_pred - energy_label + logit = dist.reshard(tmp, tmp.process_mesh, [dist.Replicate()]) + + l2_ener_loss = paddle.mean(paddle.square(logit)) if not self.inference: more_loss["l2_ener_loss"] = self.display_if_exist( l2_ener_loss.detach(), find_energy @@ -258,7 +263,8 @@ def forward(self, input_dict, model, label, natoms, learning_rate, mae=False): force_pred = model_pred["force"] force_label = label["force"] diff_f = (force_label - force_pred).reshape([-1]) - + diff_f = dist.reshard(diff_f, diff_f.process_mesh, [dist.Replicate()]) + if self.relative_f is not None: force_label_3 = force_label.reshape([-1, 3]) norm_f = force_label_3.norm(axis=1, keepdim=True) + self.relative_f @@ -354,6 +360,7 @@ def forward(self, input_dict, model, label, natoms, learning_rate, mae=False): find_virial = label.get("find_virial", 0.0) pref_v = pref_v * find_virial diff_v = label["virial"] - model_pred["virial"].reshape([-1, 9]) + diff_v = dist.reshard(diff_v, diff_v.process_mesh, [dist.Replicate()]) l2_virial_loss = paddle.mean(paddle.square(diff_v)) if not self.inference: more_loss["l2_virial_loss"] = self.display_if_exist( diff --git a/deepmd/pd/train/training.py b/deepmd/pd/train/training.py index 782070a57e..da5ab36142 100644 --- a/deepmd/pd/train/training.py +++ b/deepmd/pd/train/training.py @@ -164,17 +164,14 @@ def get_opt_param(params): def get_data_loader(_training_data, _validation_data, _training_params): def get_dataloader_and_buffer(_data, _params): - _sampler = get_sampler_from_params(_data, _params) - if _sampler is None: - log.warning( - "Sampler not specified!" - ) # None sampler will lead to a premature stop iteration. Replacement should be True in attribute of the sampler to produce expected number of items in one iteration. + # _sampler = get_sampler_from_params(_data, _params) + # if _sampler is None: + # log.warning( + # "Sampler not specified!" + # ) # None sampler will lead to a premature stop iteration. Replacement should be True in attribute of the sampler to produce expected number of items in one iteration. _dataloader = DataLoader( _data, - batch_sampler=paddle.io.BatchSampler( - sampler=_sampler, - drop_last=False, - ), + batch_size=1, num_workers=NUM_WORKERS if dist.is_available() else 0, # setting to 0 diverges the behavior of its iterator; should be >=1 @@ -325,17 +322,18 @@ def get_lr(lr_params): self.validation_data, self.valid_numb_batch, ) = get_data_loader(training_data, validation_data, training_params) - training_data.print_summary( - "training", - to_numpy_array(self.training_dataloader.batch_sampler.sampler.weights), - ) - if validation_data is not None: - validation_data.print_summary( - "validation", - to_numpy_array( - self.validation_dataloader.batch_sampler.sampler.weights - ), - ) + # no sampler, do not need print! + # training_data.print_summary( + # "training", + # to_numpy_array(self.training_dataloader.batch_sampler.sampler.weights), + # ) + # if validation_data is not None: + # validation_data.print_summary( + # "validation", + # to_numpy_array( + # self.validation_dataloader.batch_sampler.sampler.weights + # ), + # ) else: ( self.training_dataloader, @@ -370,27 +368,27 @@ def get_lr(lr_params): validation_data[model_key], training_params["data_dict"][model_key], ) - - training_data[model_key].print_summary( - f"training in {model_key}", - to_numpy_array( - self.training_dataloader[ - model_key - ].batch_sampler.sampler.weights - ), - ) - if ( - validation_data is not None - and validation_data[model_key] is not None - ): - validation_data[model_key].print_summary( - f"validation in {model_key}", - to_numpy_array( - self.validation_dataloader[ - model_key - ].batch_sampler.sampler.weights - ), - ) + # no sampler, do not need print! + # training_data[model_key].print_summary( + # f"training in {model_key}", + # to_numpy_array( + # self.training_dataloader[ + # model_key + # ].batch_sampler.sampler.weights + # ), + # ) + # if ( + # validation_data is not None + # and validation_data[model_key] is not None + # ): + # validation_data[model_key].print_summary( + # f"validation in {model_key}", + # to_numpy_array( + # self.validation_dataloader[ + # model_key + # ].batch_sampler.sampler.weights + # ), + # ) # Learning rate self.warmup_steps = training_params.get("warmup_steps", 0) @@ -706,7 +704,7 @@ def run(self) -> None: fout1 = open(record_file, mode="w", buffering=1) log.info("Start to train %d steps.", self.num_steps) if dist.is_available() and dist.is_initialized(): - log.info(f"Rank: {dist.get_rank()}/{dist.get_world_size()}") + log.info(f"xxx Rank: {dist.get_rank()}/{dist.get_world_size()}") if self.enable_tensorboard: from tensorboardX import ( SummaryWriter, @@ -755,50 +753,54 @@ def step(_step_id, task_key="Default") -> None: if self.world_size > 1 else contextlib.nullcontext ) + + # with nvprof_context(enable_profiling, "Forward pass"): + log_dict = {} + + input_dict = { + "spin": None, + "fparam": None, + "aparam": None, + } + label_dict = { + "find_box": 1.0, + "find_coord": 1.0, + "find_numb_copy": 0.0, + "find_energy": 1.0, + "find_force": 1.0, + "find_virial": 0.0, + } + for k in ["atype", "box", "coord"]: + input_dict[k] = paddle.load(f"./input_{k}.pd") + for k in ["energy", "force", "natoms", "numb_copy", "virial"]: + label_dict[k] = paddle.load(f"./label_{k}.pd") + + for __key in ('coord', 'atype', 'box'): + input_dict[__key] = dist.shard_tensor(input_dict[__key], mesh=dist.get_mesh(), placements=[dist.Shard(0)]) + for __key, _ in label_dict.items(): + if isinstance(label_dict[__key], paddle.Tensor): + label_dict[__key] = dist.shard_tensor(label_dict[__key], mesh=dist.get_mesh(), placements=[dist.Shard(0)]) - # with sync_context(): - # with nvprof_context(enable_profiling, "Forward pass"): - # model_pred, loss, more_loss = self.wrapper( - # **input_dict, - # cur_lr=paddle.full([], pref_lr, DEFAULT_PRECISION), - # label=label_dict, - # task_key=task_key, - # ) - - # with nvprof_context(enable_profiling, "Backward pass"): - # loss.backward() - - # if self.world_size > 1: - # # fuse + allreduce manually before optimization if use DDP + no_sync - # # details in https://github.com/PaddlePaddle/Paddle/issues/48898#issuecomment-1343838622 - # hpu.fused_allreduce_gradients(list(self.wrapper.parameters()), None) - - with nvprof_context(enable_profiling, "Forward pass"): - for __key in ('coord', 'atype', 'box'): - input_dict[__key] = dist.shard_tensor(input_dict[__key], mesh=dist.get_mesh(), placements=[dist.Shard(0)]) - for __key, _ in label_dict.items(): - if isinstance(label_dict[__key], paddle.Tensor): - label_dict[__key] = dist.shard_tensor(label_dict[__key], mesh=dist.get_mesh(), placements=[dist.Shard(0)]) - model_pred, loss, more_loss = self.wrapper( - **input_dict, - cur_lr=paddle.full([], pref_lr, DEFAULT_PRECISION), - label=label_dict, - task_key=task_key, - ) + model_pred, loss, more_loss = self.wrapper( + **input_dict, + cur_lr=paddle.full([], pref_lr, DEFAULT_PRECISION), + label=label_dict, + task_key=task_key, + ) - with nvprof_context(enable_profiling, "Backward pass"): - loss.backward() + # with nvprof_context(enable_profiling, "Backward pass"): + loss.backward() if self.gradient_max_norm > 0.0: - with nvprof_context(enable_profiling, "Gradient clip"): - paddle.nn.utils.clip_grad_norm_( - self.wrapper.parameters(), - self.gradient_max_norm, - error_if_nonfinite=True, - ) + # with nvprof_context(enable_profiling, "Gradient clip"): + paddle.nn.utils.clip_grad_norm_( + self.wrapper.parameters(), + self.gradient_max_norm, + error_if_nonfinite=True, + ) - with nvprof_context(enable_profiling, "Adam update"): - self.optimizer.step() + # with nvprof_context(enable_profiling, "Adam update"): + self.optimizer.step() self.scheduler.step() else: @@ -856,7 +858,9 @@ def log_loss_valid(_task_key="Default"): if not self.multi_task: train_results = log_loss_train(loss, more_loss) - valid_results = log_loss_valid() + # valid_results = log_loss_valid() + # no run valid! + valid_results = None if self.rank == 0: log.info( format_training_message_per_task( @@ -938,39 +942,39 @@ def log_loss_valid(_task_key="Default"): ): self.total_train_time += train_time - if fout: - if self.lcurve_should_print_header: - self.print_header(fout, train_results, valid_results) - self.lcurve_should_print_header = False - self.print_on_training( - fout, display_step_id, cur_lr, train_results, valid_results - ) - - if ( - ((_step_id + 1) % self.save_freq == 0 and _step_id != self.start_step) - or (_step_id + 1) == self.num_steps - ) and (self.rank == 0 or dist.get_rank() == 0): - # Handle the case if rank 0 aborted and re-assigned - self.latest_model = Path(self.save_ckpt + f"-{_step_id + 1}.pd") - self.save_model(self.latest_model, lr=cur_lr, step=_step_id) - log.info(f"Saved model to {self.latest_model}") - symlink_prefix_files(self.latest_model.stem, self.save_ckpt) - with open("checkpoint", "w") as f: - f.write(str(self.latest_model)) + # if fout: + # if self.lcurve_should_print_header: + # self.print_header(fout, train_results, valid_results) + # self.lcurve_should_print_header = False + # self.print_on_training( + # fout, display_step_id, cur_lr, train_results, valid_results + # ) + + # if ( + # ((_step_id + 1) % self.save_freq == 0 and _step_id != self.start_step) + # or (_step_id + 1) == self.num_steps + # ) and (self.rank == 0 or dist.get_rank() == 0): + # # Handle the case if rank 0 aborted and re-assigned + # self.latest_model = Path(self.save_ckpt + f"-{_step_id + 1}.pd") + # self.save_model(self.latest_model, lr=cur_lr, step=_step_id) + # log.info(f"Saved model to {self.latest_model}") + # symlink_prefix_files(self.latest_model.stem, self.save_ckpt) + # with open("checkpoint", "w") as f: + # f.write(str(self.latest_model)) # tensorboard - if self.enable_tensorboard and ( - display_step_id % self.tensorboard_freq == 0 or display_step_id == 1 - ): - writer.add_scalar(f"{task_key}/lr", cur_lr, display_step_id) - writer.add_scalar(f"{task_key}/loss", loss.item(), display_step_id) - for item in more_loss: - writer.add_scalar( - f"{task_key}/{item}", more_loss[item].item(), display_step_id - ) - - if enable_profiling: - core.nvprof_nvtx_pop() + # if self.enable_tensorboard and ( + # display_step_id % self.tensorboard_freq == 0 or display_step_id == 1 + # ): + # writer.add_scalar(f"{task_key}/lr", cur_lr, display_step_id) + # writer.add_scalar(f"{task_key}/loss", loss.item(), display_step_id) + # for item in more_loss: + # writer.add_scalar( + # f"{task_key}/{item}", more_loss[item].item(), display_step_id + # ) + + # if enable_profiling: + # core.nvprof_nvtx_pop() self.wrapper.train() self.t0 = time.time() diff --git a/deepmd/pd/utils/dataloader.py b/deepmd/pd/utils/dataloader.py index 0cb8adbc63..66d7f56188 100644 --- a/deepmd/pd/utils/dataloader.py +++ b/deepmd/pd/utils/dataloader.py @@ -168,30 +168,30 @@ def construct_dataset(system): self.batch_sizes = batch_size * np.ones(len(systems), dtype=int) assert len(self.systems) == len(self.batch_sizes) for system, batch_size in zip(self.systems, self.batch_sizes): - if dist.is_available() and dist.is_initialized(): - system_batch_sampler = DistributedBatchSampler( - system, - shuffle=( - (not (dist.is_available() and dist.is_initialized())) - and shuffle - ), - batch_size=int(batch_size), - ) - self.sampler_list.append(system_batch_sampler) - else: - system_batch_sampler = BatchSampler( - system, - shuffle=( - (not (dist.is_available() and dist.is_initialized())) - and shuffle - ), - batch_size=int(batch_size), - ) - self.sampler_list.append(system_batch_sampler) + # if dist.is_available() and dist.is_initialized(): + # system_batch_sampler = DistributedBatchSampler( + # system, + # shuffle=( + # (not (dist.is_available() and dist.is_initialized())) + # and shuffle + # ), + # batch_size=int(batch_size), + # ) + # self.sampler_list.append(system_batch_sampler) + # else: + # system_batch_sampler = BatchSampler( + # system, + # shuffle=( + # (not (dist.is_available() and dist.is_initialized())) + # and shuffle + # ), + # batch_size=int(batch_size), + # ) + # self.sampler_list.append(system_batch_sampler) system_dataloader = DataLoader( dataset=system, num_workers=0, # Should be 0 to avoid too many threads forked - batch_sampler=system_batch_sampler, + batch_size=int(batch_size), collate_fn=collate_batch, use_buffer_reader=False, places=["cpu"], diff --git a/examples/water/dpa3/input_atype.pd b/examples/water/dpa3/input_atype.pd new file mode 100644 index 0000000000000000000000000000000000000000..e3b680187ac67ad6a4375c100b0f665edfdc0d02 GIT binary patch literal 24773 zcmeI*y-tHr7{+l>NgYg_+#Q`dY2x6dny$*abbL*;m-cfOFyN|>F$3DKZ(P;Ge(~jI<#%*l2XZe?Zs{N2#{@HV2?Uw+ywrM{k GF#HAV4q&VR literal 0 HcmV?d00001 diff --git a/examples/water/dpa3/input_box.pd b/examples/water/dpa3/input_box.pd new file mode 100644 index 0000000000000000000000000000000000000000..2ba4ce0ca77547e3d0ac832af23b6a9cfba5d5b4 GIT binary patch literal 2501 zcmZo*nYxRU0StOLl1ejkN;30`r}VIvlosTqPMJKVhd(tjJ+&x4GcUd*w;Tn$kWcXo`k6qql-LXWNtv_8!)hlF9BInW@`6>5H5?$0$4U|_PpmqumH-7|`e8I7b%f+c&A}c*uyBFV*i|9ogOL2F zIoLx87A`OvyQnTc2y%h{Y(M2gxaRG0vl3# E0BE;IIsgCw literal 0 HcmV?d00001 diff --git a/examples/water/dpa3/input_coord.pd b/examples/water/dpa3/input_coord.pd new file mode 100644 index 0000000000000000000000000000000000000000..a1dd2f8fac25af496cd9f0267fc5fc83abe88a35 GIT binary patch literal 147664 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

%|1lDA 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 idroqsL7fJz=Wr>TJ`dPZ~GEb(8Dr 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 bPH&6hP)8x|4vww-YyGzjyF`n|4(WXWCR|TX literal 0 HcmV?d00001 diff --git a/examples/water/dpa3/label_virial.pd b/examples/water/dpa3/label_virial.pd new file mode 100644 index 0000000000000000000000000000000000000000..de909e6655a4c1ddc2a5233bfbdcd6f0d12bb1ac GIT binary patch literal 2501 zcmeH}p$@_@6h${+0TL1v9*LSlAW-0FGQkft+bFPPD@$p`9A*QOIxauM&q3+<3wp&h z@4dX6qwb~md<{J-JxElR%Z#6)1F6cK;Q>8n@qr1NaVm?FF6Ph^u8Oh>)01Ffq0B)n zL|j3Ss9@=dpQTW#{GJAO5xUQJ?aBkhtFiVIT(QNB_+(0k4UT;s>||Bif1UjT_gg#f uYJZ6+iZ*W}Ys8aC?kn#Xxee~z5pVQ6@i literal 0 HcmV?d00001 diff --git a/examples/water/dpa3/run.sh b/examples/water/dpa3/run.sh index db9d895ac6..f7ef137060 100644 --- a/examples/water/dpa3/run.sh +++ b/examples/water/dpa3/run.sh @@ -5,9 +5,15 @@ # unset PADDLE_ELASTIC_TIMEOUT # export NNODES=1 # export PADDLE_TRAINERS_NUM=1 -unset CUDA_DEVICE_MAX_CONNECTIONS +# unset CUDA_DEVICE_MAX_CONNECTIONS -HDFS_USE_FILE_LOCKING=0 python -m paddle.distributed.launch --gpus="0,1,2,3,4,5,6,7" --log_dir "logs" dp --pd train input_torch.json -l dp_train.log + +rm -rf output/ + +${nsys_args} python -m paddle.distributed.launch \ + --log_dir output \ + --run_mode=collective \ + dp --pd train input_torch.json # NUM_WORKERS=0 HDFS_USE_FILE_LOCKING=0 python -m paddle.distributed.launch