Skip to content

Commit a912e37

Browse files
njzjz-botGLM-5
authored andcommitted
docs: add mathematical formulas to descriptor classes
Add detailed mathematical formulas to the following descriptor classes: - DescrptSeR: radial descriptor with switching function - DescrptSeT: angular descriptor with cosine angles - DescrptSeTTebd: angular descriptor with type embedding - DescrptSeAttenV2: attention-based descriptor v2 - DescrptHybrid: concatenation of multiple descriptors - DescrptDPA2: repinit + repformer block equations - RepFlowArgs (DPA3): node/edge/angle update equations Follow numpydoc convention: parameters documented in class docstring, not in __init__ docstring. Co-authored-by: GLM-5 <glm-5@zhipuai.cn>
1 parent 5eb5400 commit a912e37

10 files changed

Lines changed: 464 additions & 55 deletions

File tree

deepmd/dpmodel/descriptor/dpa1.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,84 @@ def update_sel(
671671

672672
@DescriptorBlock.register("se_atten")
673673
class DescrptBlockSeAtten(NativeOP, DescriptorBlock):
674+
r"""The attention-based descriptor block.
675+
676+
This block computes an embedding matrix using attention mechanism and type embedding.
677+
The descriptor is computed as:
678+
679+
.. math::
680+
\mathcal{D}^i = \frac{1}{N_c^2}(\hat{\mathcal{G}}^i)^T \mathcal{R}^i (\mathcal{R}^i)^T \hat{\mathcal{G}}^i_<,
681+
682+
where :math:`\hat{\mathcal{G}}^i` is the embedding matrix after self-attention layers,
683+
:math:`\mathcal{R}^i` is the coordinate matrix, and :math:`\hat{\mathcal{G}}^i_<` denotes
684+
the first `axis_neuron` columns of :math:`\hat{\mathcal{G}}^i`.
685+
686+
The embedding matrix :math:`\mathcal{G}^i` is computed by:
687+
688+
.. math::
689+
(\mathcal{G}^i)_j = \mathcal{N}(s(r_{ji}), \mathcal{T}_i, \mathcal{T}_j),
690+
691+
where :math:`\mathcal{N}` is the embedding network, :math:`s(r_{ji})` is the smoothed
692+
radial distance, and :math:`\mathcal{T}` denotes type embedding.
693+
694+
Parameters
695+
----------
696+
rcut : float
697+
The cut-off radius.
698+
rcut_smth : float
699+
Where to start smoothing.
700+
sel : Union[list[int], int]
701+
Maximally possible number of selected neighbors.
702+
ntypes : int
703+
Number of element types.
704+
neuron : list[int], optional
705+
Number of neurons in each hidden layer of the embedding net.
706+
axis_neuron : int, optional
707+
Size of the submatrix of the embedding matrix.
708+
tebd_dim : int, optional
709+
Dimension of the type embedding.
710+
tebd_input_mode : str, optional
711+
The input mode of the type embedding. Supported modes are ["concat", "strip"].
712+
resnet_dt : bool, optional
713+
Time-step `dt` in the resnet construction.
714+
type_one_side : bool, optional
715+
If True, only type embeddings of neighbor atoms are considered.
716+
attn : int, optional
717+
Hidden dimension of the attention vectors.
718+
attn_layer : int, optional
719+
Number of attention layers.
720+
attn_dotr : bool, optional
721+
If True, dot the angular gate to the attention weights.
722+
attn_mask : bool, optional
723+
If True, mask the diagonal of attention weights.
724+
exclude_types : list[tuple[int, int]], optional
725+
The excluded pairs of types which have no interaction.
726+
env_protection : float, optional
727+
Protection parameter to prevent division by zero.
728+
set_davg_zero : bool, optional
729+
Set the shift of embedding net input to zero.
730+
activation_function : str, optional
731+
The activation function in the embedding net.
732+
precision : str, optional
733+
The precision of the embedding net parameters.
734+
scaling_factor : float, optional
735+
The scaling factor of normalization in attention weights calculation.
736+
normalize : bool, optional
737+
Whether to normalize the hidden vectors in attention weights calculation.
738+
temperature : float, optional
739+
If not None, the scaling of attention weights is `temperature` itself.
740+
trainable_ln : bool, optional
741+
Whether to use trainable shift and scale weights in layer normalization.
742+
ln_eps : float, optional
743+
The epsilon value for layer normalization.
744+
smooth : bool, optional
745+
Whether to use smoothness in attention weights calculation.
746+
seed : int, optional
747+
Random seed for parameter initialization.
748+
trainable : bool, optional
749+
If the parameters are trainable.
750+
"""
751+
674752
def __init__(
675753
self,
676754
rcut: float,

deepmd/dpmodel/descriptor/dpa2.py

Lines changed: 72 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,78 @@ def deserialize(cls, data: dict) -> "RepformerArgs":
369369

370370
@BaseDescriptor.register("dpa2")
371371
class DescrptDPA2(NativeOP, BaseDescriptor):
372+
r"""The DPA-2 descriptor[1]_.
373+
374+
The DPA-2 descriptor combines a repinit block and a repformer block to extract
375+
atomic representations. The overall descriptor is computed as:
376+
377+
.. math::
378+
\mathcal{D}^i = \mathrm{Repformer}(\mathrm{Linear}(\mathrm{Repinit}(\mathcal{R}^i, \mathcal{T}^i))),
379+
380+
where :math:`\mathcal{R}^i` is the environment matrix and :math:`\mathcal{T}^i` is the
381+
type embedding.
382+
383+
The repinit block computes initial node and edge representations using attention-based
384+
message passing. The repformer block further refines these representations through
385+
multiple layers of graph convolution and attention mechanisms.
386+
387+
The final output dimension is:
388+
389+
.. math::
390+
\dim(\mathcal{D}^i) = \text{g1\_dim} + \text{tebd\_dim} \quad (\text{if concat\_output\_tebd}).
391+
392+
Parameters
393+
----------
394+
repinit : Union[RepinitArgs, dict]
395+
The arguments used to initialize the repinit block, see docstr in `RepinitArgs` for details information.
396+
repformer : Union[RepformerArgs, dict]
397+
The arguments used to initialize the repformer block, see docstr in `RepformerArgs` for details information.
398+
concat_output_tebd : bool, optional
399+
Whether to concat type embedding at the output of the descriptor.
400+
precision : str, optional
401+
The precision of the embedding net parameters.
402+
smooth : bool, optional
403+
Whether to use smoothness in processes such as attention weights calculation.
404+
exclude_types : list[list[int]], optional
405+
The excluded pairs of types which have no interaction with each other.
406+
For example, `[[0, 1]]` means no interaction between type 0 and type 1.
407+
env_protection : float, optional
408+
Protection parameter to prevent division by zero errors during environment matrix calculations.
409+
For example, when using paddings, there may be zero distances of neighbors, which may make division by zero error during environment matrix calculations without protection.
410+
trainable : bool, optional
411+
If the parameters are trainable.
412+
seed : int, optional
413+
(Unused yet) Random seed for parameter initialization.
414+
add_tebd_to_repinit_out : bool, optional
415+
Whether to add type embedding to the output representation from repinit before inputting it into repformer.
416+
use_econf_tebd : bool, Optional
417+
Whether to use electronic configuration type embedding.
418+
use_tebd_bias : bool, Optional
419+
Whether to use bias in the type embedding layer.
420+
type_map : list[str], Optional
421+
A list of strings. Give the name to each type of atoms.
422+
423+
Returns
424+
-------
425+
descriptor: torch.Tensor
426+
the descriptor of shape nf x nloc x g1_dim.
427+
invariant single-atom representation.
428+
g2: torch.Tensor
429+
invariant pair-atom representation.
430+
h2: torch.Tensor
431+
equivariant pair-atom representation.
432+
rot_mat: torch.Tensor
433+
rotation matrix for equivariant fittings
434+
sw: torch.Tensor
435+
The switch function for decaying inverse distance.
436+
437+
References
438+
----------
439+
.. [1] Zhang, D., Liu, X., Zhang, X. et al. DPA-2: a
440+
large atomic model as a multi-task learner. npj
441+
Comput Mater 10, 293 (2024). https://doi.org/10.1038/s41524-024-01493-2
442+
"""
443+
372444
def __init__(
373445
self,
374446
ntypes: int,
@@ -389,60 +461,6 @@ def __init__(
389461
use_tebd_bias: bool = False,
390462
type_map: list[str] | None = None,
391463
) -> None:
392-
r"""The DPA-2 descriptor[1]_.
393-
394-
Parameters
395-
----------
396-
repinit : Union[RepinitArgs, dict]
397-
The arguments used to initialize the repinit block, see docstr in `RepinitArgs` for details information.
398-
repformer : Union[RepformerArgs, dict]
399-
The arguments used to initialize the repformer block, see docstr in `RepformerArgs` for details information.
400-
concat_output_tebd : bool, optional
401-
Whether to concat type embedding at the output of the descriptor.
402-
precision : str, optional
403-
The precision of the embedding net parameters.
404-
smooth : bool, optional
405-
Whether to use smoothness in processes such as attention weights calculation.
406-
exclude_types : list[list[int]], optional
407-
The excluded pairs of types which have no interaction with each other.
408-
For example, `[[0, 1]]` means no interaction between type 0 and type 1.
409-
env_protection : float, optional
410-
Protection parameter to prevent division by zero errors during environment matrix calculations.
411-
For example, when using paddings, there may be zero distances of neighbors, which may make division by zero error during environment matrix calculations without protection.
412-
trainable : bool, optional
413-
If the parameters are trainable.
414-
seed : int, optional
415-
(Unused yet) Random seed for parameter initialization.
416-
add_tebd_to_repinit_out : bool, optional
417-
Whether to add type embedding to the output representation from repinit before inputting it into repformer.
418-
use_econf_tebd : bool, Optional
419-
Whether to use electronic configuration type embedding.
420-
use_tebd_bias : bool, Optional
421-
Whether to use bias in the type embedding layer.
422-
type_map : list[str], Optional
423-
A list of strings. Give the name to each type of atoms.
424-
425-
Returns
426-
-------
427-
descriptor: torch.Tensor
428-
the descriptor of shape nf x nloc x g1_dim.
429-
invariant single-atom representation.
430-
g2: torch.Tensor
431-
invariant pair-atom representation.
432-
h2: torch.Tensor
433-
equivariant pair-atom representation.
434-
rot_mat: torch.Tensor
435-
rotation matrix for equivariant fittings
436-
sw: torch.Tensor
437-
The switch function for decaying inverse distance.
438-
439-
References
440-
----------
441-
.. [1] Zhang, D., Liu, X., Zhang, X. et al. DPA-2: a
442-
large atomic model as a multi-task learner. npj
443-
Comput Mater 10, 293 (2024). https://doi.org/10.1038/s41524-024-01493-2
444-
"""
445-
446464
def init_subclass_params(sub_data: dict | Any, sub_class: type) -> Any:
447465
if isinstance(sub_data, dict):
448466
return sub_class(**sub_data)

deepmd/dpmodel/descriptor/dpa3.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,27 @@
5959
class RepFlowArgs:
6060
r"""The constructor for the RepFlowArgs class which defines the parameters of the repflow block in DPA3 descriptor.
6161
62+
The DPA-3 descriptor uses a repflow architecture that maintains and updates three types
63+
of representations: node (:math:`\mathbf{n}`), edge (:math:`\mathbf{e}`), and angle (:math:`\mathbf{a}`).
64+
65+
The update equations for each layer are:
66+
67+
.. math::
68+
\mathbf{n}^{l+1} = \text{UpdateNode}(\mathbf{n}^l, \mathbf{e}^l, \mathbf{a}^l),
69+
70+
.. math::
71+
\mathbf{e}^{l+1} = \text{UpdateEdge}(\mathbf{n}^l, \mathbf{e}^l, \mathbf{a}^l),
72+
73+
.. math::
74+
\mathbf{a}^{l+1} = \text{UpdateAngle}(\mathbf{n}^l, \mathbf{e}^l, \mathbf{a}^l).
75+
76+
The final descriptor is obtained by symmetrization:
77+
78+
.. math::
79+
\mathcal{D}^i = \text{Symmetrize}(\mathbf{n}^L, \mathbf{e}^L),
80+
81+
where :math:`L` is the number of repflow layers.
82+
6283
Parameters
6384
----------
6485
n_dim : int, optional
@@ -254,6 +275,31 @@ def deserialize(cls, data: dict) -> "RepFlowArgs":
254275
class DescrptDPA3(NativeOP, BaseDescriptor):
255276
r"""The DPA3 descriptor[1]_.
256277
278+
The DPA-3 descriptor uses a repflow block to iteratively update node, edge, and angle
279+
representations. The descriptor is computed as:
280+
281+
.. math::
282+
\mathcal{D}^i = \mathrm{RepFlow}(\mathcal{N}^i, \mathcal{E}^i, \mathcal{A}^i),
283+
284+
where :math:`\mathcal{N}^i`, :math:`\mathcal{E}^i`, and :math:`\mathcal{A}^i` are the
285+
initial node, edge, and angle representations respectively.
286+
287+
The repflow block performs iterative updates through multiple layers:
288+
289+
.. math::
290+
\mathcal{N}^{i,l+1} = \mathrm{UpdateNode}(\mathcal{N}^{i,l}, \mathcal{E}^{i,l}, \mathcal{A}^{i,l}),
291+
292+
.. math::
293+
\mathcal{E}^{i,l+1} = \mathrm{UpdateEdge}(\mathcal{N}^{i,l}, \mathcal{E}^{i,l}, \mathcal{A}^{i,l}),
294+
295+
.. math::
296+
\mathcal{A}^{i,l+1} = \mathrm{UpdateAngle}(\mathcal{N}^{i,l}, \mathcal{E}^{i,l}, \mathcal{A}^{i,l}).
297+
298+
The final descriptor output dimension is:
299+
300+
.. math::
301+
\dim(\mathcal{D}^i) = \text{n\_dim} \times \text{axis\_neuron} \quad (\text{after symmetrization}).
302+
257303
Parameters
258304
----------
259305
repflow : Union[RepFlowArgs, dict]

deepmd/dpmodel/descriptor/hybrid.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,20 @@
3333

3434
@BaseDescriptor.register("hybrid")
3535
class DescrptHybrid(BaseDescriptor, NativeOP):
36-
"""Concate a list of descriptors to form a new descriptor.
36+
r"""Concatenate a list of descriptors to form a new descriptor.
37+
38+
The hybrid descriptor combines multiple descriptors by concatenation:
39+
40+
.. math::
41+
\mathcal{D}^i = [\mathcal{D}^i_1, \mathcal{D}^i_2, ..., \mathcal{D}^i_n],
42+
43+
where :math:`\mathcal{D}^i_k` is the descriptor computed by the :math:`k`-th
44+
sub-descriptor for atom :math:`i`.
45+
46+
The output dimension is the sum of all sub-descriptor dimensions:
47+
48+
.. math::
49+
\dim(\mathcal{D}^i) = \sum_{k=1}^{n} \dim(\mathcal{D}^i_k).
3750
3851
Parameters
3952
----------

deepmd/dpmodel/descriptor/repflows.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,31 @@ class DescrptBlockRepflows(NativeOP, DescriptorBlock):
6363
r"""
6464
The repflow descriptor block.
6565
66+
The repflow descriptor maintains three types of representations and updates them
67+
iteratively through message passing:
68+
69+
- **Node representation** :math:`\mathbf{n}^i \in \mathbb{R}^{n_{dim}}`: single-atom features
70+
- **Edge representation** :math:`\mathbf{e}^{ij} \in \mathbb{R}^{e_{dim}}`: pair-atom features
71+
- **Angle representation** :math:`\mathbf{a}^{ijk} \in \mathbb{R}^{a_{dim}}`: three-body features
72+
73+
The update equations for layer :math:`l` are:
74+
75+
.. math::
76+
\mathbf{n}^{i,l+1} = \mathbf{n}^{i,l} + \text{MLP}_n\left(\sum_{j \in \mathcal{N}(i)} \mathbf{e}^{ij,l}\right),
77+
78+
.. math::
79+
\mathbf{e}^{ij,l+1} = \mathbf{e}^{ij,l} + \text{MLP}_e\left([\mathbf{n}^{i,l}, \mathbf{n}^{j,l}, \mathbf{e}^{ij,l}, \sum_k \mathbf{a}^{ijk,l}]\right),
80+
81+
.. math::
82+
\mathbf{a}^{ijk,l+1} = \mathbf{a}^{ijk,l} + \text{MLP}_a\left([\mathbf{e}^{ij,l}, \mathbf{e}^{ik,l}, \cos\theta_{jik}]\right).
83+
84+
The final descriptor is computed via symmetrization:
85+
86+
.. math::
87+
\mathcal{D}^i = \frac{1}{N_c^2} (\mathcal{N}^i)^T \mathcal{E}^i (\mathcal{E}^i)^T \mathcal{N}^i_<,
88+
89+
where :math:`\mathcal{N}^i_<` denotes the first `axis_neuron` columns of :math:`\mathcal{N}^i`.
90+
6691
Parameters
6792
----------
6893
n_dim : int, optional

deepmd/dpmodel/descriptor/repformers.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,34 @@ class DescrptBlockRepformers(NativeOP, DescriptorBlock):
8484
r"""
8585
The repformer descriptor block.
8686
87+
The repformer block iteratively updates single-atom (:math:`\mathcal{G}_1`),
88+
pair-atom (:math:`\mathcal{G}_2`), and equivariant pair-atom (:math:`\mathcal{H}_2`)
89+
representations through multiple layers:
90+
91+
**Update of :math:`\mathcal{G}_1` (single-atom representation):**
92+
93+
The update can include multiple terms:
94+
95+
- Convolution term: :math:`\mathcal{G}_1^{i,l+1} \leftarrow \mathcal{G}_1^{i,l} + \mathrm{MLP}(\mathcal{G}_2^{i,l})`
96+
- DRRD term: :math:`\mathcal{G}_1^{i,l+1} \leftarrow \mathcal{G}_1^{i,l} + \mathrm{MLP}(\mathcal{G}_2^{i,l} \odot \mathcal{R}^i)`
97+
- GRRG term: :math:`\mathcal{G}_1^{i,l+1} \leftarrow \mathcal{G}_1^{i,l} + \mathrm{MLP}((\mathcal{G}_2^{i,l})^T \mathcal{R}^i)`
98+
- Attention term: :math:`\mathcal{G}_1^{i,l+1} \leftarrow \mathcal{G}_1^{i,l} + \mathrm{SelfAttention}(\mathcal{G}_1^{i,l})`
99+
100+
**Update of :math:`\mathcal{G}_2` (pair-atom representation):**
101+
102+
- G1xG1 term: :math:`\mathcal{G}_2^{i,l+1} \leftarrow \mathcal{G}_2^{i,l} + \mathrm{MLP}(\mathcal{G}_1^{i,l} \otimes \mathcal{G}_1^{i,l})`
103+
- Attention term: :math:`\mathcal{G}_2^{i,l+1} \leftarrow \mathcal{G}_2^{i,l} + \mathrm{GatedSelfAttention}(\mathcal{G}_2^{i,l})`
104+
105+
**Update of :math:`\mathcal{H}_2` (equivariant pair-atom representation):**
106+
107+
.. math::
108+
\mathcal{H}_2^{i,l+1} = \mathcal{H}_2^{i,l} + \mathrm{MLP}(\mathcal{G}_2^{i,l}) \odot \mathcal{R}^i.
109+
110+
The final descriptor is computed via symmetrization:
111+
112+
.. math::
113+
\mathcal{D}^i = \frac{1}{N_c^2} (\mathcal{G}_1^i)^T \mathcal{G}_2^i (\mathcal{G}_2^i)^T \mathcal{G}_{1,<}^i.
114+
87115
Parameters
88116
----------
89117
rcut : float

0 commit comments

Comments
 (0)