From 9a4a4dd1339c900d40deed0420187241fc09c4d9 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 30 Oct 2023 02:37:19 -0400 Subject: [PATCH 01/97] support compressing gelu_tf (#2957) `gelu_tf` is equivalent to `gelu`. --------- Signed-off-by: Jinzhe Zeng Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- deepmd/utils/tabulate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/deepmd/utils/tabulate.py b/deepmd/utils/tabulate.py index d0a167f1dc..ade4d973ce 100644 --- a/deepmd/utils/tabulate.py +++ b/deepmd/utils/tabulate.py @@ -85,7 +85,10 @@ def __init__( # functype if activation_fn == ACTIVATION_FN_DICT["tanh"]: self.functype = 1 - elif activation_fn == ACTIVATION_FN_DICT["gelu"]: + elif activation_fn in ( + ACTIVATION_FN_DICT["gelu"], + ACTIVATION_FN_DICT["gelu_tf"], + ): self.functype = 2 elif activation_fn == ACTIVATION_FN_DICT["relu"]: self.functype = 3 From 1429e462c3a8f72328988365412f527001459ad2 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 30 Oct 2023 02:57:35 -0400 Subject: [PATCH 02/97] fix SpecifierSet behavior with prereleases (#2959) By default, SpecifierSet doesn't allow prereleases, which is not our expected behavior. Signed-off-by: Jinzhe Zeng --- backend/find_tensorflow.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/find_tensorflow.py b/backend/find_tensorflow.py index aa75d5ecb4..6d7ce5087d 100644 --- a/backend/find_tensorflow.py +++ b/backend/find_tensorflow.py @@ -114,9 +114,9 @@ def get_tf_requirement(tf_version: str = "") -> dict: extra_requires = [] extra_select = {} - if not (tf_version == "" or tf_version in SpecifierSet(">=2.12")): + if not (tf_version == "" or tf_version in SpecifierSet(">=2.12", prereleases=True)): extra_requires.append("protobuf<3.20") - if tf_version == "" or tf_version in SpecifierSet(">=1.15"): + if tf_version == "" or tf_version in SpecifierSet(">=1.15", prereleases=True): extra_select["mpi"] = [ "horovod", "mpi4py", @@ -138,9 +138,9 @@ def get_tf_requirement(tf_version: str = "") -> dict: ], **extra_select, } - elif tf_version in SpecifierSet("<1.15") or tf_version in SpecifierSet( - ">=2.0,<2.1" - ): + elif tf_version in SpecifierSet( + "<1.15", prereleases=True + ) or tf_version in SpecifierSet(">=2.0,<2.1", prereleases=True): return { "cpu": [ f"tensorflow=={tf_version}", From 5be8fc930d6f4b0ff4085cf4c1fd3472f036a3ed Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 31 Oct 2023 08:58:03 +0800 Subject: [PATCH 03/97] [pre-commit.ci] pre-commit autoupdate (#2961) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.1.1 → v0.1.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.1...v0.1.3) - [github.com/psf/black-pre-commit-mirror: 23.10.0 → 23.10.1](https://github.com/psf/black-pre-commit-mirror/compare/23.10.0...23.10.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e168af2c8d..9ccb86f959 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,13 +30,13 @@ repos: exclude: ^source/3rdparty - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.1 + rev: v0.1.3 hooks: - id: ruff args: ["--fix"] exclude: ^source/3rdparty - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.10.0 + rev: 23.10.1 hooks: - id: black-jupyter exclude: ^source/3rdparty From 389d403ef97ba374fb4af5f4256c30c2299cdc95 Mon Sep 17 00:00:00 2001 From: Lysithea <52808607+CaRoLZhangxy@users.noreply.github.com> Date: Tue, 31 Oct 2023 14:55:13 +0800 Subject: [PATCH 04/97] merge prob_sys_size with prob_sys_size;0:nsys:1.0 (#2963) to be consistent with Pytorch version --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- deepmd/utils/data_system.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index 69a6cbe112..09dcac2d8d 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -195,8 +195,7 @@ def __init__( assert isinstance(self.test_size, (list, np.ndarray)) assert len(self.test_size) == self.nsystems - # prob of batch, init pick idx - self.prob_nbatches = [float(i) for i in self.nbatches] / np.sum(self.nbatches) + # init pick idx self.pick_idx = 0 # derive system probabilities @@ -350,11 +349,13 @@ def set_sys_probs(self, sys_probs=None, auto_prob_style: str = "prob_sys_size"): if auto_prob_style == "prob_uniform": prob_v = 1.0 / float(self.nsystems) probs = [prob_v for ii in range(self.nsystems)] - elif auto_prob_style == "prob_sys_size": - probs = self.prob_nbatches - elif auto_prob_style[:14] == "prob_sys_size;": + elif auto_prob_style[:13] == "prob_sys_size": + if auto_prob_style == "prob_sys_size": + prob_style = f"prob_sys_size;0:{self.get_nsystems()}:1.0" + else: + prob_style = auto_prob_style probs = prob_sys_size_ext( - auto_prob_style, self.get_nsystems(), self.nbatches + prob_style, self.get_nsystems(), self.nbatches ) else: raise RuntimeError("Unknown auto prob style: " + auto_prob_style) From 1529e72a171eaeaadc4a556706b2eceb50db7cb9 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Tue, 31 Oct 2023 20:38:32 -0400 Subject: [PATCH 05/97] move to ruff formatter (#2951) See https://astral.sh/blog/the-ruff-formatter --------- Signed-off-by: Jinzhe Zeng Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 9 ++++----- deepmd/entrypoints/train.py | 4 +--- deepmd/fit/polar.py | 5 +++-- deepmd/utils/argcheck.py | 16 ++++------------ deepmd/utils/finetune.py | 14 ++++++++------ deepmd/utils/tabulate.py | 3 +-- doc/getting-started/quick_start.ipynb | 3 ++- 7 files changed, 23 insertions(+), 31 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9ccb86f959..ce5cf54d33 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,11 +35,10 @@ repos: - id: ruff args: ["--fix"] exclude: ^source/3rdparty -- repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.10.1 - hooks: - - id: black-jupyter - exclude: ^source/3rdparty + types_or: [python, pyi, jupyter] + - id: ruff-format + exclude: ^source/3rdparty + types_or: [python, pyi, jupyter] # numpydoc - repo: https://github.com/Carreau/velin rev: 0.0.12 diff --git a/deepmd/entrypoints/train.py b/deepmd/entrypoints/train.py index 9469b7df90..227aa13644 100755 --- a/deepmd/entrypoints/train.py +++ b/deepmd/entrypoints/train.py @@ -404,9 +404,7 @@ def get_nbor_stat(jdata, rcut, one_type: bool = False): None, ) tmp_data.get_batch() - assert ( - tmp_data.get_type_map() - ), f"In multi-task mode, 'type_map.raw' must be defined in data systems {systems}! " + assert tmp_data.get_type_map(), f"In multi-task mode, 'type_map.raw' must be defined in data systems {systems}! " if train_data is None: train_data = tmp_data else: diff --git a/deepmd/fit/polar.py b/deepmd/fit/polar.py index 0a6f7d4242..8f6631866c 100644 --- a/deepmd/fit/polar.py +++ b/deepmd/fit/polar.py @@ -213,8 +213,9 @@ def compute_input_stats(self, all_stat, protection=1e-2): # add polar_bias polar_bias.append(all_stat["polarizability"][ss].reshape((1, 9))) - matrix, bias = np.concatenate(sys_matrix, axis=0), np.concatenate( - polar_bias, axis=0 + matrix, bias = ( + np.concatenate(sys_matrix, axis=0), + np.concatenate(polar_bias, axis=0), ) atom_polar, _, _, _ = np.linalg.lstsq(matrix, bias, rcond=None) for itype in range(len(self.sel_type)): diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index 7104eb1de4..8d09d25577 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -1857,12 +1857,8 @@ def normalize_multi_task(data): fitting_weight=fitting_weight, ) else: - assert ( - not multi_loss - ), "In single-task mode, please use 'model/loss' in stead of 'model/loss_dict'! " - assert ( - not multi_learning_rate - ), "In single-task mode, please use 'model/learning_rate' in stead of 'model/learning_rate_dict'! " + assert not multi_loss, "In single-task mode, please use 'model/loss' in stead of 'model/loss_dict'! " + assert not multi_learning_rate, "In single-task mode, please use 'model/learning_rate' in stead of 'model/learning_rate_dict'! " return data @@ -1912,9 +1908,7 @@ def normalize_learning_rate_dict(fitting_keys, learning_rate_dict): failed_learning_rate_keys = [ item for item in learning_rate_dict if item not in fitting_keys ] - assert ( - not failed_learning_rate_keys - ), "Learning rate dict key(s) {} not have corresponding fitting keys in {}! ".format( + assert not failed_learning_rate_keys, "Learning rate dict key(s) {} not have corresponding fitting keys in {}! ".format( str(failed_learning_rate_keys), str(list(fitting_keys)) ) new_dict = {} @@ -1970,9 +1964,7 @@ def normalize_fitting_weight(fitting_keys, data_keys, fitting_weight=None): failed_weight_keys = [ item for item in fitting_weight if item not in fitting_keys ] - assert ( - not failed_weight_keys - ), "Fitting weight key(s) {} not have corresponding fitting keys in {}! ".format( + assert not failed_weight_keys, "Fitting weight key(s) {} not have corresponding fitting keys in {}! ".format( str(failed_weight_keys), str(list(fitting_keys)) ) sum_prob = 0.0 diff --git a/deepmd/utils/finetune.py b/deepmd/utils/finetune.py index 4e597b1e05..cc6c0224de 100644 --- a/deepmd/utils/finetune.py +++ b/deepmd/utils/finetune.py @@ -41,12 +41,14 @@ def replace_model_params_with_pretrained_model( pretrained_jdata = json.loads(t_jdata) # Check the model type - assert pretrained_jdata["model"]["descriptor"]["type"] in [ - "se_atten", - "se_atten_v2", - ] and pretrained_jdata["model"]["fitting_net"]["type"] in [ - "ener" - ], "The finetune process only supports models pretrained with 'se_atten' or 'se_atten_v2' descriptor and 'ener' fitting_net!" + assert ( + pretrained_jdata["model"]["descriptor"]["type"] + in [ + "se_atten", + "se_atten_v2", + ] + and pretrained_jdata["model"]["fitting_net"]["type"] in ["ener"] + ), "The finetune process only supports models pretrained with 'se_atten' or 'se_atten_v2' descriptor and 'ener' fitting_net!" # Check the type map pretrained_type_map = pretrained_jdata["model"]["type_map"] diff --git a/deepmd/utils/tabulate.py b/deepmd/utils/tabulate.py index ade4d973ce..2b270b1dbc 100644 --- a/deepmd/utils/tabulate.py +++ b/deepmd/utils/tabulate.py @@ -333,8 +333,7 @@ def _build_lower( elif isinstance(self.descrpt, deepmd.descriptor.DescrptSeT): tt = np.full((nspline, self.last_layer_size), stride1) tt[ - int((lower - extrapolate * lower) / stride1) - + 1 : ( + int((lower - extrapolate * lower) / stride1) + 1 : ( int((lower - extrapolate * lower) / stride1) + int((upper - lower) / stride0) ), diff --git a/doc/getting-started/quick_start.ipynb b/doc/getting-started/quick_start.ipynb index 31209ae381..028e56dc6f 100644 --- a/doc/getting-started/quick_start.ipynb +++ b/doc/getting-started/quick_start.ipynb @@ -208,7 +208,8 @@ "print(\"# the data contains %d frames\" % len(data))\n", "\n", "# random choose 40 index for validation_data\n", - "index_validation = np.random.choice(201, size=40, replace=False)\n", + "rng = np.random.default_rng()\n", + "index_validation = rng.choice(201, size=40, replace=False)\n", "\n", "# other indexes are training_data\n", "index_training = list(set(range(201)) - set(index_validation))\n", From 1cbe63da1fb0a440691f3785524f65b5ff0c47e5 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 1 Nov 2023 21:23:57 -0400 Subject: [PATCH 06/97] docs: add theory from v2 paper (#2715) Add theory to documentation. --------- Signed-off-by: Jinzhe Zeng Signed-off-by: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> --- README.md | 1 + backend/dynamic_metadata.py | 3 +- doc/conf.py | 1 + doc/freeze/compress.md | 49 +++++++++++++++++++++++++++ doc/model/dplr.md | 22 ++++++++++++ doc/model/dprc.md | 38 +++++++++++++++++++-- doc/model/index.md | 1 + doc/model/index.rst | 1 + doc/model/overall.md | 26 ++++++++++++++ doc/model/pairtab.md | 35 +++++++++++++++++++ doc/model/train-energy.md | 56 +++++++++++++++++++++++++++++++ doc/model/train-fitting-tensor.md | 34 +++++++++++++++++++ doc/model/train-hybrid.md | 17 ++++++++++ doc/model/train-se-atten.md | 45 +++++++++++++++++++++++-- doc/model/train-se-e2-a-tebd.md | 53 ++++++++++++++++++++++++++++- doc/model/train-se-e2-a.md | 54 +++++++++++++++++++++++++++++ doc/model/train-se-e2-r.md | 40 ++++++++++++++++++++++ doc/model/train-se-e3.md | 34 ++++++++++++++++++- doc/nvnmd/nvnmd.md | 2 +- doc/test/model-deviation.md | 45 +++++++++++++++++++++++++ doc/train/multi-task-training.md | 17 ++++++++++ doc/train/training-advanced.md | 21 +++++++++--- 22 files changed, 582 insertions(+), 13 deletions(-) create mode 100644 doc/model/pairtab.md diff --git a/README.md b/README.md index 5914abe607..680e187012 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ A full [document](doc/train/train-input-auto.rst) on options in the training inp - [Deep potential long-range](doc/model/dplr.md) - [Deep Potential - Range Correction (DPRc)](doc/model/dprc.md) - [Linear model](doc/model/linear.md) + - [Interpolation with a pairwise potential](doc/model/pairtab.md) - [Training](doc/train/index.md) - [Training a model](doc/train/training.md) - [Advanced options](doc/train/training-advanced.md) diff --git a/backend/dynamic_metadata.py b/backend/dynamic_metadata.py index 0502684f47..59df7dce81 100644 --- a/backend/dynamic_metadata.py +++ b/backend/dynamic_metadata.py @@ -44,7 +44,8 @@ def dynamic_metadata( "sphinx>=3.1.1", "sphinx_rtd_theme>=1.0.0rc1", "sphinx_markdown_tables", - "myst-nb", + "myst-nb>=1.0.0rc0", + "myst-parser>=0.19.2", "breathe", "exhale", "numpydoc", diff --git a/doc/conf.py b/doc/conf.py index 4aa513d1a7..b17ca82fda 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -298,6 +298,7 @@ def setup(app): "dollarmath", "colon_fence", ] +myst_fence_as_directive = ("math",) # fix emoji issue in pdf latex_engine = "xelatex" latex_elements = { diff --git a/doc/freeze/compress.md b/doc/freeze/compress.md index 696d1377bf..7394f77143 100644 --- a/doc/freeze/compress.md +++ b/doc/freeze/compress.md @@ -1,5 +1,54 @@ # Compress a model +## Theory + +The compression of the DP model uses three techniques, tabulated inference, operator merging, and precise neighbor indexing, to improve the performance of model training and inference when the model parameters are properly trained. + +For better performance, the NN inference can be replaced by tabulated function evaluations if the input of the NN is of dimension one. +The idea is to approximate the output of the NN by a piece-wise polynomial fitting. +The input domain (a compact domain in $\mathbb R$) is divided into $L_c$ equally spaced intervals, in which we apply a fifth-order polynomial $g^l_m(x)$ approximation of the $m$-th output component of the NN function: +```math + g^l_m(x) = a^l_m x^5 + b^l_m x^4 + c^l_m x^3 + d^l_m x^2 + e^l_m x + f^l_m,\quad + x \in [x_l, x_{l+1}), +``` +where $l=1,2,\dots,L_c$ is the index of the intervals, $x_1, \dots, x_{L_c}, x_{L_c+1}$ are the endpoints of the intervals, and $a^l_m$, $b^l_m$, $c^l_m$, $d^l_m$, $e^l_m$, and $f^l_m$ are the fitting parameters. +The fitting parameters can be computed by the equations below: +```math + a^l_m = \frac{1}{2\Delta x_l^5}[12h_{m,l}-6(y'_{m,l+1}+y'_{m,l})\Delta x_l + (y''_{m,l+1}-y''_{m,l})\Delta x_l^2], +``` +```math + b^l_m = \frac{1}{2\Delta x_l^4}[-30h_{m,l} +(14y'_{m,l+1}+16y'_{m,l})\Delta x_l + (-2y''_{m,l+1}+3y''_{m,l})\Delta x_l^2], +``` +```math + c^l_m = \frac{1}{2\Delta x_l^3}[20h_{m,l}-(8y'_{m,l+1}+12y'_{m,l})\Delta x_l + (y''_{m,l+1}-3y''_{m,l})\Delta x_l^2], +``` +```math + d^l_m = \frac{1}{2}y''_{m,l}, +``` +```math + e^l_m = y_{m,l}', +``` +```math + f^l_m = y_{m,l}, +``` +where $\Delta x_l=x_{l+1}-x_l$ denotes the size of the interval. $h_{m,l}=y_{m,l+1}-y_{m,l}$. $y_{m,l} = y_m(x_l)$, $y'_{m,l} = y'_m(x_l)$ and $y''_{m,l} = y''_m(x_l)$ are the value, the first-order derivative, and the second-order derivative of the $m$-th component of the target NN function at the interval point $x_l$, respectively. +The first and second-order derivatives are easily calculated by the back-propagation of the NN functions. + +In the standard DP model inference, taking the [two-body embedding descriptor](../model/train-se-e2-a.md) as an example, the matrix product $(\mathcal G^i)^T \mathcal R$ requires the transfer of the tensor $\mathcal G^i$ between the register and the host/device memories, which usually becomes the bottle-neck of the computation due to the relatively small memory bandwidth of the GPUs. +The compressed DP model merges the matrix multiplication $(\mathcal G^i)^T \mathcal R$ with the tabulated inference step. +More specifically, once one column of the $(\mathcal G^i)^T$ is evaluated, it is immediately multiplied with one row of the environment matrix in the register, and the outer product is deposited to the result of $(\mathcal G^i)^T \mathcal R$. +By the operator merging technique, the allocation of $\mathcal G^i$ and the memory movement between register and host/device memories is avoided. +The operator merging of the three-body embedding can be derived analogously. + +The first dimension, $N_c$, of the environment ($\mathcal R^i$) and embedding ($\mathcal G^i$) matrices is the expected maximum number of neighbors. +If the number of neighbors of an atom is smaller than $N_c$, the corresponding positions of the matrices are pad with zeros. +In practice, if the real number of neighbors is significantly smaller than $N_c$, a notable operation is spent on the multiplication of padding zeros. +In the compressed DP model, the number of neighbors is precisely indexed at the tabulated inference stage, further saving computational costs.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + +## Instructions + Once the frozen model is obtained from DeePMD-kit, we can get the neural network structure and its parameters (weights, biases, etc.) from the trained model, and compress it in the following way: ```bash dp compress -i graph.pb -o graph-compress.pb diff --git a/doc/model/dplr.md b/doc/model/dplr.md index 035c27ee14..feea84e562 100644 --- a/doc/model/dplr.md +++ b/doc/model/dplr.md @@ -6,6 +6,28 @@ The method of DPLR is described in [this paper][1]. One is recommended to read t In the following, we take the DPLR model for example to introduce the training and LAMMPS simulation with the DPLR model. The DPLR model is trained in two steps. +## Theory + +The Deep Potential Long Range (DPLR) model adds the electrostatic energy to the total energy: +```math + E=E_{\text{DP}} + E_{\text{ele}}, +``` +where $E_{\text{DP}}$ is the short-range contribution constructed as the [standard energy model](./train-energy.md) that is fitted against $(E^\ast-E_{\text{ele}})$. +$E_{\text{ele}}$ is the electrostatic energy +introduced by a group of Gaussian distributions that is an approximation of the electronic structure of the system, and is calculated in Fourier space by +```math + E_{\text{ele}} = \frac{1}{2\pi V}\sum_{m \neq 0, \|m\|\leq L} \frac{\exp({-\pi ^2 m^2/\beta ^2})}{m^2}S^2(m), +``` +where $\beta$ is a freely tunable parameter that controls the spread of the Gaussians. +$L$ is the cutoff in Fourier space and $S(m)$, the structure factor, is given by +```math + S(m)=\sum_i q_i e^{-2\pi \imath m \boldsymbol r_i} + \sum_n q_n e^{-2\pi \imath m \boldsymbol W_n}, +``` +where $\imath = \sqrt{-1}$ denotes the imaginary unit, $\boldsymbol r_i$ indicates ion coordinates, $q_i$ is the charge of the ion $i$, and $W_n$ is the $n$-th Wannier centroid (WC) which can be obtained from a separated [dipole model](./train-fitting-tensor.md). +It can be proved that the error in the electrostatic energy introduced by the Gaussian approximations is dominated by a summation of dipole-quadrupole interactions that decay as $r^{-4}$, where $r$ is the distance between the dipole and quadrupole.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + ## Train a deep Wannier model for Wannier centroids We use the deep Wannier model (DW) to represent the relative position of the Wannier centroid (WC) with the atom with which it is associated. One may consult the introduction of the [dipole model](train-fitting-tensor.md) for a detailed introduction. An example input `wc.json` and a small dataset `data` for tutorial purposes can be found in diff --git a/doc/model/dprc.md b/doc/model/dprc.md index 719421108a..c7547a769f 100644 --- a/doc/model/dprc.md +++ b/doc/model/dprc.md @@ -2,7 +2,39 @@ Deep Potential - Range Correction (DPRc) is designed to combine with QM/MM method, and corrects energies from a low-level QM/MM method to a high-level QM/MM method: -$$ E=E_\text{QM}(\mathbf R; \mathbf P) + E_\text{QM/MM}(\mathbf R; \mathbf P) + E_\text{MM}(\mathbf R) + E_\text{DPRc}(\mathbf R) $$ +```math +E=E_\text{QM}(\mathbf R; \mathbf P) + E_\text{QM/MM}(\mathbf R; \mathbf P) + E_\text{MM}(\mathbf R) + E_\text{DPRc}(\mathbf R) +``` + +## Theory + +Deep Potential - Range Correction (DPRc) was initially designed to correct the potential energy from a fast, linear-scaling low-level semiempirical QM/MM theory to a high-level ''ab initio'' QM/MM theory in a range-correction way to quantitatively correct short and mid-range non-bonded interactions leveraging the non-bonded lists routinely used in molecular dynamics simulations using molecular mechanical force fields such as AMBER. +In this way, long-ranged electrostatic interactions can be modeled efficiently using the particle mesh Ewald method or its extensions for multipolar and QM/MM potentials. +In a DPRc model, the switch function is modified to disable MM-MM interaction: +```math + s_\text{DPRc}(r_{ij}) = + \begin{cases} + 0, &\text{if $i \in \text{MM} \land j \in \text{MM}$}, \\ + s(r_{ij}), &\text{otherwise}, + \end{cases} +``` +where $s_\text{DPRc}(r_{ij})$ is the new switch function and $s(r_{ij})$ is the old one. +This ensures the forces between MM atoms are zero, i.e. +```math +{\boldsymbol F}_{ij} = - \frac{\partial E}{\partial \boldsymbol r_{ij}} = 0, \quad i \in \text{MM} \land j \in \text{MM}. +``` +The fitting network is revised to remove energy bias from MM atoms: +```math + E_i= + \begin{cases} + \mathcal{F}_0(\mathcal{D}^i), &\text{if $i \in \text{QM}$}, \\ + \mathcal{F}_0(\mathcal{D}^i) - \mathcal{F}_0(\mathbf{0}), &\text{if $i \in \text{MM}$}, + \end{cases} +``` +where $\mathbf{0}$ is a zero matrix. +It is worth mentioning that usage of DPRc is not limited to its initial design for QM/MM correction and can be expanded to any similar interaction.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). See the [JCTC paper](https://doi.org/10.1021/acs.jctc.1c00201) for details. @@ -10,7 +42,9 @@ See the [JCTC paper](https://doi.org/10.1021/acs.jctc.1c00201) for details. Instead the normal _ab initio_ data, one needs to provide the correction from a low-level QM/MM method to a high-level QM/MM method: -$$ E = E_\text{high-level QM/MM} - E_\text{low-level QM/MM} $$ +```math +E = E_\text{high-level QM/MM} - E_\text{low-level QM/MM} +``` Two levels of data use the same MM method, so $E_\text{MM}$ is eliminated. diff --git a/doc/model/index.md b/doc/model/index.md index 4ef508ec1b..6c128028a6 100644 --- a/doc/model/index.md +++ b/doc/model/index.md @@ -17,3 +17,4 @@ - [Deep potential long-range](dplr.md) - [Deep Potential - Range Correction (DPRc)](dprc.md) - [Linear model](linear.md) +- [Interpolation with a pairwise potential](pairtab.md) diff --git a/doc/model/index.rst b/doc/model/index.rst index 6597ce1d21..1e850cac67 100644 --- a/doc/model/index.rst +++ b/doc/model/index.rst @@ -20,3 +20,4 @@ Model dplr dprc linear + pairtab diff --git a/doc/model/overall.md b/doc/model/overall.md index 3d4052e464..f8fb2fa151 100644 --- a/doc/model/overall.md +++ b/doc/model/overall.md @@ -1,5 +1,31 @@ # Overall +## Theory + +A Deep Potential (DP) model, denoted by $\mathcal{M}$, can be generally represented as + +```math +\boldsymbol y_i = \mathcal M (\boldsymbol x_i, \{\boldsymbol x_j\}_{j\in n(i)}; \boldsymbol \theta) += \mathcal{F} \big( \mathcal{D} (\boldsymbol x_i, \{\boldsymbol x_j\}_{j\in n(i)}; \boldsymbol \theta_d) ; \boldsymbol \theta_f \big), +``` + +where $\boldsymbol{y}_i$ is the fitting properties, $\mathcal{F}$ is the fitting network, $\mathcal{D}$ is the descriptor. +$\boldsymbol{x} = (\boldsymbol r_i, \alpha_i)$, with $\boldsymbol r_i$ being the Cartesian coordinates and $\alpha_i$ being the chemical species, denotes the degrees of freedom of the atom $i$. + +The indices of the neighboring atoms (i.e. atoms within a certain cutoff radius) of atom $i$ are given by the notation $n(i)$. +Note that the Cartesian coordinates can be either under the periodic boundary condition (PBC) or in vacuum (under the open boundary condition). +The network parameters are denoted by $\boldsymbol \theta = \{\boldsymbol \theta_d, \boldsymbol \theta_f\}$, where $\boldsymbol \theta_d$ and $\boldsymbol\theta_f$ yield the network parameters of the descriptor (if any) and those of the fitting network, respectively. +From the above equation, one may compute the global property of the system by +```math + \boldsymbol y = \sum_{i=1}^N \boldsymbol y_i, +``` +where $N$ is the number of atoms in a frame. +For example, if $y_i$ represents the potential energy contribution of atom $i$, then $y$ gives the total potential energy of the frame.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + +## Instructions + A model has two parts, a descriptor that maps atomic configuration to a set of symmetry invariant features, and a fitting net that takes descriptor as input and predicts the atomic contribution to the target physical property. It's defined in the {ref}`model ` section of the `input.json`, for example, ```json "model": { diff --git a/doc/model/pairtab.md b/doc/model/pairtab.md new file mode 100644 index 0000000000..e3f0118f2c --- /dev/null +++ b/doc/model/pairtab.md @@ -0,0 +1,35 @@ +# Interpolation with a pairwise potential + +## Theory +In applications like the radiation damage simulation, the interatomic distance may become too close, so that the DFT calculations fail. +In such cases, the DP model that is an approximation of the DFT potential energy surface is usually replaced by an empirical potential, like the Ziegler-Biersack-Littmark (ZBL) screened nuclear repulsion potential in the radiation damage simulations. +The DeePMD-kit package supports the interpolation between DP and an empirical pairwise potential +```math + E_i = (1-w_i) E_i^{\mathrm{DP}} + w_i (E_i^0 + E_i^{\mathrm{pair}}), +``` +where the $w_i$ is the interpolation weight and the $E_i^{\mathrm{pair}} $ is the atomic contribution due to the pairwise potential $u^{\mathrm{pair}}(r)$, i.e. +```math + E_i^{\mathrm{pair}} = \sum_{j\in n(i)} u^{\mathrm{pair}}(r_{ij}). +``` +The interpolation weight $w_i$ is defined by +```math + w_i = + \begin{cases} + 1, & \sigma_i \lt r_a, \\ + u_i^3 (-6 u_i^2 +15 u_i -10) +1, & r_a \leq \sigma_i \lt r_b, \\ + 0, & \sigma_i \geq r_b, + \end{cases} +``` +where $u_i = (\sigma_i - r_a ) / (r_b - r_a)$. +$E_i^0$ is the atom energy bias. +In the range $[r_a, r_b]$, the DP model smoothly switched off and the pairwise potential smoothly switched on from $r_b$ to $r_a$. The $\sigma_i$ is the softmin of the distance between atom $i$ and its neighbors, +```math + \sigma_i = + \dfrac + {\sum\limits_{j\in n(i)} r_{ij} e^{-r_{ij} / \alpha_s}} + {\sum\limits_{j\in n(i)} e^{-r_{ij} / \alpha_s}}, +``` +where the scale $\alpha_s$ is a tunable scale of the interatomic distance $r_{ij}$. +The pairwise potential $u^{\textrm{pair}}(r)$ is defined by a user-defined table that provides the value of $u^{\textrm{pair}}$ on an evenly discretized grid from 0 to the cutoff distance.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). diff --git a/doc/model/train-energy.md b/doc/model/train-energy.md index af3e4969b3..90e027d7a0 100644 --- a/doc/model/train-energy.md +++ b/doc/model/train-energy.md @@ -2,6 +2,62 @@ In this section, we will take `$deepmd_source_dir/examples/water/se_e2_a/input.json` as an example of the input file. +## Theory + +In the DP model, we let the fitting network $\mathcal{F}_ 0$ maps the descriptor $\mathcal{D}^i$ to a scalar, where the subscript $0$ means that the output is a zero-order tensor (i.e. scalar). The model can then be used to predict the total potential energy of the system by +```math + E = \sum_i E_i = \sum_i \mathcal F_0 (\mathcal D^i), +``` +where the output of the fitting network is treated as the atomic potential energy contribution, i.e. $E_i$. +The output scalar can also be treated as other scalar properties defined on an atom, for example, the partial charge of atom $i$. + +In some cases, atomic-specific or frame-specific parameters, such as electron temperature, may be treated as extra input to the fitting network. +We denote the atomic and frame-specific parameters by $\boldsymbol{P}^i\in \mathbb{R}^{N_p}$ (with $N_p$ being the dimension) and $\boldsymbol{Q}\in \mathbb{R}^{N_q}$ (with $N_q$ being the dimension), respectively. +```math + E_i=\mathcal{F}_0(\{\mathcal{D}^i, \boldsymbol{P}^i, \boldsymbol Q\}). +``` + +The atomic force $\boldsymbol{F}_ {i}$ and the virial tensor $\boldsymbol{\Xi} = (\Xi_{\alpha\beta})$ (if PBC is applied) can be derived from the potential energy $E$: +```math + F_{i,\alpha}=-\frac{\partial E}{\partial r_{i,\alpha}}, +``` +```math + \Xi_{\alpha\beta}=-\sum_{\gamma} \frac{\partial E}{\partial h_{\gamma\alpha}} h_{\gamma\beta}, +``` +where $r_{i,\alpha}$ and $F_{i,\alpha}$ denotes the $\alpha$-th component of the coordinate and force of atom $i$. $h_{\alpha\beta}$ is the $\beta$-th component of the $\alpha$-th basis vector of the simulation region. + +The properties $\eta$ of the energy loss function could be energy $E$, force $\boldsymbol{F}$, virial $\boldsymbol{\Xi}$, relative energy $\Delta E$, or any combination among them, and the loss functions of them are +```math + L_E(\boldsymbol{x};\boldsymbol{\theta})=\frac{1}{N}(E(\boldsymbol{x};\boldsymbol{\theta})-E^*)^2, +``` +```math + L_F(\boldsymbol{x};\boldsymbol{\theta})=\frac{1}{3N}\sum_{k=1}^{N}\sum_{\alpha=1}^3(F_{k,\alpha}(\boldsymbol{x};\boldsymbol{\theta})-F_{k,\alpha}^*)^2, +``` +```math + L_\Xi(\boldsymbol{x};\boldsymbol{\theta})=\frac{1}{9N}\sum_{\alpha,\beta=1}^{3}(\Xi_{\alpha\beta}(\boldsymbol{x};\boldsymbol{\theta})-\Xi_{\alpha\beta}^*)^2, +``` +```math + L_{\Delta E}(\boldsymbol{x};\boldsymbol{\theta})=\frac{1}{N}({\Delta E}(\boldsymbol{x};\boldsymbol{\theta})-{\Delta E}^*)^2, +``` +where $F_{k,\alpha}$ is the $\alpha$-th component of the force on atom $k$, and the superscript $\ast$ indicates the label of the property that should be provided in advance. +Using $N$ ensures that each loss of fitting property is averaged over atomic contributions before they contribute to the total loss by weight. + +If part of atoms is more important than others, for example, certain atoms play an essential role when calculating free energy profiles or kinetic isotope effects, the MSE of atomic forces with prefactors $q_{k}$ can also be used as the loss function: +```math + L_F^p(\mathbf{x};\boldsymbol{\theta})=\frac{1}{3N}\sum_{k=1}^{N} \sum_{\alpha} q_{k} (F_{k,\alpha}(\mathbf{x};\boldsymbol{\theta})-F_{k,\alpha}^*)^2. +``` +The atomic forces with larger prefactors will be fitted more accurately than those in other atoms. + +If some forces are quite large, for example, forces can be greater than 60 eV/Å in high-temperature reactive simulations, one may also prefer the force loss is relative to the magnitude: +```math + L^r_F(\boldsymbol{x};\boldsymbol{\theta})=\frac{1}{3N}\sum_{k=1}^{N}\sum_\alpha \left(\frac{F_{k,\alpha}(\boldsymbol{x};\boldsymbol{\theta})-F_{k,\alpha}^*}{\lvert\boldsymbol{F}^\ast_k\lvert + \nu}\right)^2. +``` +where $\nu$ is a small constant used to protect +an atom where the magnitude of $\boldsymbol{F}^\ast_k$ is small from having a large $L^r_F$. +Benefiting from the relative force loss, small forces can be fitted more accurately.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + ## The fitting network The construction of the fitting net is given by section {ref}`fitting_net ` diff --git a/doc/model/train-fitting-tensor.md b/doc/model/train-fitting-tensor.md index d7c06a25ed..90370adfcf 100644 --- a/doc/model/train-fitting-tensor.md +++ b/doc/model/train-fitting-tensor.md @@ -11,6 +11,40 @@ The training and validation data are also provided our examples. But note that * Similar to the `input.json` used in `ener` mode, training JSON is also divided into {ref}`model `, {ref}`learning_rate `, {ref}`loss ` and {ref}`training `. Most keywords remain the same as `ener` mode, and their meaning can be found [here](train-se-e2-a.md). To fit a tensor, one needs to modify {ref}`model/fitting_net ` and {ref}`loss `. +## Theory + +To represent the first-order tensorial properties (i.e. vector properties), we let the fitting network, denoted by $\mathcal F_{1}$, output an $M$-dimensional vector; then we have the representation, + +```math +(T_i^{(1)})_\alpha = +\frac{1}{N_c} +\sum_{j=1}^{N_c}\sum_{m=1}^M (\mathcal G^i)_{jm} (\mathcal R^i)_{j,\alpha+1} +(\mathcal F_{1}(\mathcal D^i))_m, \ \alpha=1,2,3. +``` +We let the fitting network $\mathcal F_{2}$ output an $M$-dimensional vector, and the second-order tensorial properties (matrix properties) are formulated as +```math +(T_i^{(2)})_{\alpha\beta} = +\frac{1}{N_c^2} +\sum_{j=1}^{N_c}\sum_{k=1}^{N_c}\sum_{m=1}^M +(\mathcal G^i)_{jm} +(\mathcal R^i)_{j,\alpha+1} +(\mathcal R^i)_{k,\beta+1} +(\mathcal G^i)_{km} +(\mathcal F_{2}(\mathcal D^i))_m, +\ \alpha,\beta=1,2,3, +``` + +where $\mathcal{G}^i$ and $\mathcal{R}^i$ can be found in [`se_e2_a`](./train-se-e2-a.md). +Thus, the tensor fitting network requires the descriptor to have the same or similar form as the DeepPot-SE descriptor. +$\mathcal{F}_1$ and $\mathcal F_2$ are the neural network functions. +The total tensor $\boldsymbol{T}$ (total dipole $\boldsymbol{T}^{(1)}$ or total polarizability $\boldsymbol{T}^{(2)}$) is the sum of the atomic tensor: +```math + \boldsymbol{T} = \sum_i \boldsymbol{T}_i. +``` +The tensorial models can be used to calculate IR spectrum and Raman spectrum.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + ## The fitting Network The {ref}`fitting_net ` section tells DP which fitting net to use. diff --git a/doc/model/train-hybrid.md b/doc/model/train-hybrid.md index 37666668c7..58b66f25e0 100644 --- a/doc/model/train-hybrid.md +++ b/doc/model/train-hybrid.md @@ -2,6 +2,23 @@ This descriptor hybridizes multiple descriptors to form a new descriptor. For example, we have a list of descriptors denoted by $\mathcal D_1$, $\mathcal D_2$, ..., $\mathcal D_N$, the hybrid descriptor this the concatenation of the list, i.e. $\mathcal D = (\mathcal D_1, \mathcal D_2, \cdots, \mathcal D_N)$. +## Theory + +A hybrid descriptor $\mathcal{D}^i_\text{hyb}$ concatenates multiple kinds of descriptors into one descriptor: +```math + \mathcal{D}^{i}_\text{hyb} = \{ + \begin{array}{cccc} + \mathcal{D}^{i}_1 & \mathcal{D}^{i}_2 & \cdots & \mathcal{D}^{i}_n + \end{array} + \}. +``` +The list of descriptors can be different types or the same descriptors with different parameters. +This way, one can set the different cutoff radii for different descriptors.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + +## Instructions + To use the descriptor in DeePMD-kit, one firstly set the {ref}`type ` to {ref}`hybrid `, then provide the definitions of the descriptors by the items in the `list`, ```json "descriptor" :{ diff --git a/doc/model/train-se-atten.md b/doc/model/train-se-atten.md index 55bb0458f7..7480ddbc12 100644 --- a/doc/model/train-se-atten.md +++ b/doc/model/train-se-atten.md @@ -8,9 +8,48 @@ Here we propose DPA-1, a Deep Potential model with a novel attention mechanism, See [this paper](https://arxiv.org/abs/2208.08236) for more information. DPA-1 is implemented as a new descriptor `"se_atten"` for model training, which can be used after simply editing the input.json. -## Installation -Follow the [standard installation](../install/install-from-source.md#install-the-python-interface) of Python interface in the DeePMD-kit. -After that, you can smoothly use the DPA-1 model with the following instructions. +## Theory + +Attention-based descriptor $\mathcal{D}^i \in \mathbb{R}^{M \times M_{<}}$, which is proposed in pretrainable DPA-1 model, is given by + +```math + \mathcal{D}^i = \frac{1}{N_c^2}(\hat{\mathcal{G}}^i)^T \mathcal{R}^i (\mathcal{R}^i)^T \hat{\mathcal{G}}^i_<, +``` +where $\hat{\mathcal{G}}^i$ represents the embedding matrix $\mathcal{G}^i$ after additional self-attention mechanism and $\mathcal{R}^i$ is defined by the full case in the [`se_e2_a`](./train-se-e2-a.md). +Note that we obtain $\mathcal{G}^i$ using the type embedding method by default in this descriptor. + +To perform the self-attention mechanism, the queries $\mathcal{Q}^{i,l} \in \mathbb{R}^{N_c\times d_k}$, keys $\mathcal{K}^{i,l} \in \mathbb{R}^{N_c\times d_k}$, and values $\mathcal{V}^{i,l} \in \mathbb{R}^{N_c\times d_v}$ are first obtained: +```math + \left(\mathcal{Q}^{i,l}\right)_{j}=Q_{l}\left(\left(\mathcal{G}^{i,l-1}\right)_{j}\right), +``` +```math + \left(\mathcal{K}^{i,l}\right)_{j}=K_{l}\left(\left(\mathcal{G}^{i,l-1}\right)_{j}\right), +``` +```math + \left(\mathcal{V}^{i,l}\right)_{j}=V_{l}\left(\left(\mathcal{G}^{i,l-1}\right)_{j}\right), +``` +where $Q_{l}$, $K_{l}$, $V_{l}$ represent three trainable linear transformations that output the queries and keys of dimension $d_k$ and values of dimension $d_v$, and $l$ is the index of the attention layer. +The input embedding matrix to the attention layers, denoted by $\mathcal{G}^{i,0}$, is chosen as the two-body embedding matrix. + +Then the scaled dot-product attention method is adopted: +```math +A(\mathcal{Q}^{i,l}, \mathcal{K}^{i,l}, \mathcal{V}^{i,l}, \mathcal{R}^{i,l})=\varphi\left(\mathcal{Q}^{i,l}, \mathcal{K}^{i,l},\mathcal{R}^{i,l}\right)\mathcal{V}^{i,l}, +``` +where $\varphi\left(\mathcal{Q}^{i,l}, \mathcal{K}^{i,l},\mathcal{R}^{i,l}\right) \in \mathbb{R}^{N_c\times N_c}$ is attention weights. +In the original attention method, one typically has $\varphi\left(\mathcal{Q}^{i,l}, \mathcal{K}^{i,l}\right)=\mathrm{softmax}\left(\frac{\mathcal{Q}^{i,l} (\mathcal{K}^{i,l})^{T}}{\sqrt{d_{k}}}\right)$, with $\sqrt{d_{k}}$ being the normalization temperature. +This is slightly modified to incorporate the angular information: +```math +\varphi\left(\mathcal{Q}^{i,l}, \mathcal{K}^{i,l},\mathcal{R}^{i,l}\right) = \mathrm{softmax}\left(\frac{\mathcal{Q}^{i,l} (\mathcal{K}^{i,l})^{T}}{\sqrt{d_{k}}}\right) \odot \hat{\mathcal{R}}^{i}(\hat{\mathcal{R}}^{i})^{T}, +``` +where $\hat{\mathcal{R}}^{i} \in \mathbb{R}^{N_c\times 3}$ denotes normalized relative coordinates , $\hat{\mathcal{R}}^{i}_{j} = \frac{\boldsymbol{r}_{ij}}{\lVert \boldsymbol{r}_{ij} \lVert}$ and $\odot$ means element-wise multiplication. + +Then layer normalization is added in a residual way to finally obtain the self-attention local embedding matrix $\hat{\mathcal{G}}^{i} = \mathcal{G}^{i,L_a}$ after $L_a$ attention layers:[^1] +```math +\mathcal{G}^{i,l} = \mathcal{G}^{i,l-1} + \mathrm{LayerNorm}(A(\mathcal{Q}^{i,l}, \mathcal{K}^{i,l}, \mathcal{V}^{i,l}, \mathcal{R}^{i,l})). +``` + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + ## Introduction to new features of DPA-1 Next, we will list the detailed settings in input.json and the data format, especially for large systems with dozens of elements. An example of DPA-1 input can be found [here](../../examples/water/se_atten/input.json). diff --git a/doc/model/train-se-e2-a-tebd.md b/doc/model/train-se-e2-a-tebd.md index 7528202ff2..cb6ce6674f 100644 --- a/doc/model/train-se-e2-a-tebd.md +++ b/doc/model/train-se-e2-a-tebd.md @@ -4,7 +4,58 @@ We generate specific a type embedding vector for each atom type so that we can s The training input script is similar to that of [`se_e2_a`](train-se-e2-a.md), but different by adding the {ref}`type_embedding ` section. -## Type embedding net +## Theory + +Usually, when the type embedding approach is not enabled, for a system with multiple chemical species ($|\{\alpha_i\}| > 1$), parameters of the embedding network $\mathcal{N}_{e,\{2,3\}}$ are as follows chemical-species-wise: + +```math + (\mathcal{G}^i)_j = \mathcal{N}^{\alpha_i, \alpha_j}_{e,2}(s(r_{ij})) \quad \mathrm{or}\quad + (\mathcal{G}^i)_j = \mathcal{N}^{ \alpha_j}_{e,2}(s(r_{ij})), +``` +```math + (\mathcal{G}^i)_{jk} =\mathcal{N}^{\alpha_j, \alpha_k}_{e,3}((\theta_i)_{jk}). +``` + +Thus, there will be $N_t^2$ or $N_t$ embedding networks where $N_t$ is the number of chemical species. +To improve the performance of matrix operations, $n(i)$ is divided into blocks of different chemical species. +Each matrix with a dimension of $N_c$ is divided into corresponding blocks, and each block is padded to $N_c^{\alpha_j}$ separately. +The limitation of this approach is that when there are large numbers of chemical species, the number of embedding networks will increase, requiring large memory and decreasing computing efficiency. + +Similar to the embedding networks, if the type embedding approach is not used, the fitting network parameters are chemical-species-wise, and there are $N_t$ sets of fitting network parameters. +For performance, atoms are sorted by their chemical species $\alpha_i$ in advance. +Take an example, the atomic energy $E_i$ is represented as follows: +```math +E_i=\mathcal{F}_0^{\alpha_i}(\mathcal{D}^i). +``` + +To reduce the number of NN parameters and improve computing efficiency when there are large numbers of chemical species, +the type embedding $\mathcal{A}$ is introduced, represented as a NN function $\mathcal{N}_t$ of the atomic type $\alpha$: + +```math + \mathcal{A}^i = \mathcal{N}_t\big( \text{one hot}(\alpha_i) \big), +``` + +where $\alpha_i$ is converted to a one-hot vector representing the chemical species before feeding to the NN. +The type embeddings of central and neighboring atoms $\mathcal{A}^i$ and $\mathcal{A}^j$ are added as an extra input of the embedding network $\mathcal{N}_{e,\{2,3\}}$: + +```math + (\mathcal{G}^i)_j = \mathcal{N}_{e,2}(\{s(r_{ij}), \mathcal{A}^i, \mathcal{A}^j\}) \quad \mathrm{or}\quad + (\mathcal{G}^i)_j = \mathcal{N}_{e,2}(\{s(r_{ij}), \mathcal{A}^j\}) , +``` +```math + (\mathcal{G}^i)_{jk} =\mathcal{N}_{e,3}(\{(\theta_i)_{jk}, \mathcal{A}^j, \mathcal{A}^k\}). +``` + +In fitting networks, the type embedding is inserted into the input of the fitting networks: +```math +E_i=\mathcal{F}_0(\{\mathcal{D}^i, \mathcal{A}^i\}). +``` + +In this way, all chemical species share the same network parameters through the type embedding.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + +## Instructions The {ref}`model ` defines how the model is constructed, adding a section of type embedding net: ```json "model": { diff --git a/doc/model/train-se-e2-a.md b/doc/model/train-se-e2-a.md index a043f64716..537253a6d9 100644 --- a/doc/model/train-se-e2-a.md +++ b/doc/model/train-se-e2-a.md @@ -4,6 +4,60 @@ The notation of `se_e2_a` is short for the Deep Potential Smooth Edition (DeepPo Note that it is sometimes called a "two-atom embedding descriptor" which means the input of the embedding net is atomic distances. The descriptor **does** encode multi-body information (both angular and radial information of neighboring atoms). +## Theory + +The two-body embedding smooth edition of the DP descriptor $\mathcal{D}^i \in \mathbb{R}^{M \times M_{<}}$, is usually named DeepPot-SE descriptor. +It is noted that the descriptor is a multi-body representation of the local environment of the atom $i$. +We call it two-body embedding because the embedding network takes only the distance between atoms $i$ and $j$ (see below), but it is not implied that the descriptor takes only the pairwise information between $i$ and its neighbors. +The descriptor, using full information, is given by + +```math + \mathcal{D}^i = \frac{1}{N_c^2} (\mathcal{G}^i)^T \mathcal{R}^i (\mathcal{R}^i)^T \mathcal{G}^i_<, +``` + +where +$N_c$ is the expected maximum number of neighboring atoms, which is the same constant for all atoms over all frames. +A matrix with a dimension of $N_c$ will be padded if the number of neighboring atoms is less than $N_c$. $\mathcal{R}^i \in \mathbb{R}^{N_c \times 4}$ is the coordinate matrix, and each row of $\mathcal{R}^i$ can be constructed as + +```math + (\mathcal{R}^i)_j = + \{ + \begin{array}{cccc} + s(r_{ij}) & \frac{s(r_{ij})x_{ij}}{r_{ij}} & \frac{s(r_{ij})y_{ij}}{r_{ij}} & \frac{s(r_{ij})z_{ij}}{r_{ij}} + \end{array} + \}, +``` + +where $\boldsymbol{r}_{ij}=\boldsymbol{r}_j-\boldsymbol{r}_i = (x_{ij}, y_{ij}, z_{ij})$ is the relative coordinate and $r_{ij}=\lVert \boldsymbol{r}_{ij} \lVert$ is its norm. The switching function $s(r)$ is defined as + +```math + s(r)= + \begin{cases} + \frac{1}{r}, & r \lt r_s, \\ + \frac{1}{r} \big[ x^3 (-6 x^2 +15 x -10) +1 \big], & r_s \leq r \lt r_c, \\ + 0, & r \geq r_c, + \end{cases} +``` + +where $x=\frac{r - r_s}{ r_c - r_s}$ switches from 1 at $r_s$ to 0 at the cutoff radius $r_c$. +The switching function $s(r)$ is smooth in the sense that the second-order derivative is continuous. + +Each row of the embedding matrix $\mathcal{G}^i \in \mathbb{R}^{N_c \times M}$ consists of $M$ nodes from the output layer of an NN function $\mathcal{N}_ {g}$ of $s(r_{ij})$: + +```math + (\mathcal{G}^i)_j = \mathcal{N}_{e,2}(s(r_{ij})), +``` + +where the subscript $e,2$ is used to distinguish the NN from other NNs used in the DP model. +In the above equation, the network parameters are not explicitly written. +$\mathcal{G}^i_< \in \mathbb{R}^{N_c \times M_<}$ only takes first $M_<$ columns of $\mathcal{G}^i$ to reduce the size of $\mathcal D^i$. +$r_s$, $r_c$, $M$ and $M_<$ are hyperparameters provided by the user. +The DeepPot-SE is continuous up to the second-order derivative in its domain.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + +## Instructions + In this example, we will train a DeepPot-SE model for a water system. A complete training input script of this example can be found in the directory. ```bash $deepmd_source_dir/examples/water/se_e2_a/input.json diff --git a/doc/model/train-se-e2-r.md b/doc/model/train-se-e2-r.md index f48e10c17b..f2f990b16a 100644 --- a/doc/model/train-se-e2-r.md +++ b/doc/model/train-se-e2-r.md @@ -2,6 +2,46 @@ The notation of `se_e2_r` is short for the Deep Potential Smooth Edition (DeepPot-SE) constructed from the radial information of atomic configurations. The `e2` stands for the embedding with two-atom information. +## Theory + +The descriptor, using either radial-only information, is given by + +```math + \mathcal{D}^i = \frac{1}{N_c} \sum_j (\mathcal{G}^i)_{jk}, +``` + +where +$N_c$ is the expected maximum number of neighboring atoms, which is the same constant for all atoms over all frames. +A matrix with a dimension of $N_c$ will be padded if the number of neighboring atoms is less than $N_c$. + +Each row of the embedding matrix $\mathcal{G}^i \in \mathbb{R}^{N_c \times M}$ consists of $M$ nodes from the output layer of an NN function $\mathcal{N}_ {g}$ of $s(r_{ij})$: + +```math + (\mathcal{G}^i)_j = \mathcal{N}_{e,2}(s(r_{ij})), +``` + +where $\boldsymbol{r}_ {ij}=\boldsymbol{r}_ j-\boldsymbol{r}_ i = (x_{ij}, y_{ij}, z_{ij})$ is the relative coordinate and $r_{ij}=\lVert \boldsymbol{r}_{ij} \lVert$ is its norm. The switching function $s(r)$ is defined as + +```math + s(r)= + \begin{cases} + \frac{1}{r}, & r \lt r_s, \\ + \frac{1}{r} \big[ x^3 (-6 x^2 +15 x -10) +1 \big], & r_s \leq r \lt r_c, \\ + 0, & r \geq r_c, + \end{cases} +``` + +where $x=\frac{r - r_s}{ r_c - r_s}$ switches from 1 at $r_s$ to 0 at the cutoff radius $r_c$. +The switching function $s(r)$ is smooth in the sense that the second-order derivative is continuous. + +In the above equations, the network parameters are not explicitly written. +$r_s$, $r_c$ and $M$ are hyperparameters provided by the user. +The DeepPot-SE is continuous up to the second-order derivative in its domain.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + +## Instructions + A complete training input script of this example can be found in the directory ```bash $deepmd_source_dir/examples/water/se_e2_r/input.json diff --git a/doc/model/train-se-e3.md b/doc/model/train-se-e3.md index d59f11b264..5b0710a389 100644 --- a/doc/model/train-se-e3.md +++ b/doc/model/train-se-e3.md @@ -1,6 +1,38 @@ # Descriptor `"se_e3"` -The notation of `se_e3` is short for the Deep Potential Smooth Edition (DeepPot-SE) constructed from all information (both angular and radial) of atomic configurations. The embedding takes angles between two neighboring atoms as input (denoted by `e3`). +The notation of `se_e3` is short for the Deep Potential Smooth Edition (DeepPot-SE) constructed from all information (both angular and radial) of atomic configurations. The embedding takes bond angles between a central atom and its two neighboring atoms as input (denoted by `e3`). + +## Theory + +The three-body embedding DeepPot-SE descriptor incorporates bond-angle information, making the model more accurate. The descriptor $\mathcal{D}^i$ can be represented as +```math + \mathcal{D}^i = \frac{1}{N_c^2}(\mathcal{R}^i(\mathcal{R}^i)^T):\mathcal{G}^i, +``` +where +$N_c$ is the expected maximum number of neighboring atoms, which is the same constant for all atoms over all frames. +$\mathcal{R}^i$ is constructed as + +```math + (\mathcal{R}^i)_j = + \{ + \begin{array}{cccc} + s(r_{ij}) & \frac{s(r_{ij})x_{ij}}{r_{ij}} & \frac{s(r_{ij})y_{ij}}{r_{ij}} & \frac{s(r_{ij})z_{ij}}{r_{ij}} + \end{array} + \}, +``` +Currently, only the full information case of $\mathcal{R}^i$ is supported by the three-body embedding. +Each element of $\mathcal{G}^i \in \mathbb{R}^{N_c \times N_c \times M}$ comes from $M$ nodes from the output layer of an NN $\mathcal{N}_{e,3}$ function: + +```math + (\mathcal{G}^i)_{jk}=\mathcal{N}_{e,3}((\theta_i)_{jk}), +``` + +where $(\theta_i)_ {jk} = (\mathcal{R}^i)_ {j,\\{2,3,4\\}}\cdot (\mathcal{R}^i)_ {k,\\{2,3,4\\}}$ considers the angle form of two neighbours ($j$ and $k$). +The notation $:$ in the equation indicates the contraction between matrix $\mathcal{R}^i(\mathcal{R}^i)^T$ and the first two dimensions of tensor $\mathcal{G}^i$.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + +## Instructions A complete training input script of this example can be found in the directory ```bash diff --git a/doc/nvnmd/nvnmd.md b/doc/nvnmd/nvnmd.md index d89afd09e5..7a11e3170e 100644 --- a/doc/nvnmd/nvnmd.md +++ b/doc/nvnmd/nvnmd.md @@ -6,7 +6,7 @@ This is the training code we used to generate the results in our paper entitled Any user can follow two consecutive steps to run molecular dynamics (MD) on the proposed NVNMD computer, which has been released online: (i) to train a machine learning (ML) model that can decently reproduce the potential energy surface (PES); and (ii) to deploy the trained ML model on the proposed NVNMD computer, then run MD there to obtain the atomistic trajectories. -# Training +## Training Our training procedure consists of not only continuous neural network (CNN) training but also quantized neural network (QNN) training which uses the results of CNN as inputs. It is performed on CPU or GPU by using the training codes we open-sourced online. diff --git a/doc/test/model-deviation.md b/doc/test/model-deviation.md index 6a89d7c2f4..a59696c5ee 100644 --- a/doc/test/model-deviation.md +++ b/doc/test/model-deviation.md @@ -1,5 +1,50 @@ # Calculate Model Deviation +## Theory + +Model deviation $\epsilon_y$ is the standard deviation of properties $\boldsymbol y$ inferred by an ensemble of models $\mathcal{M}_ 1, \dots, \mathcal{M}_{n_m}$ that are trained by the same dataset(s) with the model parameters initialized independently. +The DeePMD-kit supports $\boldsymbol y$ to be the atomic force $\boldsymbol F_i$ and the virial tensor $\boldsymbol \Xi$. +The model deviation is used to estimate the error of a model at a certain data frame, denoted by $\boldsymbol x$, containing the coordinates and chemical species of all atoms. +We present the model deviation of the atomic force and the virial tensor +```math + \epsilon_{\boldsymbol{F},i} (\boldsymbol x)= + \sqrt{\langle \lVert \boldsymbol F_i(\boldsymbol x; \boldsymbol \theta_k)-\langle \boldsymbol F_i(\boldsymbol x; \boldsymbol \theta_k) \rangle \rVert^2 \rangle}, +``` +```math + \epsilon_{\boldsymbol{\Xi},{\alpha \beta}} (\boldsymbol x)= + \frac{1}{N} \sqrt{\langle ( {\Xi}_{\alpha \beta}(\boldsymbol x; \boldsymbol \theta_k)-\langle {\Xi}_{\alpha \beta}(\boldsymbol x; \boldsymbol \theta_k) \rangle )^2 \rangle}, +``` +where $\boldsymbol \theta_k$ is the parameters of the model $\mathcal M_k$, and the ensemble average $\langle\cdot\rangle$ is estimated by +```math + \langle \boldsymbol y(\boldsymbol x; \boldsymbol \theta_k) \rangle + = + \frac{1}{n_m} \sum_{k=1}^{n_m} \boldsymbol y(\boldsymbol x; \boldsymbol \theta_k). +``` +Small $\epsilon_{\boldsymbol{F},i}$ means the model has learned the given data; otherwise, it is not covered, and the training data needs to be expanded. +If the magnitude of $\boldsymbol F_i$ or $\boldsymbol \Xi$ is quite large, +a relative model deviation $\epsilon_{\boldsymbol{F},i,\text{rel}}$ or $\epsilon_{\boldsymbol{\Xi},\alpha\beta,\text{rel}}$ can be used instead of the absolute model deviation: +```math + \epsilon_{\boldsymbol{F},i,\text{rel}} (\boldsymbol x) + = + \frac{\lvert \epsilon_{\boldsymbol{F},i} (\boldsymbol x) \lvert} + {\lvert \langle \boldsymbol F_i (\boldsymbol x; \boldsymbol \theta_k) \rangle \lvert + \nu}, +``` +```math + \epsilon_{\boldsymbol{\Xi},\alpha\beta,\text{rel}} (\boldsymbol x) + = + \frac{ \epsilon_{\boldsymbol{\Xi},\alpha\beta} (\boldsymbol x) } + {\lvert \langle \boldsymbol \Xi (\boldsymbol x; \boldsymbol \theta_k) \rangle \lvert + \nu}, +``` +where $\nu$ is a small constant used to protect +an atom where the magnitude of $\boldsymbol{F}_i$ or $\boldsymbol{\Xi}$ is small from having a large model deviation. + +Statistics of $\epsilon_{\boldsymbol{F},i}$ and $\epsilon_{\boldsymbol{\Xi},{\alpha \beta}}$ can be provided, including the maximum, average, and minimal model deviation over the atom index $i$ and over the component index $\alpha,\beta$, respectively. +The maximum model deviation of forces $\epsilon_{\boldsymbol F,\text{max}}$ in a frame was found to be the best error indicator in a concurrent or active learning algorithm.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + +## Instructions + One can also use a subcommand to calculate the deviation of predicted forces or virials for a bunch of models in the following way: ```bash dp model-devi -m graph.000.pb graph.001.pb graph.002.pb graph.003.pb -s ./data -o model_devi.out diff --git a/doc/train/multi-task-training.md b/doc/train/multi-task-training.md index c3cbe98c83..c647e6905e 100644 --- a/doc/train/multi-task-training.md +++ b/doc/train/multi-task-training.md @@ -1,5 +1,22 @@ # Multi-task training +## Theory + +The multi-task training process can simultaneously handle different datasets with properties that cannot be fitted in one network (e.g. properties from DFT calculations under different exchange-correlation functionals or different basis sets). +These datasets are denoted by $\boldsymbol x^{(1)}, \dots, \boldsymbol x^{(n_t)}$. +For each dataset, a training task is defined as +```math + \min_{\boldsymbol \theta} L^{(t)} (\boldsymbol x^{(t)}; \boldsymbol \theta^{(t)}, \tau), \quad t=1, \dots, n_t. +``` + +During the multi-task training process, all tasks share one descriptor with trainable parameters $\boldsymbol{\theta}_ {d}$, while each of them has its own fitting network with trainable parameters $\boldsymbol{\theta}_ f^{(t)}$, thus +$\boldsymbol{\theta}^{(t)} = \{ \boldsymbol{\theta}_ {d} , \boldsymbol{\theta}_ {f}^{(t)} \}$. +At each training step, a task is randomly picked from ${1, \dots, n_t}$, and the Adam optimizer is executed to minimize $L^{(t)}$ for one step to update the parameter $\boldsymbol \theta^{(t)}$. +If different fitting networks have the same architecture, they can share the parameters of some layers +to improve training efficiency.[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + ## Perform the multi-task training Training on multiple data sets (each data set contains several data systems) can be performed in multi-task mode, with one common descriptor and multiple specific fitting nets for each data set. diff --git a/doc/train/training-advanced.md b/doc/train/training-advanced.md index b0194e3471..4940b77fa7 100644 --- a/doc/train/training-advanced.md +++ b/doc/train/training-advanced.md @@ -4,6 +4,23 @@ In this section, we will take `$deepmd_source_dir/examples/water/se_e2_a/input.j ## Learning rate +### Theory + +The learning rate $\gamma$ decays exponentially: +```math + \gamma(\tau) = \gamma^0 r ^ {\lfloor \tau/s \rfloor}, +``` +where $\tau \in \mathbb{N}$ is the index of the training step, $\gamma^0 \in \mathbb{R}$ is the learning rate at the first step, and the decay rate $r$ is given by +```math + r = {\left(\frac{\gamma^{\text{stop}}}{\gamma^0}\right )} ^{\frac{s}{\tau^{\text{stop}}}}, +``` +where $\tau^{\text{stop}} \in \mathbb{N}$, $\gamma^{\text{stop}} \in \mathbb{R}$, and $s \in \mathbb{N}$ are the stopping step, the stopping learning rate, and the decay steps, respectively, all of which are hyperparameters provided in advance. +[^1] + +[^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + +### Instructions + The {ref}`learning_rate ` section in `input.json` is given as follows ```json "learning_rate" :{ @@ -18,10 +35,6 @@ The {ref}`learning_rate ` section in `input.json` is given as fol * {ref}`stop_lr ` gives the learning rate at the end of the training. It should be small enough to ensure that the network parameters satisfactorily converge. * During the training, the learning rate decays exponentially from {ref}`start_lr ` to {ref}`stop_lr ` following the formula: -$$ \alpha(t) = \alpha_0 \lambda ^ { t / \tau } $$ - -where $t$ is the training step, $\alpha$ is the learning rate, $\alpha_0$ is the starting learning rate (set by {ref}`start_lr `), $\lambda$ is the decay rate, and $\tau$ is the decay steps, i.e. - ``` lr(t) = start_lr * decay_rate ^ ( t / decay_steps ) ``` From 9154da26013ecce6297f744919e5771952b2f1b1 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 5 Nov 2023 19:53:05 -0500 Subject: [PATCH 07/97] docs: configuring automatically generated release notes (#2975) See https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes. We shall add proper labels when submitting and merging PRs, so release notes can be more automatic. --------- Signed-off-by: Jinzhe Zeng --- .github/release.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/release.yml diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000000..382e5db00e --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,34 @@ +changelog: + exclude: + authors: + - app/pre-commit-ci + - app/dependabot + categories: + - title: Breaking Changes + labels: + - "breaking change" + - title: New Features + labels: + - "new feature" + - title: Enhancement + labels: + - enhancement + - title: Documentation + labels: + # automatically added + - Docs + # for docs outside the doc directory + - "other docs" + exclude: + labels: + - build + - bug + - title: Build and release + labels: + - build + - title: Bug fixings + labels: + - bug + - title: Other Changes + labels: + - "*" From 574068caadf0acd3a4971a22d1457c8d81d01dd1 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 5 Nov 2023 22:35:13 -0500 Subject: [PATCH 08/97] docs: use relative links (#2976) Signed-off-by: Jinzhe Zeng Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- doc/getting-started/quick_start.ipynb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/getting-started/quick_start.ipynb b/doc/getting-started/quick_start.ipynb index 028e56dc6f..ec939265fd 100644 --- a/doc/getting-started/quick_start.ipynb +++ b/doc/getting-started/quick_start.ipynb @@ -102,8 +102,7 @@ "metadata": {}, "source": [ "## General Introduction\n", - "This tutorial will introduce you to the basic usage of the DeePMD-kit, taking a gas phase methane molecule as an example. [DeePMD-kit's documentation](https://docs.deepmodeling.org/projects/deepmd/ \n", - ") is recommended as the complete reference.\n", + "This tutorial will introduce you to the basic usage of the DeePMD-kit, taking a gas phase methane molecule as an example. [DeePMD-kit's documentation](../index.rst) is recommended as the complete reference.\n", "\n", "The DP model is generated using the DeePMD-kit package (v2.1.5). The training data is converted into the format of DeePMD-kit using a tool named dpdata (v0.2.14). \n", "\n", @@ -129,7 +128,7 @@ "id": "209c5dd7-983a-468e-9406-652ade04be91", "metadata": {}, "source": [ - "Folder `abacus_md` is obtained by performing ab-initio molecular dynamics with ABACUS. Detailed instructions on ABACUS can be found in its [document](https://abacus.deepmodeling.com/en/latest/). " + "Folder `abacus_md` is obtained by performing ab-initio molecular dynamics with ABACUS. Detailed instructions on ABACUS can be found in its [document](https://abacus.deepmodeling.com/). " ] }, { @@ -456,7 +455,7 @@ "id": "7b0edb0f-df47-4e6c-8c37-5f32c4bd6b39", "metadata": {}, "source": [ - "More detailed docs about Data conversion can be found [here](https://docs.deepmodeling.org/projects/deepmd/en/master/data/data-conv.html)." + "More detailed docs about Data conversion can be found [here](../data/data-conv.md)." ] }, { From 7fb94ef06154b77ec0a082ec10b2c7baaf617d74 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 7 Nov 2023 12:05:36 +0800 Subject: [PATCH 09/97] [pre-commit.ci] pre-commit autoupdate (#2978) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.1.3 → v0.1.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.3...v0.1.4) - [github.com/pre-commit/mirrors-clang-format: v17.0.3 → v17.0.4](https://github.com/pre-commit/mirrors-clang-format/compare/v17.0.3...v17.0.4) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ce5cf54d33..245f691ce3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,7 +30,7 @@ repos: exclude: ^source/3rdparty - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.3 + rev: v0.1.4 hooks: - id: ruff args: ["--fix"] @@ -53,7 +53,7 @@ repos: - id: blacken-docs # C++ - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v17.0.3 + rev: v17.0.4 hooks: - id: clang-format exclude: ^source/3rdparty|source/lib/src/gpu/cudart/.+\.inc From ffbdcf89626c0a82701040cfe135fdd8311af2da Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Tue, 7 Nov 2023 00:27:39 -0500 Subject: [PATCH 10/97] respect user defined CUDAARCHS (#2979) Although we set it to `all` by default, one may manually set it via [CMAKE_CUDA_ARCHITECTURES](https://cmake.org/cmake/help/latest/variable/CMAKE_CUDA_ARCHITECTURES.html) or [CUDAARCHS](https://cmake.org/cmake/help/latest/envvar/CUDAARCHS.html#envvar:CUDAARCHS). Signed-off-by: Jinzhe Zeng --- source/lib/src/gpu/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/lib/src/gpu/CMakeLists.txt b/source/lib/src/gpu/CMakeLists.txt index c78da978a2..5eb833e24d 100644 --- a/source/lib/src/gpu/CMakeLists.txt +++ b/source/lib/src/gpu/CMakeLists.txt @@ -5,7 +5,9 @@ if(USE_CUDA_TOOLKIT) project(deepmd_op_cuda) set(GPU_LIB_NAME deepmd_op_cuda) - set(CMAKE_CUDA_ARCHITECTURES all) + if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) + set(CMAKE_CUDA_ARCHITECTURES all) + endif() enable_language(CUDA) set(CMAKE_CUDA_STANDARD 11) add_compile_definitions( From a40dcaa8c5e42f97f7f6976c18a8cb76337b2ef3 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Tue, 7 Nov 2023 00:30:02 -0500 Subject: [PATCH 11/97] lmp: refactor ixnode (#2971) The current implementation used a complex method to ensure `ixnode` (int) within `[0, nxnodes-1]`, but why not use mod ("%") to get the same behavior? --------- Signed-off-by: Jinzhe Zeng --- source/lmp/pair_deepmd.cpp | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/source/lmp/pair_deepmd.cpp b/source/lmp/pair_deepmd.cpp index 432077de5b..600c4cae29 100644 --- a/source/lmp/pair_deepmd.cpp +++ b/source/lmp/pair_deepmd.cpp @@ -339,24 +339,10 @@ void PairDeepMD::make_ttm_aparam(vector &daparam) { int ixnode = static_cast(xscale * nxnodes); int iynode = static_cast(yscale * nynodes); int iznode = static_cast(zscale * nznodes); - while (ixnode > nxnodes - 1) { - ixnode -= nxnodes; - } - while (iynode > nynodes - 1) { - iynode -= nynodes; - } - while (iznode > nznodes - 1) { - iznode -= nznodes; - } - while (ixnode < 0) { - ixnode += nxnodes; - } - while (iynode < 0) { - iynode += nynodes; - } - while (iznode < 0) { - iznode += nznodes; - } + // https://stackoverflow.com/a/1907585/9567349 + ixnode = ((ixnode % nxnodes) + nxnodes) % nxnodes; + iynode = ((iynode % nynodes) + nynodes) % nynodes; + iznode = ((iznode % nznodes) + nznodes) % nznodes; daparam[ii] = T_electron[ixnode][iynode][iznode]; } } From 283e8fe2764d32519d34de8557b7d85181b5ee6c Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 8 Nov 2023 00:19:29 -0500 Subject: [PATCH 12/97] bump scikit-build-core to 0.6 (#2981) Bump scikit-build-core from `>=0.5,<0.6` to `>=0.5,<0.7,!=0.6.0`. (by default it will install 0.6.1) Signed-off-by: Jinzhe Zeng --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 35a11d2163..f8bfbbee79 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ requires = [ # dynamic metadata API is still unstable # TODO: unpin the upper bound when it is stable - "scikit-build-core>=0.5,<0.6", + "scikit-build-core>=0.5,<0.7,!=0.6.0", "packaging", ] build-backend = "backend.dp_backend" From 43fc073a49932e55ab7a40804336c1632fdeacd5 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 8 Nov 2023 20:04:26 -0500 Subject: [PATCH 13/97] rename `deepmd_cli` to `deepmd_utils` (#2983) Preparation for more methods in the `deepmd_utils` package. (`deepmd_cli` is not a good name for this usage) Enable documentation for the `deepmd_utils` package. --------- Signed-off-by: Jinzhe Zeng --- .github/labeler.yml | 2 +- .github/workflows/test_cuda.yml | 2 +- .github/workflows/test_python.yml | 2 +- backend/dynamic_metadata.py | 2 +- codecov.yml | 2 +- deepmd/__init__.py | 2 +- deepmd/entrypoints/main.py | 2 +- deepmd_cli/__init__.py | 6 ------ deepmd_utils/__init__.py | 6 ++++++ {deepmd_cli => deepmd_utils}/main.py | 7 ++++++- doc/conf.py | 3 ++- pyproject.toml | 4 ++-- 12 files changed, 23 insertions(+), 17 deletions(-) delete mode 100644 deepmd_cli/__init__.py create mode 100644 deepmd_utils/__init__.py rename {deepmd_cli => deepmd_utils}/main.py (98%) diff --git a/.github/labeler.yml b/.github/labeler.yml index 195d2cd217..049c9badff 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,6 +1,6 @@ Python: - deepmd/**/* -- deepmd_cli/**/* +- deepmd_utils/**/* - source/tests/**/* Docs: doc/**/* Examples: examples/**/* diff --git a/.github/workflows/test_cuda.yml b/.github/workflows/test_cuda.yml index ca72a32277..5e754226ae 100644 --- a/.github/workflows/test_cuda.yml +++ b/.github/workflows/test_cuda.yml @@ -42,7 +42,7 @@ jobs: DP_VARIANT: cuda CUDA_PATH: /usr/local/cuda-11.8 - run: dp --version - - run: python -m pytest -s --cov=deepmd --cov=deepmd_cli source/tests --durations=0 + - run: python -m pytest -s --cov=deepmd --cov=deepmd_utils source/tests --durations=0 - run: source/install/test_cc_local.sh env: OMP_NUM_THREADS: 1 diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index 0ac29a7d9b..b6011cb523 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -38,7 +38,7 @@ jobs: HOROVOD_WITH_TENSORFLOW: 1 HOROVOD_WITHOUT_GLOO: 1 - run: dp --version - - run: pytest --cov=deepmd --cov=deepmd_cli source/tests --durations=0 + - run: pytest --cov=deepmd --cov=deepmd_utils source/tests --durations=0 - uses: codecov/codecov-action@v3 with: gcov: true diff --git a/backend/dynamic_metadata.py b/backend/dynamic_metadata.py index 59df7dce81..dad9c5b597 100644 --- a/backend/dynamic_metadata.py +++ b/backend/dynamic_metadata.py @@ -27,7 +27,7 @@ def dynamic_metadata( _, _, find_libpython_requires, extra_scripts, tf_version = get_argument_from_env() if field == "scripts": return { - "dp": "deepmd_cli.main:main", + "dp": "deepmd_utils.main:main", **extra_scripts, } elif field == "optional-dependencies": diff --git a/codecov.yml b/codecov.yml index 24dd9e3a23..3654859423 100644 --- a/codecov.yml +++ b/codecov.yml @@ -20,7 +20,7 @@ component_management: name: Python paths: - deepmd/** - - deepmd_cli/** + - deepmd_utils/** - component_id: module_op name: OP paths: diff --git a/deepmd/__init__.py b/deepmd/__init__.py index b02817b6fc..0190bbc124 100644 --- a/deepmd/__init__.py +++ b/deepmd/__init__.py @@ -32,7 +32,7 @@ set_mkl() try: - from deepmd_cli._version import version as __version__ + from deepmd_utils._version import version as __version__ except ImportError: from .__about__ import ( __version__, diff --git a/deepmd/entrypoints/main.py b/deepmd/entrypoints/main.py index 782136b542..2c6ac26a7f 100644 --- a/deepmd/entrypoints/main.py +++ b/deepmd/entrypoints/main.py @@ -32,7 +32,7 @@ from deepmd.nvnmd.entrypoints.train import ( train_nvnmd, ) -from deepmd_cli.main import ( +from deepmd_utils.main import ( get_ll, main_parser, parse_args, diff --git a/deepmd_cli/__init__.py b/deepmd_cli/__init__.py deleted file mode 100644 index d295053965..0000000000 --- a/deepmd_cli/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-later -"""This module contains the entry points for DeePMD-kit. - -If only printing the help message, this module does not call -the main DeePMD-kit module to avoid the slow import of TensorFlow. -""" diff --git a/deepmd_utils/__init__.py b/deepmd_utils/__init__.py new file mode 100644 index 0000000000..1c5314bb7e --- /dev/null +++ b/deepmd_utils/__init__.py @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +"""Untilization methods for DeePMD-kit. + +The __init__ module should not import any modules +for performance. +""" diff --git a/deepmd_cli/main.py b/deepmd_utils/main.py similarity index 98% rename from deepmd_cli/main.py rename to deepmd_utils/main.py index bffc1c6911..3dc54db052 100644 --- a/deepmd_cli/main.py +++ b/deepmd_utils/main.py @@ -1,4 +1,9 @@ # SPDX-License-Identifier: LGPL-3.0-or-later +"""The entry points for DeePMD-kit. + +If only printing the help message, this module does not call +the main DeePMD-kit module to avoid the slow import of TensorFlow. +""" import argparse import logging import textwrap @@ -8,7 +13,7 @@ ) try: - from deepmd_cli._version import version as __version__ + from deepmd_utils._version import version as __version__ except ImportError: __version__ = "unknown" diff --git a/doc/conf.py b/doc/conf.py index b17ca82fda..63af974a86 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -134,7 +134,7 @@ def run_apidoc(_): sys.path.append(os.path.join(os.path.dirname(__file__), "..")) cur_dir = os.path.abspath(os.path.dirname(__file__)) - module = os.path.join(cur_dir, "..", "deepmd") + module = os.path.join(cur_dir, "..") main( [ "-M", @@ -145,6 +145,7 @@ def run_apidoc(_): "-o", os.path.join(cur_dir, "api_py"), module, + "source/*", "--force", ] ) diff --git a/pyproject.toml b/pyproject.toml index f8bfbbee79..4ba3bb81e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,7 +82,7 @@ sdist.exclude = [ ] wheel.packages = [ "deepmd", - "deepmd_cli", + "deepmd_utils", ] wheel.py-api = "py37" build-dir = "build/{wheel_tag}" @@ -102,7 +102,7 @@ provider-path = "backend" provider = "scikit_build_core.metadata.fancy_pypi_readme" [[tool.scikit-build.generate]] -path = "deepmd_cli/_version.py" +path = "deepmd_utils/_version.py" template = ''' version = "${version}" ''' From 4c888d8605910790a508f005202aae293bb0bb53 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 12 Nov 2023 19:41:49 -0500 Subject: [PATCH 14/97] docs: remove lammps.md (#2986) It has been covered by `quick_start.ipynb` or `lammps-command.md`. --- README.md | 3 +-- doc/third-party/index.md | 3 +-- doc/third-party/index.rst | 1 - doc/third-party/lammps-command.md | 2 +- doc/third-party/lammps.md | 9 --------- 5 files changed, 3 insertions(+), 15 deletions(-) delete mode 100644 doc/third-party/lammps.md diff --git a/README.md b/README.md index 680e187012..a1e9c9484a 100644 --- a/README.md +++ b/README.md @@ -135,8 +135,7 @@ A full [document](doc/train/train-input-auto.rst) on options in the training inp - [Node.js interface](doc/inference/nodejs.md) - [Integrate with third-party packages](doc/third-party/index.rst) - [Use deep potential with ASE](doc/third-party/ase.md) - - [Run MD with LAMMPS](doc/third-party/lammps.md) - - [LAMMPS commands](doc/third-party/lammps-command.md) + - [Run MD with LAMMPS](doc/third-party/lammps-command.md) - [Run path-integral MD with i-PI](doc/third-party/ipi.md) - [Run MD with GROMACS](doc/third-party/gromacs.md) - [Interfaces out of DeePMD-kit](doc/third-party/out-of-deepmd-kit.md) diff --git a/doc/third-party/index.md b/doc/third-party/index.md index 3de01d6944..235337974c 100644 --- a/doc/third-party/index.md +++ b/doc/third-party/index.md @@ -3,8 +3,7 @@ Note that the model for inference is required to be compatible with the DeePMD-kit package. See [Model compatibility](../troubleshooting/model-compatability.html) for details. - [Use deep potential with ASE](ase.md) -- [Run MD with LAMMPS](lammps.md) -- [LAMMPS commands](lammps-command.md) +- [Run MD with LAMMPS](lammps-command.md) - [Run path-integral MD with i-PI](ipi.md) - [Run MD with GROMACS](gromacs.md) - [Interfaces out of DeePMD-kit](out-of-deepmd-kit.md) diff --git a/doc/third-party/index.rst b/doc/third-party/index.rst index 678dfc9315..f88a477fc7 100644 --- a/doc/third-party/index.rst +++ b/doc/third-party/index.rst @@ -7,7 +7,6 @@ Note that the model for inference is required to be compatible with the DeePMD-k :maxdepth: 1 ase - lammps lammps-command ipi gromacs diff --git a/doc/third-party/lammps-command.md b/doc/third-party/lammps-command.md index cdfa4b87d6..023345d638 100644 --- a/doc/third-party/lammps-command.md +++ b/doc/third-party/lammps-command.md @@ -1,4 +1,4 @@ -# LAMMPS commands +# Run MD with LAMMPS ## units All units in LAMMPS except `lj` are supported. `lj` is not supported. diff --git a/doc/third-party/lammps.md b/doc/third-party/lammps.md deleted file mode 100644 index 0020db01c5..0000000000 --- a/doc/third-party/lammps.md +++ /dev/null @@ -1,9 +0,0 @@ -# Run MD with LAMMPS - -Running an MD simulation with LAMMPS is simpler. In the LAMMPS input file, one needs to specify the pair style as follows - -```lammps -pair_style deepmd graph.pb -pair_coeff * * O H -``` -where `graph.pb` is the file name of the frozen model. `pair_coeff` maps atom names (`O H`) with LAMMPS atom types (integers from 1 to Ntypes, i.e. `1 2`). From 55d678dcf34f78ab2f1eacbc39d1f4ae78b9c316 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Thu, 16 Nov 2023 00:30:55 -0500 Subject: [PATCH 15/97] bump CUDA version to 12.2 for pre-built packages (#2960) TensorFlow 2.15 bumps the CUDA version to 12.2. See https://github.com/tensorflow/tensorflow/commit/3de44168950a5972ba4cfa7e3c6cbf4cffa67fe6. --------- Signed-off-by: Jinzhe Zeng --- .github/workflows/build_cc.yml | 2 +- .github/workflows/test_cuda.yml | 13 +++++++------ backend/find_tensorflow.py | 9 +++++++++ doc/install/easy-install-dev.md | 4 ++-- doc/install/easy-install.md | 8 ++++---- doc/install/install-from-c-library.md | 2 +- pyproject.toml | 9 ++++----- source/install/docker/Dockerfile | 2 +- source/install/docker_package_c.sh | 2 +- 9 files changed, 30 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build_cc.yml b/.github/workflows/build_cc.yml index 964a11ce37..e6377f4fab 100644 --- a/.github/workflows/build_cc.yml +++ b/.github/workflows/build_cc.yml @@ -37,7 +37,7 @@ jobs: wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.0-1_all.deb \ && sudo dpkg -i cuda-keyring_1.0-1_all.deb \ && sudo apt-get update \ - && sudo apt-get -y install cuda-cudart-dev-12-0 cuda-nvcc-12-0 + && sudo apt-get -y install cuda-cudart-dev-12-2 cuda-nvcc-12-2 if: matrix.variant == 'cuda120' env: DEBIAN_FRONTEND: noninteractive diff --git a/.github/workflows/test_cuda.yml b/.github/workflows/test_cuda.yml index 5e754226ae..d8eddaa44f 100644 --- a/.github/workflows/test_cuda.yml +++ b/.github/workflows/test_cuda.yml @@ -11,7 +11,7 @@ jobs: runs-on: nvidia # https://github.com/deepmodeling/deepmd-kit/pull/2884#issuecomment-1744216845 container: - image: nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04 + image: nvidia/cuda:12.2.0-devel-ubuntu22.04 options: --gpus all if: github.repository_owner == 'deepmodeling' && github.event.label.name == 'Test CUDA' || github.event_name == 'workflow_dispatch' steps: @@ -31,16 +31,17 @@ jobs: wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.0-1_all.deb \ && sudo dpkg -i cuda-keyring_1.0-1_all.deb \ && sudo apt-get update \ - && sudo apt-get -y install cuda-11-8 libcudnn8=8.9.5.*-1+cuda11.8 + && sudo apt-get -y install cuda-12-2 libcudnn8=8.9.5.*-1+cuda12.2 if: false # skip as we use nvidia image - name: Set PyPI mirror for Aliyun cloud machine run: python -m pip config --user set global.index-url https://mirrors.aliyun.com/pypi/simple/ - run: python -m pip install -U "pip>=21.3.1,!=23.0.0" - - run: python -m pip install -v -e .[gpu,test,lmp,cu11] "ase @ https://gitlab.com/ase/ase/-/archive/8c5aa5fd6448c5cfb517a014dccf2b214a9dfa8f/ase-8c5aa5fd6448c5cfb517a014dccf2b214a9dfa8f.tar.gz" + - run: python -m pip install "tensorflow>=2.15.0rc0" + - run: python -m pip install -v -e .[gpu,test,lmp,cu12] "ase @ https://gitlab.com/ase/ase/-/archive/8c5aa5fd6448c5cfb517a014dccf2b214a9dfa8f/ase-8c5aa5fd6448c5cfb517a014dccf2b214a9dfa8f.tar.gz" env: DP_BUILD_TESTING: 1 DP_VARIANT: cuda - CUDA_PATH: /usr/local/cuda-11.8 + CUDA_PATH: /usr/local/cuda-12.2 - run: dp --version - run: python -m pytest -s --cov=deepmd --cov=deepmd_utils source/tests --durations=0 - run: source/install/test_cc_local.sh @@ -52,7 +53,7 @@ jobs: CMAKE_GENERATOR: Ninja DP_VARIANT: cuda DP_USE_MPICH2: 1 - CUDA_PATH: /usr/local/cuda-11.8 + CUDA_PATH: /usr/local/cuda-12.2 - run: | export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/dp_test/lib:$CUDA_PATH/lib64:$LD_LIBRARY_PATH export PATH=$GITHUB_WORKSPACE/dp_test/bin:$PATH @@ -63,7 +64,7 @@ jobs: TF_INTRA_OP_PARALLELISM_THREADS: 1 TF_INTER_OP_PARALLELISM_THREADS: 1 LAMMPS_PLUGIN_PATH: ${{ github.workspace }}/dp_test/lib/deepmd_lmp - CUDA_PATH: /usr/local/cuda-11.8 + CUDA_PATH: /usr/local/cuda-12.2 - uses: codecov/codecov-action@v3 with: gcov: true diff --git a/backend/find_tensorflow.py b/backend/find_tensorflow.py index 6d7ce5087d..fbbe0e56c0 100644 --- a/backend/find_tensorflow.py +++ b/backend/find_tensorflow.py @@ -87,6 +87,13 @@ def find_tensorflow() -> Tuple[Optional[str], List[str]]: # TypeError if submodule_search_locations are None # IndexError if submodule_search_locations is an empty list except (AttributeError, TypeError, IndexError): + if os.environ.get("CIBUILDWHEEL", "0") == "1": + # CUDA 12.2 + requires.extend( + [ + "tensorflow-cpu>=2.15.0rc0; platform_machine=='x86_64' and platform_system == 'Linux'", + ] + ) requires.extend(get_tf_requirement()["cpu"]) # setuptools will re-find tensorflow after installing setup_requires tf_install_dir = None @@ -129,6 +136,8 @@ def get_tf_requirement(tf_version: str = "") -> dict: "cpu": [ "tensorflow-cpu; platform_machine!='aarch64' and (platform_machine!='arm64' or platform_system != 'Darwin')", "tensorflow; platform_machine=='aarch64' or (platform_machine=='arm64' and platform_system == 'Darwin')", + # https://github.com/tensorflow/tensorflow/issues/61830 + "tensorflow-cpu<2.15; platform_system=='Windows'", *extra_requires, ], "gpu": [ diff --git a/doc/install/easy-install-dev.md b/doc/install/easy-install-dev.md index dd943c37af..f3d4fa1a32 100644 --- a/doc/install/easy-install-dev.md +++ b/doc/install/easy-install-dev.md @@ -17,10 +17,10 @@ docker pull ghcr.io/deepmodeling/deepmd-kit:devel Below is an one-line shell command to download the [artifact](https://nightly.link/deepmodeling/deepmd-kit/workflows/build_wheel/devel/artifact.zip) containing wheels and install it with `pip`: ```sh -pip install -U --pre deepmd-kit[gpu,cu11,lmp] --extra-index-url https://deepmodeling.github.io/deepmd-kit/simple +pip install -U --pre deepmd-kit[gpu,cu12,lmp] --extra-index-url https://deepmodeling.github.io/deepmd-kit/simple ``` -`cu11` and `lmp` are optional, which is the same as the stable version. +`cu12` and `lmp` are optional, which is the same as the stable version. ## Download pre-compiled C Library diff --git a/doc/install/easy-install.md b/doc/install/easy-install.md index f033310f8f..7bd632694b 100644 --- a/doc/install/easy-install.md +++ b/doc/install/easy-install.md @@ -84,13 +84,13 @@ docker pull deepmodeling/dpmdkit-rocm:dp2.0.3-rocm4.5.2-tf2.6-lmp29Sep2021 ## Install Python interface with pip -If you have no existing TensorFlow installed, you can use `pip` to install the pre-built package of the Python interface with CUDA 11 supported: +If you have no existing TensorFlow installed, you can use `pip` to install the pre-built package of the Python interface with CUDA 12 supported: ```bash -pip install deepmd-kit[gpu,cu11] +pip install deepmd-kit[gpu,cu12] ``` -`cu11` is required only when CUDA Toolkit and cuDNN were not installed. +`cu12` is required only when CUDA Toolkit and cuDNN were not installed. Or install the CPU version without CUDA supported: ```bash @@ -99,7 +99,7 @@ pip install deepmd-kit[cpu] [The LAMMPS module](../third-party/lammps-command.md) and [the i-Pi driver](../third-party/ipi.md) are only provided on Linux and macOS. To install LAMMPS and/or i-Pi, add `lmp` and/or `ipi` to extras: ```bash -pip install deepmd-kit[gpu,cu11,lmp,ipi] +pip install deepmd-kit[gpu,cu12,lmp,ipi] ``` MPICH is required for parallel running. (The macOS arm64 package doesn't support MPI yet.) diff --git a/doc/install/install-from-c-library.md b/doc/install/install-from-c-library.md index 343446888c..04b71234db 100644 --- a/doc/install/install-from-c-library.md +++ b/doc/install/install-from-c-library.md @@ -2,7 +2,7 @@ DeePMD-kit provides pre-compiled C library package (`libdeepmd_c.tar.gz`) in each [release](https://github.com/deepmodeling/deepmd-kit/releases). It can be used to build the [LAMMPS plugin](./install-lammps.md) and [GROMACS patch](./install-gromacs.md), as well as many [third-party software packages](../third-party/out-of-deepmd-kit.md), without building TensorFlow and DeePMD-kit on one's own. -The library is built in Linux (GLIBC 2.17) with CUDA 11.8. It's noted that this package does not contain CUDA Toolkit and cuDNN, so one needs to download them from the NVIDIA website. +The library is built in Linux (GLIBC 2.17) with CUDA 12.2. It's noted that this package does not contain CUDA Toolkit and cuDNN, so one needs to download them from the NVIDIA website. ## Use Pre-compiled C Library to build the LAMMPS plugin and GROMACS patch diff --git a/pyproject.toml b/pyproject.toml index 4ba3bb81e1..e9ee563960 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ classifiers = [ "Programming Language :: C", "Programming Language :: C++", "Programming Language :: Python :: 3 :: Only", - "Environment :: GPU :: NVIDIA CUDA :: 11.8", + "Environment :: GPU :: NVIDIA CUDA :: 12 :: 12.2", "Intended Audience :: Science/Research", "Programming Language :: Python :: 3.7", "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", @@ -133,9 +133,8 @@ test-command = [ test-extras = ["cpu", "test", "lmp", "ipi"] build = ["cp310-*"] skip = ["*-win32", "*-manylinux_i686", "*-musllinux*"] -# TODO: bump to "latest" tag when CUDA supports GCC 12 -manylinux-x86_64-image = "quay.io/pypa/manylinux_2_28_x86_64:2022-11-19-1b19e81" -manylinux-aarch64-image = "quay.io/pypa/manylinux_2_28_aarch64:2022-11-19-1b19e81" +manylinux-x86_64-image = "manylinux_2_28" +manylinux-aarch64-image = "manylinux_2_28" [tool.cibuildwheel.macos] environment = { PIP_PREFER_BINARY="1", DP_LAMMPS_VERSION="stable_2Aug2023_update1", DP_ENABLE_IPI="1" } @@ -152,7 +151,7 @@ repair-wheel-command = "auditwheel repair --exclude libtensorflow_framework.so.2 environment-pass = ["CIBW_BUILD", "DP_VARIANT"] environment = { PIP_PREFER_BINARY="1", DP_LAMMPS_VERSION="stable_2Aug2023_update1", DP_ENABLE_IPI="1", MPI_HOME="/usr/lib64/mpich", PATH="/usr/lib64/mpich/bin:$PATH" } before-all = [ - """{ if [ "$(uname -m)" = "x86_64" ] ; then yum config-manager --add-repo http://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/cuda-rhel8.repo && yum install -y cuda-nvcc-11-8 cuda-cudart-devel-11-8; fi }""", + """{ if [ "$(uname -m)" = "x86_64" ] ; then yum config-manager --add-repo http://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/cuda-rhel8.repo && yum install -y cuda-nvcc-12-2 cuda-cudart-devel-12-2; fi }""", "yum install -y mpich-devel", ] diff --git a/source/install/docker/Dockerfile b/source/install/docker/Dockerfile index c5fa878e2a..9ac905dcd0 100644 --- a/source/install/docker/Dockerfile +++ b/source/install/docker/Dockerfile @@ -4,7 +4,7 @@ RUN python -m venv /opt/deepmd-kit ENV PATH="/opt/deepmd-kit/bin:$PATH" # Install package COPY dist /dist -RUN pip install "$(ls /dist/deepmd_kit-*manylinux*_x86_64.whl)[gpu,cu11,lmp,ipi]" \ +RUN pip install "$(ls /dist/deepmd_kit-*manylinux*_x86_64.whl)[gpu,cu12,lmp,ipi]" \ && dp -h \ && lmp -h \ && dp_ipi \ diff --git a/source/install/docker_package_c.sh b/source/install/docker_package_c.sh index d6fb269acd..75f2d1138b 100755 --- a/source/install/docker_package_c.sh +++ b/source/install/docker_package_c.sh @@ -3,7 +3,7 @@ set -e SCRIPT_PATH=$(dirname $(realpath -s $0)) docker run --rm -v ${SCRIPT_PATH}/../..:/root/deepmd-kit -w /root/deepmd-kit \ - tensorflow/build:2.13-python3.11 \ + tensorflow/build:2.15-python3.11 \ /bin/sh -c "pip install tensorflow cmake \ && cd /root/deepmd-kit/source/install \ && CC=/dt9/usr/bin/gcc \ From 6e9a57548b2949cb04542be94059cfc8c992116f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 17 Nov 2023 17:32:49 -0500 Subject: [PATCH 16/97] [pre-commit.ci] pre-commit autoupdate (#2990) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.1.4 → v0.1.5](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.4...v0.1.5) - [github.com/scop/pre-commit-shfmt: v3.7.0-1 → v3.7.0-2](https://github.com/scop/pre-commit-shfmt/compare/v3.7.0-1...v3.7.0-2) --------- Signed-off-by: Jinzhe Zeng Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Jinzhe Zeng --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 245f691ce3..8a8e98cac7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,7 +30,7 @@ repos: exclude: ^source/3rdparty - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.4 + rev: v0.1.5 hooks: - id: ruff args: ["--fix"] @@ -64,9 +64,9 @@ repos: - id: csslint # Shell - repo: https://github.com/scop/pre-commit-shfmt - rev: v3.7.0-1 + rev: v3.7.0-3 hooks: - - id: shfmt + - id: shfmt-src # CMake - repo: https://github.com/cheshirekow/cmake-format-precommit rev: v0.6.13 From 87d9ffbc2d80c48119b54d05d3c33be87bd77505 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 19 Nov 2023 19:50:10 -0500 Subject: [PATCH 17/97] add unit tests for LAMMPS fparam/aparam keywords (#2998) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- source/lmp/tests/test_lammps_faparam.py | 223 ++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 source/lmp/tests/test_lammps_faparam.py diff --git a/source/lmp/tests/test_lammps_faparam.py b/source/lmp/tests/test_lammps_faparam.py new file mode 100644 index 0000000000..064928eeb1 --- /dev/null +++ b/source/lmp/tests/test_lammps_faparam.py @@ -0,0 +1,223 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +"""Test LAMMPS fparam and aparam input.""" +import os +import subprocess as sp +import sys +from pathlib import ( + Path, +) + +import constants +import numpy as np +import pytest +from lammps import ( + PyLammps, +) +from write_lmp_data import ( + write_lmp_data, +) + +pbtxt_file = ( + Path(__file__).parent.parent.parent / "tests" / "infer" / "fparam_aparam.pbtxt" +) +pb_file = Path(__file__).parent / "fparam_aparam.pb" +system_file = Path(__file__).parent.parent.parent / "tests" +data_file = Path(__file__).parent / "data.lmp" +md_file = Path(__file__).parent / "md.out" + +# from api_cc/tests/test_deeppot_a_fparam_aparam.cc +expected_ae = np.array( + [ + -1.038271183039953804e-01, + -7.285433575272914908e-02, + -9.467600174099155552e-02, + -1.467050086239614082e-01, + -7.660561620618722145e-02, + -7.277295998502930630e-02, + ] +) +expected_e = np.sum(expected_ae) +expected_f = np.array( + [ + 6.622266817497907132e-02, + 5.278739055693523058e-02, + 2.265727495541422845e-02, + -2.606047850915838363e-02, + -4.538811686410718776e-02, + 1.058247569147072187e-02, + 1.679392490937766935e-01, + -2.257828022687320690e-03, + -4.490145670355452645e-02, + -1.148364103573685929e-01, + -1.169790466695089237e-02, + 6.140402504113953025e-02, + -8.078778132132799494e-02, + -5.838878056243369807e-02, + 6.773639989682191109e-02, + -1.247724708090079161e-02, + 6.494523955924384750e-02, + -1.174787188812918687e-01, + ] +).reshape(6, 3) + +expected_v = -np.array( + [ + -1.589185553287162656e-01, + 2.586163333170100279e-03, + -1.575127933809472624e-04, + -1.855360380105876630e-02, + 1.949822090859933826e-02, + -1.006552056166355388e-02, + 3.177029853276916449e-02, + 1.714349636720383010e-03, + -1.290389175187874483e-03, + -8.553510339477603253e-02, + -5.654637257232508415e-03, + -1.286954833787038420e-02, + 2.464156457499515687e-02, + -2.398202886026797043e-02, + -1.957110465239037672e-02, + 2.233492928605742764e-02, + 6.107843207824020099e-03, + 1.707078295947736047e-03, + -1.653994088976195043e-01, + 3.894358678172111371e-02, + -2.169595969759342477e-02, + 6.819704294738503786e-03, + -5.018242039618424008e-03, + 2.640664428663210429e-03, + -1.985298275686078057e-03, + -3.638421609610945767e-02, + 2.342932331075030239e-02, + -8.501331914753691710e-02, + -2.181253413538992297e-03, + 4.311300069651782287e-03, + -1.910329328333908129e-03, + -1.808810159508548836e-03, + -1.540075281450827612e-03, + -1.173703213175551763e-02, + -2.596306629910121507e-03, + 6.705025662372287101e-03, + -9.038455005073858795e-02, + 3.011717773578577451e-02, + -5.083054073419784880e-02, + -2.951210292616929069e-03, + 2.342445652898489383e-02, + -4.091207474993674431e-02, + -1.648470649301832236e-02, + -2.872261885460645689e-02, + 4.763924972552112391e-02, + -8.300036532764677732e-02, + 1.020429228955421243e-03, + -1.026734151199098881e-03, + 5.678534096113684732e-02, + 1.273635718045938205e-02, + -1.530143225195957322e-02, + -1.061671865629566225e-01, + -2.486859433265622629e-02, + 2.875323131744185121e-02, + ] +).reshape(6, 9) + +box = np.array([0, 13, 0, 13, 0, 13, 0, 0, 0]) +coord = np.array( + [ + [12.83, 2.56, 2.18], + [12.09, 2.87, 2.74], + [0.25, 3.32, 1.68], + [3.36, 3.00, 1.81], + [3.51, 2.51, 2.60], + [4.27, 3.22, 1.56], + ] +) +type_OH = np.array([1, 1, 1, 1, 1, 1]) + + +sp.check_output( + "{} -m deepmd convert-from pbtxt -i {} -o {}".format( + sys.executable, + pbtxt_file.resolve(), + pb_file.resolve(), + ).split() +) + + +def setup_module(): + write_lmp_data(box, coord, type_OH, data_file) + + +def teardown_module(): + os.remove(data_file) + + +def _lammps(data_file, units="metal") -> PyLammps: + lammps = PyLammps() + lammps.units(units) + lammps.boundary("p p p") + lammps.atom_style("atomic") + if units == "metal" or units == "real": + lammps.neighbor("2.0 bin") + elif units == "si": + lammps.neighbor("2.0e-10 bin") + else: + raise ValueError("units should be metal, real, or si") + lammps.neigh_modify("every 10 delay 0 check no") + lammps.read_data(data_file.resolve()) + if units == "metal" or units == "real": + lammps.mass("1 16") + elif units == "si": + lammps.mass("1 %.10e" % (16 * constants.mass_metal2si)) + else: + raise ValueError("units should be metal, real, or si") + if units == "metal": + lammps.timestep(0.0005) + elif units == "real": + lammps.timestep(0.5) + elif units == "si": + lammps.timestep(5e-16) + else: + raise ValueError("units should be metal, real, or si") + lammps.fix("1 all nve") + return lammps + + +@pytest.fixture +def lammps(): + lmp = _lammps(data_file=data_file) + yield lmp + lmp.close() + + +def test_pair_deepmd(lammps): + lammps.pair_style(f"deepmd {pb_file.resolve()} fparam 0.25852028 aparam 0.25852028") + lammps.pair_coeff("* *") + lammps.run(0) + assert lammps.eval("pe") == pytest.approx(expected_e) + for ii in range(6): + assert lammps.atoms[ii].force == pytest.approx( + expected_f[lammps.atoms[ii].id - 1] + ) + lammps.run(1) + + +def test_pair_deepmd_virial(lammps): + lammps.pair_style(f"deepmd {pb_file.resolve()} fparam 0.25852028 aparam 0.25852028") + lammps.pair_coeff("* *") + lammps.compute("virial all centroid/stress/atom NULL pair") + for ii in range(9): + jj = [0, 4, 8, 3, 6, 7, 1, 2, 5][ii] + lammps.variable(f"virial{jj} atom c_virial[{ii+1}]") + lammps.dump( + "1 all custom 1 dump id " + " ".join([f"v_virial{ii}" for ii in range(9)]) + ) + lammps.run(0) + assert lammps.eval("pe") == pytest.approx(expected_e) + for ii in range(6): + assert lammps.atoms[ii].force == pytest.approx( + expected_f[lammps.atoms[ii].id - 1] + ) + idx_map = lammps.lmp.numpy.extract_atom("id") - 1 + for ii in range(9): + assert np.array( + lammps.variables[f"virial{ii}"].value + ) / constants.nktv2p == pytest.approx(expected_v[idx_map, ii]) From a342e94b4f71824e0a66b220646eec0643ad2b67 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 19 Nov 2023 19:51:02 -0500 Subject: [PATCH 18/97] fix restarting from compressed training with type embedding (#2996) Fix #2989. --------- Signed-off-by: Jinzhe Zeng --- deepmd/model/dos.py | 4 +- deepmd/model/ener.py | 4 +- deepmd/model/model.py | 54 ++++++++++++++++++++ deepmd/model/multi.py | 4 +- deepmd/model/pairwise_dprc.py | 4 +- deepmd/model/tensor.py | 4 +- deepmd/utils/type_embed.py | 8 +-- source/tests/test_compressed_training.py | 63 ++++++++++++++++++++++++ 8 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 source/tests/test_compressed_training.py diff --git a/deepmd/model/dos.py b/deepmd/model/dos.py index 697fad9a9e..22e291a0f0 100644 --- a/deepmd/model/dos.py +++ b/deepmd/model/dos.py @@ -155,10 +155,12 @@ def build( # type embedding if any if self.typeebd is not None: - type_embedding = self.typeebd.build( + type_embedding = self.build_type_embedding( self.ntypes, reuse=reuse, suffix=suffix, + frz_model=frz_model, + ckpt_meta=ckpt_meta, ) input_dict["type_embedding"] = type_embedding input_dict["atype"] = atype_ diff --git a/deepmd/model/ener.py b/deepmd/model/ener.py index 1976c1ad51..0d8d66b305 100644 --- a/deepmd/model/ener.py +++ b/deepmd/model/ener.py @@ -203,10 +203,12 @@ def build( # type embedding if any if self.typeebd is not None and "type_embedding" not in input_dict: - type_embedding = self.typeebd.build( + type_embedding = self.build_type_embedding( self.ntypes, reuse=reuse, suffix=suffix, + ckpt_meta=ckpt_meta, + frz_model=frz_model, ) input_dict["type_embedding"] = type_embedding # spin if any diff --git a/deepmd/model/model.py b/deepmd/model/model.py index 3f24e42aec..dd439056b4 100644 --- a/deepmd/model/model.py +++ b/deepmd/model/model.py @@ -331,6 +331,60 @@ def build_descrpt( self.descrpt.pass_tensors_from_frz_model(*imported_tensors[:-1]) return dout + def build_type_embedding( + self, + ntypes: int, + frz_model: Optional[str] = None, + ckpt_meta: Optional[str] = None, + suffix: str = "", + reuse: Optional[Union[bool, Enum]] = None, + ) -> tf.Tensor: + """Build the type embedding part of the model. + + Parameters + ---------- + ntypes : int + The number of types + frz_model : str, optional + The path to the frozen model + ckpt_meta : str, optional + The path prefix of the checkpoint and meta files + suffix : str, optional + The suffix of the scope + reuse : bool or tf.AUTO_REUSE, optional + Whether to reuse the variables + + Returns + ------- + tf.Tensor + The type embedding tensor + """ + assert self.typeebd is not None + if frz_model is None and ckpt_meta is None: + dout = self.typeebd.build( + ntypes, + reuse=reuse, + suffix=suffix, + ) + else: + # nothing input + feed_dict = {} + return_elements = [ + f"t_typeebd{suffix}:0", + ] + if frz_model is not None: + imported_tensors = self._import_graph_def_from_frz_model( + frz_model, feed_dict, return_elements + ) + elif ckpt_meta is not None: + imported_tensors = self._import_graph_def_from_ckpt_meta( + ckpt_meta, feed_dict, return_elements + ) + else: + raise RuntimeError("should not reach here") # pragma: no cover + dout = imported_tensors[-1] + return dout + def _import_graph_def_from_frz_model( self, frz_model: str, feed_dict: dict, return_elements: List[str] ): diff --git a/deepmd/model/multi.py b/deepmd/model/multi.py index bfc67b9792..83b231c0e8 100644 --- a/deepmd/model/multi.py +++ b/deepmd/model/multi.py @@ -317,10 +317,12 @@ def build( # type embedding if any if self.typeebd is not None: - type_embedding = self.typeebd.build( + type_embedding = self.build_type_embedding( self.ntypes, reuse=reuse, suffix=suffix, + frz_model=frz_model, + ckpt_meta=ckpt_meta, ) input_dict["type_embedding"] = type_embedding input_dict["atype"] = atype_ diff --git a/deepmd/model/pairwise_dprc.py b/deepmd/model/pairwise_dprc.py index 6983a31cfd..f74571febb 100644 --- a/deepmd/model/pairwise_dprc.py +++ b/deepmd/model/pairwise_dprc.py @@ -173,10 +173,12 @@ def build( atype_qmmm = gather_placeholder(atype_qmmm, forward_qmmm_map, placeholder=-1) box_qm = box - type_embedding = self.typeebd.build( + type_embedding = self.build_type_embedding( self.ntypes, reuse=reuse, suffix=suffix, + frz_model=frz_model, + ckpt_meta=ckpt_meta, ) input_dict_qm["type_embedding"] = type_embedding input_dict_qmmm["type_embedding"] = type_embedding diff --git a/deepmd/model/tensor.py b/deepmd/model/tensor.py index 9099b753a4..6a21e085f3 100644 --- a/deepmd/model/tensor.py +++ b/deepmd/model/tensor.py @@ -135,10 +135,12 @@ def build( # type embedding if any if self.typeebd is not None: - type_embedding = self.typeebd.build( + type_embedding = self.build_type_embedding( self.ntypes, reuse=reuse, suffix=suffix, + ckpt_meta=ckpt_meta, + frz_model=frz_model, ) input_dict["type_embedding"] = type_embedding input_dict["atype"] = atype_ diff --git a/deepmd/utils/type_embed.py b/deepmd/utils/type_embed.py index aadbb3c6e0..c8ab01f7f5 100644 --- a/deepmd/utils/type_embed.py +++ b/deepmd/utils/type_embed.py @@ -16,7 +16,6 @@ nvnmd_cfg, ) from deepmd.utils.graph import ( - get_tensor_by_name_from_graph, get_type_embedding_net_variables_from_graph_def, ) from deepmd.utils.network import ( @@ -109,7 +108,6 @@ def __init__( self.trainable = trainable self.uniform_seed = uniform_seed self.type_embedding_net_variables = None - self.type_embedding_from_graph = None self.padding = padding self.model_type = None @@ -135,8 +133,6 @@ def build( embedded_types The computational graph for embedded types """ - if self.model_type is not None and self.model_type == "compressed_model": - return self.type_embedding_from_graph types = tf.convert_to_tensor(list(range(ntypes)), dtype=tf.int32) ebd_type = tf.cast( tf.one_hot(tf.cast(types, dtype=tf.int32), int(ntypes)), @@ -166,7 +162,7 @@ def build( if self.padding: last_type = tf.cast(tf.zeros([1, self.neuron[-1]]), self.filter_precision) ebd_type = tf.concat([ebd_type, last_type], 0) # (ntypes + 1) * neuron[-1] - self.ebd_type = tf.identity(ebd_type, name="t_typeebd") + self.ebd_type = tf.identity(ebd_type, name="t_typeebd" + suffix) return self.ebd_type def init_variables( @@ -193,5 +189,3 @@ def init_variables( self.type_embedding_net_variables = ( get_type_embedding_net_variables_from_graph_def(graph_def, suffix=suffix) ) - type_embedding = get_tensor_by_name_from_graph(graph, "t_typeebd") - self.type_embedding_from_graph = tf.convert_to_tensor(type_embedding) diff --git a/source/tests/test_compressed_training.py b/source/tests/test_compressed_training.py new file mode 100644 index 0000000000..0a0bbeaadf --- /dev/null +++ b/source/tests/test_compressed_training.py @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +import json +import os +import unittest + +# from deepmd.entrypoints.compress import compress +from common import ( + j_loader, + run_dp, + tests_path, +) +from packaging.version import parse as parse_version + +from deepmd.env import ( + tf, +) + + +@unittest.skipIf( + parse_version(tf.__version__) < parse_version("2"), + f"The current tf version {tf.__version__} is too low to run the new testing model.", +) +class TestCompressedTrainingSeAtten(unittest.TestCase): + def setUp(self) -> None: + data_file = str(tests_path / os.path.join("model_compression", "data")) + self.input_file = str(tests_path / "input.json") + self.frozen_model = str(tests_path / "dp-compress-training-original.pb") + self.compressed_model = str(tests_path / "dp-compress-training-compressed.pb") + self.frozen_compress_training_model = str( + tests_path / "dp-compress-training-compress-training.pb" + ) + self.ckpt_file = str(tests_path / "dp-compress-training.ckpt") + self.checkpoint_dir = str(tests_path) + jdata = j_loader( + str(tests_path / os.path.join("model_compression", "input.json")) + ) + jdata["model"]["descriptor"] = {} + jdata["model"]["descriptor"]["type"] = "se_atten_v2" + jdata["model"]["descriptor"]["sel"] = 20 + jdata["model"]["descriptor"]["attn_layer"] = 0 + jdata["training"]["training_data"]["systems"] = data_file + jdata["training"]["validation_data"]["systems"] = data_file + jdata["training"]["save_ckpt"] = self.ckpt_file + with open(self.input_file, "w") as fp: + json.dump(jdata, fp, indent=4) + + def test_compressed_training(self): + run_dp(f"dp train {self.input_file}") + run_dp(f"dp freeze -c {self.checkpoint_dir} -o {self.frozen_model}") + run_dp(f"dp compress -i {self.frozen_model} -o {self.compressed_model}") + # compress training + run_dp(f"dp train {self.input_file} -f {self.compressed_model}") + # restart compress training + run_dp(f"dp train {self.input_file} -r {self.ckpt_file}") + # freeze compress training + run_dp( + f"dp freeze -c {self.checkpoint_dir} -o {self.frozen_compress_training_model}" + ) + # it should not be able to compress again + with self.assertRaises(RuntimeError): + run_dp( + f"dp compress -i {self.frozen_compress_training_model} -o {self.compressed_model}" + ) From af6eb43053655397116ab4e14c35dd1334501576 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Nov 2023 09:54:03 +0800 Subject: [PATCH 19/97] Bump docker/build-push-action from 5.0.0 to 5.1.0 (#2999) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5.0.0 to 5.1.0.
Release notes

Sourced from docker/build-push-action's releases.

v5.1.0

Full Changelog: https://github.com/docker/build-push-action/compare/v5.0.0...v5.1.0

Commits
  • 4a13e50 Merge pull request #1006 from docker/dependabot/npm_and_yarn/docker/actions-t...
  • 7416668 chore: update generated content
  • b4f76a5 chore(deps): Bump @​docker/actions-toolkit from 0.13.0 to 0.14.0
  • b7feb76 Merge pull request #1005 from crazy-max/ci-inspect
  • fae8018 ci: inspect sbom and provenance
  • b625868 Merge pull request #1004 from crazy-max/ci-update-buildx
  • 5193ef1 ci: update buildx to latest
  • d3afd77 Merge pull request #991 from docker/dependabot/npm_and_yarn/babel/traverse-7....
  • 7a786bb Merge pull request #992 from crazy-max/annotations
  • c66ae3a chore: update generated content
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/build-push-action&package-manager=github_actions&previous-version=5.0.0&new-version=5.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_wheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 84c8ac4b74..2ff3ade215 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -129,7 +129,7 @@ jobs: images: ghcr.io/deepmodeling/deepmd-kit - name: Build and push Docker image - uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 + uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 with: context: source/install/docker push: ${{ github.repository_owner == 'deepmodeling' && github.event_name == 'push' }} From 66259b18437715f12e58967e43226236e69f0bbc Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 20 Nov 2023 21:07:07 -0500 Subject: [PATCH 20/97] docs: document horovod on Conda-Forge (#3001) Recently I contributed Horovod to conda-forge at https://github.com/conda-forge/staged-recipes/pull/24472. I have tested it with DeePMD-kit. Now the Conda-forge channel has all the features in our deepmodeling channel and even more available platforms. I wonder if we should recommend Conda-forge in favor of our DeepModeling channel and use it for the offline installer. In 2019, Conda-forge lacked support for TensorFlow, so we hosted and built our own channel against the Anaconda channel. But now Conda-forge has become a mature channel and has better support for TensorFlow than the Anaconda channel. Signed-off-by: Jinzhe Zeng --- doc/install/easy-install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/easy-install.md b/doc/install/easy-install.md index 7bd632694b..741ef632a8 100644 --- a/doc/install/easy-install.md +++ b/doc/install/easy-install.md @@ -58,7 +58,7 @@ conda activate deepmd DeePMD-kit is also available on the [conda-forge](https://conda-forge.org/) channel: ```bash -conda create -n deepmd deepmd-kit lammps -c conda-forge +conda create -n deepmd deepmd-kit lammps horovod -c conda-forge ``` The supported platform includes Linux x86-64, macOS x86-64, and macOS arm64. From 4d1c5fd4d11d0efe5fa645477e4970d050fda3bd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:07:28 +0800 Subject: [PATCH 21/97] [pre-commit.ci] pre-commit autoupdate (#3000) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.1.5 → v0.1.6](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.5...v0.1.6) - [github.com/pre-commit/mirrors-clang-format: v17.0.4 → v17.0.5](https://github.com/pre-commit/mirrors-clang-format/compare/v17.0.4...v17.0.5) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8a8e98cac7..fd218813f8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,7 +30,7 @@ repos: exclude: ^source/3rdparty - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.5 + rev: v0.1.6 hooks: - id: ruff args: ["--fix"] @@ -53,7 +53,7 @@ repos: - id: blacken-docs # C++ - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v17.0.4 + rev: v17.0.5 hooks: - id: clang-format exclude: ^source/3rdparty|source/lib/src/gpu/cudart/.+\.inc From f32104675e188891d4c1ab137d6ca6401b709f72 Mon Sep 17 00:00:00 2001 From: nahso <47053538+nahso@users.noreply.github.com> Date: Fri, 24 Nov 2023 09:20:51 +0800 Subject: [PATCH 22/97] Add the missing initializations for extra embedding variables (#3005) --- deepmd/descriptor/se_a.py | 41 ++-- deepmd/descriptor/se_atten.py | 49 ++--- deepmd/utils/compress.py | 6 +- deepmd/utils/graph.py | 85 ++++++++ source/tests/test_init_frz_model_se_a_tebd.py | 196 ++++++++++++++++++ 5 files changed, 331 insertions(+), 46 deletions(-) create mode 100644 source/tests/test_init_frz_model_se_a_tebd.py diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 2de0b63245..6b0a7f7ab1 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -41,6 +41,8 @@ GraphWithoutTensorError, ) from deepmd.utils.graph import ( + get_extra_embedding_net_suffix, + get_extra_embedding_net_variables_from_graph_def, get_pattern_nodes_from_graph_def, get_tensor_by_name_from_graph, ) @@ -204,7 +206,7 @@ def __init__( self.type_one_side = type_one_side self.spin = spin self.stripped_type_embedding = stripped_type_embedding - self.extra_embeeding_net_variables = None + self.extra_embedding_net_variables = None self.layer_size = len(neuron) # extend sel_a for spin system @@ -470,11 +472,13 @@ def enable_compression( ) if self.stripped_type_embedding: + one_side_suffix = get_extra_embedding_net_suffix(type_one_side=True) + two_side_suffix = get_extra_embedding_net_suffix(type_one_side=False) ret_two_side = get_pattern_nodes_from_graph_def( - graph_def, f"filter_type_all{suffix}/.+_two_side_ebd" + graph_def, f"filter_type_all{suffix}/.+{two_side_suffix}" ) ret_one_side = get_pattern_nodes_from_graph_def( - graph_def, f"filter_type_all{suffix}/.+_one_side_ebd" + graph_def, f"filter_type_all{suffix}/.+{one_side_suffix}" ) if len(ret_two_side) == 0 and len(ret_one_side) == 0: raise RuntimeError( @@ -487,19 +491,19 @@ def enable_compression( elif len(ret_two_side) != 0: self.final_type_embedding = get_two_side_type_embedding(self, graph) self.matrix = get_extra_side_embedding_net_variable( - self, graph_def, "two_side", "matrix", suffix + self, graph_def, two_side_suffix, "matrix", suffix ) self.bias = get_extra_side_embedding_net_variable( - self, graph_def, "two_side", "bias", suffix + self, graph_def, two_side_suffix, "bias", suffix ) self.extra_embedding = make_data(self, self.final_type_embedding) else: self.final_type_embedding = get_type_embedding(self, graph) self.matrix = get_extra_side_embedding_net_variable( - self, graph_def, "one_side", "matrix", suffix + self, graph_def, one_side_suffix, "matrix", suffix ) self.bias = get_extra_side_embedding_net_variable( - self, graph_def, "one_side", "bias", suffix + self, graph_def, one_side_suffix, "bias", suffix ) self.extra_embedding = make_data(self, self.final_type_embedding) @@ -961,20 +965,21 @@ def _filter_lower( if not self.compress: if self.type_one_side: - one_side_type_embedding_suffix = "_one_side_ebd" net_output = embedding_net( type_embedding, self.filter_neuron, self.filter_precision, activation_fn=activation_fn, resnet_dt=self.filter_resnet_dt, - name_suffix=one_side_type_embedding_suffix, + name_suffix=get_extra_embedding_net_suffix( + self.type_one_side + ), stddev=stddev, bavg=bavg, seed=self.seed, trainable=trainable, uniform_seed=self.uniform_seed, - initial_variables=self.extra_embeeding_net_variables, + initial_variables=self.extra_embedding_net_variables, mixed_prec=self.mixed_prec, ) net_output = tf.nn.embedding_lookup( @@ -1004,20 +1009,21 @@ def _filter_lower( index_of_two_side = tf.reshape(idx, [-1]) self.extra_embedding_index = index_of_two_side - two_side_type_embedding_suffix = "_two_side_ebd" net_output = embedding_net( two_side_type_embedding, self.filter_neuron, self.filter_precision, activation_fn=activation_fn, resnet_dt=self.filter_resnet_dt, - name_suffix=two_side_type_embedding_suffix, + name_suffix=get_extra_embedding_net_suffix( + self.type_one_side + ), stddev=stddev, bavg=bavg, seed=self.seed, trainable=trainable, uniform_seed=self.uniform_seed, - initial_variables=self.extra_embeeding_net_variables, + initial_variables=self.extra_embedding_net_variables, mixed_prec=self.mixed_prec, ) net_output = tf.nn.embedding_lookup(net_output, idx) @@ -1327,6 +1333,15 @@ def init_variables( self.dstd = new_dstd if self.original_sel is None: self.original_sel = sel + if self.stripped_type_embedding: + self.extra_embedding_net_variables = ( + get_extra_embedding_net_variables_from_graph_def( + graph_def, + suffix, + get_extra_embedding_net_suffix(self.type_one_side), + self.layer_size, + ) + ) @property def explicit_ntypes(self) -> bool: diff --git a/deepmd/descriptor/se_atten.py b/deepmd/descriptor/se_atten.py index 8e4c3c3ef6..1ceda23065 100644 --- a/deepmd/descriptor/se_atten.py +++ b/deepmd/descriptor/se_atten.py @@ -42,9 +42,10 @@ ) from deepmd.utils.graph import ( get_attention_layer_variables_from_graph_def, + get_extra_embedding_net_suffix, + get_extra_embedding_net_variables_from_graph_def, get_pattern_nodes_from_graph_def, get_tensor_by_name_from_graph, - get_tensor_by_type, ) from deepmd.utils.network import ( embedding_net, @@ -391,11 +392,12 @@ def enable_compression( raise RuntimeError("can not compress model when attention layer is not 0.") ret = get_pattern_nodes_from_graph_def( - graph_def, f"filter_type_all{suffix}/.+_two_side_ebd" + graph_def, + f"filter_type_all{suffix}/.+{get_extra_embedding_net_suffix(type_one_side=False)}", ) if len(ret) == 0: raise RuntimeError( - "can not find variables of embedding net `*_two_side_ebd` from graph_def, maybe it is not a compressible model." + f"can not find variables of embedding net `*{get_extra_embedding_net_suffix(type_one_side=False)}` from graph_def, maybe it is not a compressible model." ) self.compress = True @@ -420,11 +422,12 @@ def enable_compression( ) self.final_type_embedding = get_two_side_type_embedding(self, graph) + type_side_suffix = get_extra_embedding_net_suffix(type_one_side=False) self.matrix = get_extra_side_embedding_net_variable( - self, graph_def, "two_side", "matrix", suffix + self, graph_def, type_side_suffix, "matrix", suffix ) self.bias = get_extra_side_embedding_net_variable( - self, graph_def, "two_side", "bias", suffix + self, graph_def, type_side_suffix, "bias", suffix ) self.two_embd = make_data(self, self.final_type_embedding) @@ -1125,14 +1128,15 @@ def _filter_lower( two_side_type_embedding, [-1, two_side_type_embedding.shape[-1]], ) - two_side_type_embedding_suffix = "_two_side_ebd" embedding_of_two_side_type_embedding = embedding_net( two_side_type_embedding, self.filter_neuron, self.filter_precision, activation_fn=activation_fn, resnet_dt=self.filter_resnet_dt, - name_suffix=two_side_type_embedding_suffix, + name_suffix=get_extra_embedding_net_suffix( + type_one_side=False + ), stddev=stddev, bavg=bavg, seed=self.seed, @@ -1292,18 +1296,6 @@ def init_variables( """ super().init_variables(graph=graph, graph_def=graph_def, suffix=suffix) - if self.stripped_type_embedding: - self.two_side_embeeding_net_variables = {} - for i in range(1, self.layer_size + 1): - matrix_pattern = f"filter_type_all{suffix}/matrix_{i}_two_side_ebd" - self.two_side_embeeding_net_variables[ - matrix_pattern - ] = self._get_two_embed_variables(graph_def, matrix_pattern) - bias_pattern = f"filter_type_all{suffix}/bias_{i}_two_side_ebd" - self.two_side_embeeding_net_variables[ - bias_pattern - ] = self._get_two_embed_variables(graph_def, bias_pattern) - self.attention_layer_variables = get_attention_layer_variables_from_graph_def( graph_def, suffix=suffix ) @@ -1322,18 +1314,15 @@ def init_variables( f"attention_layer_{i}{suffix}/layer_normalization_{i}/gamma" ] - def _get_two_embed_variables(self, graph_def, pattern: str): - node = get_pattern_nodes_from_graph_def(graph_def, pattern)[pattern] - dtype = tf.as_dtype(node.dtype).as_numpy_dtype - tensor_shape = tf.TensorShape(node.tensor_shape).as_list() - if (len(tensor_shape) != 1) or (tensor_shape[0] != 1): - tensor_value = np.frombuffer( - node.tensor_content, - dtype=tf.as_dtype(node.dtype).as_numpy_dtype, + if self.stripped_type_embedding: + self.two_side_embeeding_net_variables = ( + get_extra_embedding_net_variables_from_graph_def( + graph_def, + suffix, + get_extra_embedding_net_suffix(type_one_side=False), + self.layer_size, + ) ) - else: - tensor_value = get_tensor_by_type(node, dtype) - return np.reshape(tensor_value, tensor_shape) def build_type_exclude_mask( self, diff --git a/deepmd/utils/compress.py b/deepmd/utils/compress.py index c6e68dfe19..7a79dec520 100644 --- a/deepmd/utils/compress.py +++ b/deepmd/utils/compress.py @@ -43,15 +43,15 @@ def get_two_side_type_embedding(self, graph): def get_extra_side_embedding_net_variable( - self, graph_def, type_side, varialbe_name, suffix + self, graph_def, type_side_suffix, varialbe_name, suffix ): ret = {} for i in range(1, self.layer_size + 1): target = get_pattern_nodes_from_graph_def( graph_def, - f"filter_type_all{suffix}/{varialbe_name}_{i}_{type_side}_ebd", + f"filter_type_all{suffix}/{varialbe_name}_{i}{type_side_suffix}", ) - node = target[f"filter_type_all{suffix}/{varialbe_name}_{i}_{type_side}_ebd"] + node = target[f"filter_type_all{suffix}/{varialbe_name}_{i}{type_side_suffix}"] ret["layer_" + str(i)] = node return ret diff --git a/deepmd/utils/graph.py b/deepmd/utils/graph.py index 2a795a45a2..ad4ee0224a 100644 --- a/deepmd/utils/graph.py +++ b/deepmd/utils/graph.py @@ -237,6 +237,91 @@ def get_embedding_net_variables_from_graph_def( return embedding_net_variables +def get_extra_embedding_net_suffix(type_one_side: bool): + """Get the extra embedding net suffix according to the value of type_one_side. + + Parameters + ---------- + type_one_side + The value of type_one_side + + Returns + ------- + str + The extra embedding net suffix + """ + if type_one_side: + extra_suffix = "_one_side_ebd" + else: + extra_suffix = "_two_side_ebd" + return extra_suffix + + +def get_variables_from_graph_def_as_numpy_array(graph_def: tf.GraphDef, pattern: str): + """Get variables from the given tf.GraphDef object, with numpy array returns. + + Parameters + ---------- + graph_def + The input tf.GraphDef object + pattern : str + The name of variable + + Returns + ------- + np.ndarray + The numpy array of the variable + """ + node = get_pattern_nodes_from_graph_def(graph_def, pattern)[pattern] + dtype = tf.as_dtype(node.dtype).as_numpy_dtype + tensor_shape = tf.TensorShape(node.tensor_shape).as_list() + if (len(tensor_shape) != 1) or (tensor_shape[0] != 1): + tensor_value = np.frombuffer( + node.tensor_content, + dtype=tf.as_dtype(node.dtype).as_numpy_dtype, + ) + else: + tensor_value = get_tensor_by_type(node, dtype) + return np.reshape(tensor_value, tensor_shape) + + +def get_extra_embedding_net_variables_from_graph_def( + graph_def: tf.GraphDef, suffix: str, extra_suffix: str, layer_size: int +): + """Get extra embedding net variables from the given tf.GraphDef object. + The "extra embedding net" means the embedding net with only type embeddings input, + which occurs in "se_atten_v2" and "se_a_ebd_v2" descriptor. + + Parameters + ---------- + graph_def + The input tf.GraphDef object + suffix : str + The "common" suffix in the descriptor + extra_suffix : str + This value depends on the value of "type_one_side". + It should always be "_one_side_ebd" or "_two_side_ebd" + layer_size : int + The layer size of the embedding net + + Returns + ------- + Dict + The extra embedding net variables within the given tf.GraphDef object + """ + extra_embedding_net_variables = {} + for i in range(1, layer_size + 1): + matrix_pattern = f"filter_type_all{suffix}/matrix_{i}{extra_suffix}" + extra_embedding_net_variables[ + matrix_pattern + ] = get_variables_from_graph_def_as_numpy_array(graph_def, matrix_pattern) + bias_pattern = f"filter_type_all{suffix}/bias_{i}{extra_suffix}" + extra_embedding_net_variables[ + bias_pattern + ] = get_variables_from_graph_def_as_numpy_array(graph_def, bias_pattern) + return extra_embedding_net_variables + + def get_embedding_net_variables(model_file: str, suffix: str = "") -> Dict: """Get the embedding net variables with the given frozen model(model_file). diff --git a/source/tests/test_init_frz_model_se_a_tebd.py b/source/tests/test_init_frz_model_se_a_tebd.py new file mode 100644 index 0000000000..e54cae9781 --- /dev/null +++ b/source/tests/test_init_frz_model_se_a_tebd.py @@ -0,0 +1,196 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +import json +import os +import unittest + +import numpy as np +from common import ( + j_loader, + run_dp, + tests_path, +) + +from deepmd.env import ( + GLOBAL_NP_FLOAT_PRECISION, + tf, +) +from deepmd.train.run_options import ( + RunOptions, +) +from deepmd.train.trainer import ( + DPTrainer, +) +from deepmd.utils.argcheck import ( + normalize, +) +from deepmd.utils.compat import ( + update_deepmd_input, +) +from deepmd.utils.data_system import ( + DeepmdDataSystem, +) + +if GLOBAL_NP_FLOAT_PRECISION == np.float32: + default_places = 4 +else: + default_places = 10 + + +def _file_delete(file): + if os.path.isdir(file): + os.rmdir(file) + elif os.path.isfile(file): + os.remove(file) + + +def _init_models(): + data_file = str(tests_path / os.path.join("init_frz_model", "data")) + frozen_model = str(tests_path / "init_frz_se_a_tebd.pb") + ckpt = str(tests_path / "init_frz_se_a_tebd.ckpt") + run_opt_ckpt = RunOptions(init_model=ckpt, log_level=20) + run_opt_frz = RunOptions(init_frz_model=frozen_model, log_level=20) + INPUT = str(tests_path / "input.json") + jdata = j_loader(str(tests_path / os.path.join("init_frz_model", "input.json"))) + jdata["model"]["descriptor"]["type"] = "se_a_ebd_v2" + jdata["training"]["training_data"]["systems"] = data_file + jdata["training"]["validation_data"]["systems"] = data_file + jdata["training"]["save_ckpt"] = ckpt + with open(INPUT, "w") as fp: + json.dump(jdata, fp, indent=4) + ret = run_dp("dp train " + INPUT) + np.testing.assert_equal(ret, 0, "DP train failed!") + ret = run_dp("dp freeze -c " + str(tests_path) + " -o " + frozen_model) + np.testing.assert_equal(ret, 0, "DP freeze failed!") + + jdata = update_deepmd_input(jdata, warning=True, dump="input_v2_compat.json") + jdata = normalize(jdata) + model_ckpt = DPTrainer(jdata, run_opt=run_opt_ckpt) + model_frz = DPTrainer(jdata, run_opt=run_opt_frz) + rcut = model_ckpt.model.get_rcut() + type_map = model_ckpt.model.get_type_map() + data = DeepmdDataSystem( + systems=[data_file], + batch_size=1, + test_size=1, + rcut=rcut, + type_map=type_map, + trn_all_set=True, + ) + data_requirement = { + "energy": { + "ndof": 1, + "atomic": False, + "must": False, + "high_prec": True, + "type_sel": None, + "repeat": 1, + "default": 0.0, + }, + "force": { + "ndof": 3, + "atomic": True, + "must": False, + "high_prec": False, + "type_sel": None, + "repeat": 1, + "default": 0.0, + }, + "virial": { + "ndof": 9, + "atomic": False, + "must": False, + "high_prec": False, + "type_sel": None, + "repeat": 1, + "default": 0.0, + }, + "atom_ener": { + "ndof": 1, + "atomic": True, + "must": False, + "high_prec": False, + "type_sel": None, + "repeat": 1, + "default": 0.0, + }, + "atom_pref": { + "ndof": 1, + "atomic": True, + "must": False, + "high_prec": False, + "type_sel": None, + "repeat": 3, + "default": 0.0, + }, + } + data.add_dict(data_requirement) + stop_batch = jdata["training"]["numb_steps"] + + return INPUT, ckpt, frozen_model, model_ckpt, model_frz, data, stop_batch + + +( + INPUT, + CKPT, + FROZEN_MODEL, + CKPT_TRAINER, + FRZ_TRAINER, + VALID_DATA, + STOP_BATCH, +) = _init_models() + + +class TestInitFrzModelA(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.dp_ckpt = CKPT_TRAINER + cls.dp_frz = FRZ_TRAINER + cls.valid_data = VALID_DATA + cls.stop_batch = STOP_BATCH + + @classmethod + def tearDownClass(cls): + _file_delete(INPUT) + _file_delete(FROZEN_MODEL) + _file_delete("out.json") + _file_delete(str(tests_path / "checkpoint")) + _file_delete(CKPT + ".meta") + _file_delete(CKPT + ".index") + _file_delete(CKPT + ".data-00000-of-00001") + _file_delete(CKPT + "-0.meta") + _file_delete(CKPT + "-0.index") + _file_delete(CKPT + "-0.data-00000-of-00001") + _file_delete(CKPT + "-1.meta") + _file_delete(CKPT + "-1.index") + _file_delete(CKPT + "-1.data-00000-of-00001") + _file_delete("input_v2_compat.json") + _file_delete("lcurve.out") + + def test_single_frame(self): + valid_batch = self.valid_data.get_batch() + natoms = valid_batch["natoms_vec"] + tf.reset_default_graph() + self.dp_ckpt.build(self.valid_data, self.stop_batch) + self.dp_ckpt._init_session() + feed_dict_ckpt = self.dp_ckpt.get_feed_dict(valid_batch, is_training=False) + ckpt_rmse_ckpt = self.dp_ckpt.loss.eval( + self.dp_ckpt.sess, feed_dict_ckpt, natoms + ) + tf.reset_default_graph() + + self.dp_frz.build(self.valid_data, self.stop_batch) + self.dp_frz._init_session() + feed_dict_frz = self.dp_frz.get_feed_dict(valid_batch, is_training=False) + ckpt_rmse_frz = self.dp_frz.loss.eval(self.dp_frz.sess, feed_dict_frz, natoms) + tf.reset_default_graph() + + # check values + np.testing.assert_almost_equal( + ckpt_rmse_ckpt["rmse_e"], ckpt_rmse_frz["rmse_e"], default_places + ) + np.testing.assert_almost_equal( + ckpt_rmse_ckpt["rmse_f"], ckpt_rmse_frz["rmse_f"], default_places + ) + np.testing.assert_almost_equal( + ckpt_rmse_ckpt["rmse_v"], ckpt_rmse_frz["rmse_v"], default_places + ) From c03416d0be874ebda9fc831d001817c3eec159a8 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 26 Nov 2023 04:42:41 -0500 Subject: [PATCH 23/97] add cu11 prebuilt packages (#3002) Signed-off-by: Jinzhe Zeng --- .github/workflows/build_wheel.yml | 24 ++++++++++++++++++++++-- .github/workflows/package_c.yml | 18 ++++++++++++++++-- backend/find_tensorflow.py | 23 +++++++++++++++++------ doc/install/easy-install-dev.md | 4 +++- doc/install/easy-install.md | 6 ++++++ doc/install/install-from-c-library.md | 2 +- pyproject.toml | 14 +++++++++++--- source/install/docker/Dockerfile | 8 +++++--- source/install/docker_package_c.sh | 4 ++-- 9 files changed, 83 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 2ff3ade215..c58a5925bf 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -33,6 +33,13 @@ jobs: python: 311 platform_id: manylinux_x86_64 dp_variant: cuda + cuda_version: 12.2 + - os: ubuntu-latest + python: 311 + platform_id: manylinux_x86_64 + dp_variant: cuda + cuda_version: 11.8 + dp_pkg_name: deepmd-kit-cu11 # macos-x86-64 - os: macos-latest python: 311 @@ -68,6 +75,8 @@ jobs: CIBW_ARCHS: all CIBW_BUILD: cp${{ matrix.python }}-${{ matrix.platform_id }} DP_VARIANT: ${{ matrix.dp_variant }} + CUDA_VERSION: ${{ matrix.cuda_version }} + DP_PKG_NAME: ${{ matrix.dp_pkg_name }} - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl @@ -109,6 +118,14 @@ jobs: # use the already built wheels to build docker needs: [build_wheels] runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - variant: "" + cuda_version: "12" + - variant: "_cu11" + cuda_version: "11" steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v3 @@ -133,8 +150,11 @@ jobs: with: context: source/install/docker push: ${{ github.repository_owner == 'deepmodeling' && github.event_name == 'push' }} - tags: ${{ steps.meta.outputs.tags }} + tags: ${{ steps.meta.outputs.tags }}${{ matrix.variant }} labels: ${{ steps.meta.outputs.labels }} + build-args: | + VARIANT=${{ matrix.variant }} + CUDA_VERSION=${{ matrix.cuda_version }} build_pypi_index: needs: [build_wheels, build_sdist] @@ -173,7 +193,7 @@ jobs: pass: name: Pass testing build wheels - needs: [build_wheels, build_sdist] + needs: [build_wheels, build_sdist, build_docker, build_pypi_index] runs-on: ubuntu-latest if: always() steps: diff --git a/.github/workflows/package_c.yml b/.github/workflows/package_c.yml index ada205be00..2b5f74b97d 100644 --- a/.github/workflows/package_c.yml +++ b/.github/workflows/package_c.yml @@ -8,23 +8,37 @@ jobs: build_c: name: Build C library runs-on: ubuntu-22.04 + strategy: + matrix: + include: + - tensorflow_build_version: "2.15" + tensorflow_version: "" + filename: libdeepmd_c.tar.gz + - tensorflow_build_version: "2.14" + tensorflow_version: ">=2.5.0rc0,<2.15" + filename: libdeepmd_c_cu11.tar.gz steps: - uses: actions/checkout@v4 - name: Package C library run: ./source/install/docker_package_c.sh + env: + TENSORFLOW_VERSION: ${{ matrix.tensorflow_version }} + TENSORFLOW_BUILD_VERSION: ${{ matrix.tensorflow_build_version }} + - run: cp libdeepmd_c.tar.gz ${{ matrix.filename }} + if: matrix.filename != 'libdeepmd_c.tar.gz' # for download and debug - name: Upload artifact uses: actions/upload-artifact@v3 with: name: libdeepmd_c - path: ./libdeepmd_c.tar.gz + path: ${{ matrix.filename }} - name: Test C library run: ./source/install/docker_test_package_c.sh - name: Release uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/') with: - files: libdeepmd_c.tar.gz + files: ${{ matrix.filename }} test_c: name: Test building from C library needs: [build_c] diff --git a/backend/find_tensorflow.py b/backend/find_tensorflow.py index fbbe0e56c0..08a73f7252 100644 --- a/backend/find_tensorflow.py +++ b/backend/find_tensorflow.py @@ -88,12 +88,23 @@ def find_tensorflow() -> Tuple[Optional[str], List[str]]: # IndexError if submodule_search_locations is an empty list except (AttributeError, TypeError, IndexError): if os.environ.get("CIBUILDWHEEL", "0") == "1": - # CUDA 12.2 - requires.extend( - [ - "tensorflow-cpu>=2.15.0rc0; platform_machine=='x86_64' and platform_system == 'Linux'", - ] - ) + cuda_version = os.environ.get("CUDA_VERSION", "12.2") + if cuda_version == "" or cuda_version in SpecifierSet(">=12,<13"): + # CUDA 12.2 + requires.extend( + [ + "tensorflow-cpu>=2.15.0rc0; platform_machine=='x86_64' and platform_system == 'Linux'", + ] + ) + elif cuda_version in SpecifierSet(">=11,<12"): + # CUDA 11.8 + requires.extend( + [ + "tensorflow-cpu>=2.5.0rc0,<2.15; platform_machine=='x86_64' and platform_system == 'Linux'", + ] + ) + else: + raise RuntimeError("Unsupported CUDA version") requires.extend(get_tf_requirement()["cpu"]) # setuptools will re-find tensorflow after installing setup_requires tf_install_dir = None diff --git a/doc/install/easy-install-dev.md b/doc/install/easy-install-dev.md index f3d4fa1a32..6fd9171730 100644 --- a/doc/install/easy-install-dev.md +++ b/doc/install/easy-install-dev.md @@ -6,12 +6,14 @@ The following is the way to install the pre-compiled packages without [building ## Install with docker -The [`devel` tag](https://github.com/deepmodeling/deepmd-kit/pkgs/container/deepmd-kit/131827568?tag=devel) is used to mark the latest development version with CUDA support: +The [`devel` tag](https://github.com/deepmodeling/deepmd-kit/pkgs/container/deepmd-kit/131827568?tag=devel) is used to mark the latest development version with CUDA 12.2 support: ```bash docker pull ghcr.io/deepmodeling/deepmd-kit:devel ``` +For CUDA 11.8 support, use the `devel_cu11` tag. + ## Install with pip Below is an one-line shell command to download the [artifact](https://nightly.link/deepmodeling/deepmd-kit/workflows/build_wheel/devel/artifact.zip) containing wheels and install it with `pip`: diff --git a/doc/install/easy-install.md b/doc/install/easy-install.md index 741ef632a8..3bc1f4b944 100644 --- a/doc/install/easy-install.md +++ b/doc/install/easy-install.md @@ -92,6 +92,12 @@ pip install deepmd-kit[gpu,cu12] `cu12` is required only when CUDA Toolkit and cuDNN were not installed. +To install the package built against CUDA 11.8, use + +```bash +pip install deepmd-kit-cu11[gpu,cu11] +``` + Or install the CPU version without CUDA supported: ```bash pip install deepmd-kit[cpu] diff --git a/doc/install/install-from-c-library.md b/doc/install/install-from-c-library.md index 04b71234db..eb89538277 100644 --- a/doc/install/install-from-c-library.md +++ b/doc/install/install-from-c-library.md @@ -2,7 +2,7 @@ DeePMD-kit provides pre-compiled C library package (`libdeepmd_c.tar.gz`) in each [release](https://github.com/deepmodeling/deepmd-kit/releases). It can be used to build the [LAMMPS plugin](./install-lammps.md) and [GROMACS patch](./install-gromacs.md), as well as many [third-party software packages](../third-party/out-of-deepmd-kit.md), without building TensorFlow and DeePMD-kit on one's own. -The library is built in Linux (GLIBC 2.17) with CUDA 12.2. It's noted that this package does not contain CUDA Toolkit and cuDNN, so one needs to download them from the NVIDIA website. +The library is built in Linux (GLIBC 2.17) with CUDA 12.2 (`libdeepmd_c.tar.gz`) or 11.8 (`libdeepmd_c_cu11.tar.gz`). It's noted that this package does not contain CUDA Toolkit and cuDNN, so one needs to download them from the NVIDIA website. ## Use Pre-compiled C Library to build the LAMMPS plugin and GROMACS patch diff --git a/pyproject.toml b/pyproject.toml index e9ee563960..04bcc69f75 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -133,7 +133,9 @@ test-command = [ test-extras = ["cpu", "test", "lmp", "ipi"] build = ["cp310-*"] skip = ["*-win32", "*-manylinux_i686", "*-musllinux*"] -manylinux-x86_64-image = "manylinux_2_28" +# TODO: uncomment when CUDA 11 is deprecated +# manylinux-x86_64-image = "manylinux_2_28" +manylinux-x86_64-image = "quay.io/pypa/manylinux_2_28_x86_64:2022-11-19-1b19e81" manylinux-aarch64-image = "manylinux_2_28" [tool.cibuildwheel.macos] @@ -148,10 +150,16 @@ repair-wheel-command = """if [[ "$CIBW_BUILD" == *macosx_arm64* ]]; then rm -rf [tool.cibuildwheel.linux] repair-wheel-command = "auditwheel repair --exclude libtensorflow_framework.so.2 --exclude libtensorflow_framework.so.1 --exclude libtensorflow_framework.so --exclude _pywrap_tensorflow_internal.so --exclude libtensorflow_cc.so.2 -w {dest_dir} {wheel}" -environment-pass = ["CIBW_BUILD", "DP_VARIANT"] +environment-pass = [ + "CIBW_BUILD", + "DP_VARIANT", + "CUDA_VERSION", + "DP_PKG_NAME", +] environment = { PIP_PREFER_BINARY="1", DP_LAMMPS_VERSION="stable_2Aug2023_update1", DP_ENABLE_IPI="1", MPI_HOME="/usr/lib64/mpich", PATH="/usr/lib64/mpich/bin:$PATH" } before-all = [ - """{ if [ "$(uname -m)" = "x86_64" ] ; then yum config-manager --add-repo http://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/cuda-rhel8.repo && yum install -y cuda-nvcc-12-2 cuda-cudart-devel-12-2; fi }""", + """if [ ! -z "${DP_PKG_NAME}" ]; then sed -i "s/name = \\"deepmd-kit\\"/name = \\"${DP_PKG_NAME}\\"/g" pyproject.toml; fi""", + """{ if [ "$(uname -m)" = "x86_64" ] ; then yum config-manager --add-repo http://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/cuda-rhel8.repo && yum install -y cuda-nvcc-${CUDA_VERSION/./-} cuda-cudart-devel-${CUDA_VERSION/./-}; fi }""", "yum install -y mpich-devel", ] diff --git a/source/install/docker/Dockerfile b/source/install/docker/Dockerfile index 9ac905dcd0..26b7be9f19 100644 --- a/source/install/docker/Dockerfile +++ b/source/install/docker/Dockerfile @@ -1,16 +1,18 @@ -FROM python:3.10 AS compile-image +FROM python:3.11 AS compile-image +ARG VARIANT="" +ARG CUDA_VERSION="12" RUN python -m venv /opt/deepmd-kit # Make sure we use the virtualenv ENV PATH="/opt/deepmd-kit/bin:$PATH" # Install package COPY dist /dist -RUN pip install "$(ls /dist/deepmd_kit-*manylinux*_x86_64.whl)[gpu,cu12,lmp,ipi]" \ +RUN pip install "$(ls /dist/deepmd_kit${VARIANT}-*manylinux*_x86_64.whl)[gpu,cu${CUDA_VERSION},lmp,ipi]" \ && dp -h \ && lmp -h \ && dp_ipi \ && python -m deepmd -h -FROM python:3.10 AS build-image +FROM python:3.11 AS build-image COPY --from=compile-image /opt/deepmd-kit /opt/deepmd-kit ENV PATH="/opt/deepmd-kit/bin:$PATH" CMD ["/bin/bash"] diff --git a/source/install/docker_package_c.sh b/source/install/docker_package_c.sh index 75f2d1138b..544c175a0a 100755 --- a/source/install/docker_package_c.sh +++ b/source/install/docker_package_c.sh @@ -3,8 +3,8 @@ set -e SCRIPT_PATH=$(dirname $(realpath -s $0)) docker run --rm -v ${SCRIPT_PATH}/../..:/root/deepmd-kit -w /root/deepmd-kit \ - tensorflow/build:2.15-python3.11 \ - /bin/sh -c "pip install tensorflow cmake \ + tensorflow/build:${TENSORFLOW_BUILD_VERSION:-2.15}-python3.11 \ + /bin/sh -c "pip install \"tensorflow${TENSORFLOW_VERSION}\" cmake \ && cd /root/deepmd-kit/source/install \ && CC=/dt9/usr/bin/gcc \ CXX=/dt9/usr/bin/g++ \ From efb0a34971899884b1b4d7ccc2fe87b6337c8cf6 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 27 Nov 2023 22:39:53 -0500 Subject: [PATCH 24/97] print system prob using scientific natation (#3008) When the probability of a system is smaller than 1e-3, it is shown as `0.000`, which is useless. This commit changes it to the scientific notation, displaying it like `1.547e-06`. --------- Signed-off-by: Jinzhe Zeng Co-authored-by: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> --- deepmd/utils/data_system.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index 09dcac2d8d..bf05b5faa7 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -560,11 +560,11 @@ def print_summary(self, name): log.info("found %d system(s):" % self.nsystems) log.info( ("%s " % self._format_name_length("system", sys_width)) - + ("%6s %6s %6s %5s %3s" % ("natoms", "bch_sz", "n_bch", "prob", "pbc")) + + ("%6s %6s %6s %9s %3s" % ("natoms", "bch_sz", "n_bch", "prob", "pbc")) ) for ii in range(self.nsystems): log.info( - "%s %6d %6d %6d %5.3f %3s" + "%s %6d %6d %6d %9.3e %3s" % ( self._format_name_length(self.system_dirs[ii], sys_width), self.natoms[ii], From b4bb3a902f521e9230cdf5e1a8cfa63db5717610 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 15:08:30 +0800 Subject: [PATCH 25/97] [pre-commit.ci] pre-commit autoupdate (#3011) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/scop/pre-commit-shfmt: v3.7.0-3 → v3.7.0-4](https://github.com/scop/pre-commit-shfmt/compare/v3.7.0-3...v3.7.0-4) --------- Signed-off-by: Jinzhe Zeng Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Jinzhe Zeng --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fd218813f8..089118f9af 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -64,9 +64,9 @@ repos: - id: csslint # Shell - repo: https://github.com/scop/pre-commit-shfmt - rev: v3.7.0-3 + rev: v3.7.0-4 hooks: - - id: shfmt-src + - id: shfmt # CMake - repo: https://github.com/cheshirekow/cmake-format-precommit rev: v0.6.13 From 12baf124e0ee7a989eb44b694b3357f6487ca321 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Tue, 28 Nov 2023 19:19:50 -0500 Subject: [PATCH 26/97] Fix macro issue with multiple arguments (#3016) Modified the `DPMD_CVT_STR` macro to handle multiple arguments by using `__VA_ARGS__`. This resolves #2952, the error caused by commas in the branch name during compilation. This commit (including the above message) is entirely generated by ChatGPT 3.5. Signed-off-by: Jinzhe Zeng --- source/lmp/deepmd_version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/lmp/deepmd_version.h.in b/source/lmp/deepmd_version.h.in index f4c72c8413..4b99bc7c33 100644 --- a/source/lmp/deepmd_version.h.in +++ b/source/lmp/deepmd_version.h.in @@ -5,7 +5,7 @@ #define DEEPMD_ROOT @CMAKE_INSTALL_PREFIX@ #define TensorFlow_INCLUDE_DIRS @TensorFlow_INCLUDE_DIRS@ #define TensorFlow_LIBRARY @TensorFlow_LIBRARY@ -#define DPMD_CVT_STR(x) #x +#define DPMD_CVT_STR(...) #__VA_ARGS__ #define DPMD_CVT_ASSTR(X) DPMD_CVT_STR(X) #define STR_GIT_SUMM DPMD_CVT_ASSTR(GIT_SUMM) #define STR_GIT_HASH DPMD_CVT_ASSTR(GIT_HASH) From ea452956d5f2f5754f82ee4f0da846f78ddbeeff Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:14:17 +0800 Subject: [PATCH 27/97] [pre-commit.ci] pre-commit autoupdate (#3032) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-clang-format: v17.0.5 → v17.0.6](https://github.com/pre-commit/mirrors-clang-format/compare/v17.0.5...v17.0.6) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 089118f9af..64a061dd54 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -53,7 +53,7 @@ repos: - id: blacken-docs # C++ - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v17.0.5 + rev: v17.0.6 hooks: - id: clang-format exclude: ^source/3rdparty|source/lib/src/gpu/cudart/.+\.inc From 44aba8352d897f87bd5e637b082893c0a296aaa0 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Tue, 5 Dec 2023 20:10:25 -0500 Subject: [PATCH 28/97] bump scikit-build-core to 0.7 (#3038) No breaking changes there Signed-off-by: Jinzhe Zeng --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 04bcc69f75..fdd4904eb5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ requires = [ # dynamic metadata API is still unstable # TODO: unpin the upper bound when it is stable - "scikit-build-core>=0.5,<0.7,!=0.6.0", + "scikit-build-core>=0.5,<0.8,!=0.6.0", "packaging", ] build-backend = "backend.dp_backend" From 3c549492dbba017aaa994b090f926deeb29bb687 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Tue, 5 Dec 2023 20:11:19 -0500 Subject: [PATCH 29/97] breaking(lmp): do not apply scale factor to model deviation (#3036) Resolves #3027. --------- Signed-off-by: Jinzhe Zeng Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- doc/third-party/lammps-command.md | 1 + source/lmp/pair_deepmd.cpp | 15 +++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/third-party/lammps-command.md b/doc/third-party/lammps-command.md index 023345d638..150d755795 100644 --- a/doc/third-party/lammps-command.md +++ b/doc/third-party/lammps-command.md @@ -82,6 +82,7 @@ Evaluate the interaction of the system by using [Deep Potential][DP] or [Deep Po This pair style takes the deep potential defined in a model file that usually has the .pb extension. The model can be trained and frozen by package [DeePMD-kit](https://github.com/deepmodeling/deepmd-kit), which can have either double or single float precision interface. The model deviation evalulates the consistency of the force predictions from multiple models. By default, only the maximal, minimal and average model deviations are output. If the key `atomic` is set, then the model deviation of force prediction of each atom will be output. +The unit follows [LAMMPS units](#units) and the [scale factor](https://docs.lammps.org/pair_hybrid.html) is not applied. By default, the model deviation is output in absolute value. If the keyword `relative` is set, then the relative model deviation of the force will be output, including values output by the keyword `atomic`. The relative model deviation of the force on atom $i$ is defined by diff --git a/source/lmp/pair_deepmd.cpp b/source/lmp/pair_deepmd.cpp index 600c4cae29..645bb9fec9 100644 --- a/source/lmp/pair_deepmd.cpp +++ b/source/lmp/pair_deepmd.cpp @@ -767,12 +767,12 @@ void PairDeepMD::compute(int eflag, int vflag) { all_v_avg = sqrt(all_v_avg / 9); } if (rank == 0) { - all_v_max *= scale[1][1] * ener_unit_cvt_factor; - all_v_min *= scale[1][1] * ener_unit_cvt_factor; - all_v_avg *= scale[1][1] * ener_unit_cvt_factor; - all_f_max *= scale[1][1] * force_unit_cvt_factor; - all_f_min *= scale[1][1] * force_unit_cvt_factor; - all_f_avg *= scale[1][1] * force_unit_cvt_factor; + all_v_max *= ener_unit_cvt_factor; + all_v_min *= ener_unit_cvt_factor; + all_v_avg *= ener_unit_cvt_factor; + all_f_max *= force_unit_cvt_factor; + all_f_min *= force_unit_cvt_factor; + all_f_avg *= force_unit_cvt_factor; fp << setw(12) << update->ntimestep << " " << setw(18) << all_v_max << " " << setw(18) << all_v_min << " " << setw(18) << all_v_avg << " " << setw(18) << all_f_max << " " << setw(18) << all_f_min @@ -798,8 +798,7 @@ void PairDeepMD::compute(int eflag, int vflag) { displacements, MPI_DOUBLE, 0, world); if (rank == 0) { for (int dd = 0; dd < all_nlocal; ++dd) { - std_f_all[tagrecv[dd] - 1] = - stdfrecv[dd] * scale[1][1] * force_unit_cvt_factor; + std_f_all[tagrecv[dd] - 1] = stdfrecv[dd] * force_unit_cvt_factor; } for (int dd = 0; dd < all_nlocal; ++dd) { fp << " " << setw(18) << std_f_all[dd]; From fe488a4560e86176414e1b9b04904902ac6ed488 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 6 Dec 2023 20:13:01 -0500 Subject: [PATCH 30/97] fix se_a_ebd_v2 when nloc != nall (#3037) See also #2390 and #2505... Signed-off-by: Jinzhe Zeng --- deepmd/descriptor/se_a.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 6b0a7f7ab1..9beec2db1d 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -782,16 +782,16 @@ def _pass_filter( type_i = -1 if nvnmd_cfg.enable and nvnmd_cfg.quantize_descriptor: inputs_i = descrpt2r4(inputs_i, natoms) + self.atype_nloc = tf.reshape( + tf.slice(atype, [0, 0], [-1, natoms[0]]), [-1] + ) # when nloc != nall, pass nloc to mask if len(self.exclude_types): - atype_nloc = tf.reshape( - tf.slice(atype, [0, 0], [-1, natoms[0]]), [-1] - ) # when nloc != nall, pass nloc to mask mask = self.build_type_exclude_mask( self.exclude_types, self.ntypes, self.sel_a, self.ndescrpt, - atype_nloc, + self.atype_nloc, tf.shape(inputs_i)[0], ) inputs_i *= mask @@ -956,7 +956,7 @@ def _filter_lower( extra_embedding_index = self.nei_type_vec else: padding_ntypes = type_embedding.shape[0] - atype_expand = tf.reshape(self.atype, [-1, 1]) + atype_expand = tf.reshape(self.atype_nloc, [-1, 1]) idx_i = tf.tile(atype_expand * padding_ntypes, [1, self.nnei]) idx_j = tf.reshape(self.nei_type_vec, [-1, self.nnei]) idx = idx_i + idx_j @@ -1002,7 +1002,7 @@ def _filter_lower( [-1, two_side_type_embedding.shape[-1]], ) - atype_expand = tf.reshape(self.atype, [-1, 1]) + atype_expand = tf.reshape(self.atype_nloc, [-1, 1]) idx_i = tf.tile(atype_expand * padding_ntypes, [1, self.nnei]) idx_j = tf.reshape(self.nei_type_vec, [-1, self.nnei]) idx = idx_i + idx_j From a21079913d125ab6cce6dec9b48454c6e948454b Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 6 Dec 2023 20:16:46 -0500 Subject: [PATCH 31/97] skip pushing when an action is triggered by dependeabot (#3035) See https://github.com/deepmodeling/deepmd-kit/pull/3029 See also https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions#responding-to-events Signed-off-by: Jinzhe Zeng --- .github/workflows/build_wheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index c58a5925bf..ad4a17cfea 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -149,7 +149,7 @@ jobs: uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 with: context: source/install/docker - push: ${{ github.repository_owner == 'deepmodeling' && github.event_name == 'push' }} + push: ${{ github.repository_owner == 'deepmodeling' && github.event_name == 'push' && github.actor != 'dependabot[bot]' }} tags: ${{ steps.meta.outputs.tags }}${{ matrix.variant }} labels: ${{ steps.meta.outputs.labels }} build-args: | From 0547940baa74db029f05f4f95e0d2341d51ab97e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Dec 2023 01:56:32 +0000 Subject: [PATCH 32/97] Bump docker/metadata-action from 5.0.0 to 5.3.0 (#3029) --- .github/workflows/build_wheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index ad4a17cfea..67241e6e23 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -141,7 +141,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 + uses: docker/metadata-action@31cebacef4805868f9ce9a0cb03ee36c32df2ac4 with: images: ghcr.io/deepmodeling/deepmd-kit From ce25ff453a178df2ab451bb49c39df1789d7ca4a Mon Sep 17 00:00:00 2001 From: Futaki Haduki <812556867@qq.com> Date: Mon, 11 Dec 2023 13:15:21 +0800 Subject: [PATCH 33/97] fix: invalid read and write when natom grows (#3031) This PR fixes #3015, which reported an invalid memory read and write when running `fix deposition` in Lammps to add atoms into the system. The issue could not be reproduced when `atomic` was removed from the `pair_style deepmd` line. As suggested by @njzjz , the possible cause of the bug was the allocation of `stdfsend`, `stdfrecv`, etc., which only happened when `out_each == 1`, set by `atomic` in the `pair_style deepmd` command. Moreover, their size was only determined in the initialization step, based on the initial `natoms`. The valgrind log also supported this hypothesis, as it showed `MPI_Gather` and `MPI_Gatherv` errors in the traceback. Therefore, we decided to destroy and recreate the memory when `atom->natoms` became larger than `stdfsend`. This should prevent the invalid memory access and resolve the issue. --- source/api_cc/src/common.cc | 4 ++-- source/lmp/pair_deepmd.cpp | 26 ++++++++++++++++++++------ source/lmp/pair_deepmd.h | 1 + 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/source/api_cc/src/common.cc b/source/api_cc/src/common.cc index 5994e9446f..33c433a90a 100644 --- a/source/api_cc/src/common.cc +++ b/source/api_cc/src/common.cc @@ -1277,10 +1277,10 @@ void deepmd::print_summary(const std::string& pre) { deepmd::get_env_nthreads(num_intra_nthreads, num_inter_nthreads); std::cout << pre << "installed to: " + global_install_prefix << "\n"; std::cout << pre << "source: " + global_git_summ << "\n"; - std::cout << pre << "source branch: " + global_git_branch << "\n"; + std::cout << pre << "source branch: " + global_git_branch << "\n"; std::cout << pre << "source commit: " + global_git_hash << "\n"; std::cout << pre << "source commit at: " + global_git_date << "\n"; - std::cout << pre << "surpport model ver.:" + global_model_version << "\n"; + std::cout << pre << "support model ver.: " + global_model_version << "\n"; #if defined(GOOGLE_CUDA) std::cout << pre << "build variant: cuda" << "\n"; diff --git a/source/lmp/pair_deepmd.cpp b/source/lmp/pair_deepmd.cpp index 645bb9fec9..533e3538fe 100644 --- a/source/lmp/pair_deepmd.cpp +++ b/source/lmp/pair_deepmd.cpp @@ -394,6 +394,7 @@ PairDeepMD::PairDeepMD(LAMMPS *lmp) out_each = 0; out_rel = 0; out_rel_v = 0; + stdf_comm_buff_size = 0; eps = 0.; eps_v = 0.; scale = NULL; @@ -720,13 +721,11 @@ void PairDeepMD::compute(int eflag, int vflag) { } double min = numeric_limits::max(), max = 0, avg = 0; ana_st(max, min, avg, std_f, nlocal); - int all_nlocal = 0; - MPI_Reduce(&nlocal, &all_nlocal, 1, MPI_INT, MPI_SUM, 0, world); double all_f_min = 0, all_f_max = 0, all_f_avg = 0; MPI_Reduce(&min, &all_f_min, 1, MPI_DOUBLE, MPI_MIN, 0, world); MPI_Reduce(&max, &all_f_max, 1, MPI_DOUBLE, MPI_MAX, 0, world); MPI_Reduce(&avg, &all_f_avg, 1, MPI_DOUBLE, MPI_SUM, 0, world); - all_f_avg /= double(all_nlocal); + all_f_avg /= double(atom->natoms); // std v std::vector send_v(9 * numb_models); std::vector recv_v(9 * numb_models); @@ -779,10 +778,22 @@ void PairDeepMD::compute(int eflag, int vflag) { << " " << setw(18) << all_f_avg; } if (out_each == 1) { - vector std_f_all(all_nlocal); + vector std_f_all(atom->natoms); // Gather std_f and tags tagint *tag = atom->tag; int nprocs = comm->nprocs; + // Grow arrays if necessary + if (atom->natoms > stdf_comm_buff_size) { + stdf_comm_buff_size = atom->natoms; + memory->destroy(stdfsend); + memory->destroy(stdfrecv); + memory->destroy(tagsend); + memory->destroy(tagrecv); + memory->create(stdfsend, stdf_comm_buff_size, "deepmd:stdfsendall"); + memory->create(stdfrecv, stdf_comm_buff_size, "deepmd:stdfrecvall"); + memory->create(tagsend, stdf_comm_buff_size, "deepmd:tagsendall"); + memory->create(tagrecv, stdf_comm_buff_size, "deepmd:tagrecvall"); + } for (int ii = 0; ii < nlocal; ii++) { tagsend[ii] = tag[ii]; stdfsend[ii] = std_f[ii]; @@ -797,10 +808,10 @@ void PairDeepMD::compute(int eflag, int vflag) { MPI_Gatherv(stdfsend, nlocal, MPI_DOUBLE, stdfrecv, counts, displacements, MPI_DOUBLE, 0, world); if (rank == 0) { - for (int dd = 0; dd < all_nlocal; ++dd) { + for (int dd = 0; dd < atom->natoms; ++dd) { std_f_all[tagrecv[dd] - 1] = stdfrecv[dd] * force_unit_cvt_factor; } - for (int dd = 0; dd < all_nlocal; ++dd) { + for (int dd = 0; dd < atom->natoms; ++dd) { fp << " " << setw(18) << std_f_all[dd]; } } @@ -1278,6 +1289,9 @@ void PairDeepMD::init_style() { if (out_each == 1) { int ntotal = atom->natoms; int nprocs = comm->nprocs; + if (ntotal > stdf_comm_buff_size) { + stdf_comm_buff_size = ntotal; + } memory->create(counts, nprocs, "deepmd:counts"); memory->create(displacements, nprocs, "deepmd:displacements"); memory->create(stdfsend, ntotal, "deepmd:stdfsendall"); diff --git a/source/lmp/pair_deepmd.h b/source/lmp/pair_deepmd.h index 0f704ab45c..cd72dc7b2a 100644 --- a/source/lmp/pair_deepmd.h +++ b/source/lmp/pair_deepmd.h @@ -98,6 +98,7 @@ class PairDeepMD : public Pair { int out_each; int out_rel; int out_rel_v; + int stdf_comm_buff_size; bool single_model; bool multi_models_mod_devi; bool multi_models_no_mod_devi; From a6f133387ce0b7dbf823fad54bfe5725b90228ce Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 11 Dec 2023 00:21:01 -0500 Subject: [PATCH 34/97] build neighbor list with external Python program (#3046) Fix #2877 --------- Signed-off-by: Jinzhe Zeng --- deepmd/calculator.py | 5 +- deepmd/infer/__init__.py | 7 +++ deepmd/infer/deep_dipole.py | 4 ++ deepmd/infer/deep_eval.py | 95 +++++++++++++++++++++++++++++++++ deepmd/infer/deep_polar.py | 13 ++++- deepmd/infer/deep_pot.py | 58 +++++++++++++++++--- deepmd/infer/deep_tensor.py | 85 +++++++++++++++++++++++++---- source/tests/test_deepdipole.py | 32 +++++++++-- source/tests/test_deeppolar.py | 34 +++++++++--- source/tests/test_deeppot_a.py | 23 ++++++++ 10 files changed, 326 insertions(+), 30 deletions(-) diff --git a/deepmd/calculator.py b/deepmd/calculator.py index 8636ff30d2..b9c0a81006 100644 --- a/deepmd/calculator.py +++ b/deepmd/calculator.py @@ -45,6 +45,8 @@ class DP(Calculator): type_dict : Dict[str, int], optional mapping of element types and their numbers, best left None and the calculator will infer this information from model, by default None + neighbor_list : ase.neighborlist.NeighborList, optional + The neighbor list object. If None, then build the native neighbor list. Examples -------- @@ -83,10 +85,11 @@ def __init__( model: Union[str, "Path"], label: str = "DP", type_dict: Optional[Dict[str, int]] = None, + neighbor_list=None, **kwargs, ) -> None: Calculator.__init__(self, label=label, **kwargs) - self.dp = DeepPotential(str(Path(model).resolve())) + self.dp = DeepPotential(str(Path(model).resolve()), neighbor_list=neighbor_list) if type_dict: self.type_dict = type_dict else: diff --git a/deepmd/infer/__init__.py b/deepmd/infer/__init__.py index 14d75d0c44..c1071af35c 100644 --- a/deepmd/infer/__init__.py +++ b/deepmd/infer/__init__.py @@ -58,6 +58,7 @@ def DeepPotential( load_prefix: str = "load", default_tf_graph: bool = False, input_map: Optional[dict] = None, + neighbor_list=None, ) -> Union[DeepDipole, DeepGlobalPolar, DeepPolar, DeepPot, DeepDOS, DeepWFC]: """Factory function that will inialize appropriate potential read from `model_file`. @@ -71,6 +72,8 @@ def DeepPotential( If uses the default tf graph, otherwise build a new tf graph for evaluation input_map : dict, optional The input map for tf.import_graph_def. Only work with default tf graph + neighbor_list : ase.neighborlist.NeighborList, optional + The neighbor list object. If None, then build the native neighbor list. Returns ------- @@ -97,6 +100,7 @@ def DeepPotential( load_prefix=load_prefix, default_tf_graph=default_tf_graph, input_map=input_map, + neighbor_list=neighbor_list, ) elif model_type == "dos": dp = DeepDOS( @@ -111,6 +115,7 @@ def DeepPotential( load_prefix=load_prefix, default_tf_graph=default_tf_graph, input_map=input_map, + neighbor_list=neighbor_list, ) elif model_type == "polar": dp = DeepPolar( @@ -118,6 +123,7 @@ def DeepPotential( load_prefix=load_prefix, default_tf_graph=default_tf_graph, input_map=input_map, + neighbor_list=neighbor_list, ) elif model_type == "global_polar": dp = DeepGlobalPolar( @@ -125,6 +131,7 @@ def DeepPotential( load_prefix=load_prefix, default_tf_graph=default_tf_graph, input_map=input_map, + neighbor_list=neighbor_list, ) elif model_type == "wfc": dp = DeepWFC( diff --git a/deepmd/infer/deep_dipole.py b/deepmd/infer/deep_dipole.py index 6020118135..aba098a9f3 100644 --- a/deepmd/infer/deep_dipole.py +++ b/deepmd/infer/deep_dipole.py @@ -27,6 +27,8 @@ class DeepDipole(DeepTensor): If uses the default tf graph, otherwise build a new tf graph for evaluation input_map : dict, optional The input map for tf.import_graph_def. Only work with default tf graph + neighbor_list : ase.neighborlist.NeighborList, optional + The neighbor list object. If None, then build the native neighbor list. Warnings -------- @@ -41,6 +43,7 @@ def __init__( load_prefix: str = "load", default_tf_graph: bool = False, input_map: Optional[dict] = None, + neighbor_list=None, ) -> None: # use this in favor of dict update to move attribute from class to # instance namespace @@ -58,6 +61,7 @@ def __init__( load_prefix=load_prefix, default_tf_graph=default_tf_graph, input_map=input_map, + neighbor_list=neighbor_list, ) def get_dim_fparam(self) -> int: diff --git a/deepmd/infer/deep_eval.py b/deepmd/infer/deep_eval.py index 3f5dede1ad..0ca9f21a77 100644 --- a/deepmd/infer/deep_eval.py +++ b/deepmd/infer/deep_eval.py @@ -45,6 +45,9 @@ class DeepEval: as the initial batch size. input_map : dict, optional The input map for tf.import_graph_def. Only work with default tf graph + neighbor_list : ase.neighborlist.NewPrimitiveNeighborList, optional + The ASE neighbor list class to produce the neighbor list. If None, the + neighbor list will be built natively in the model. """ load_prefix: str # set by subclass @@ -56,6 +59,7 @@ def __init__( default_tf_graph: bool = False, auto_batch_size: Union[bool, int, AutoBatchSize] = False, input_map: Optional[dict] = None, + neighbor_list=None, ): self.graph = self._load_graph( model_file, @@ -86,6 +90,8 @@ def __init__( else: raise TypeError("auto_batch_size should be bool, int, or AutoBatchSize") + self.neighbor_list = neighbor_list + @property @lru_cache(maxsize=None) def model_type(self) -> str: @@ -360,3 +366,92 @@ def eval_typeebd(self) -> np.ndarray: t_typeebd = self._get_tensor("t_typeebd:0") [typeebd] = run_sess(self.sess, [t_typeebd], feed_dict={}) return typeebd + + def build_neighbor_list( + self, + coords: np.ndarray, + cell: Optional[np.ndarray], + atype: np.ndarray, + imap: np.ndarray, + neighbor_list, + ): + """Make the mesh with neighbor list for a single frame. + + Parameters + ---------- + coords : np.ndarray + The coordinates of atoms. Should be of shape [natoms, 3] + cell : Optional[np.ndarray] + The cell of the system. Should be of shape [3, 3] + atype : np.ndarray + The type of atoms. Should be of shape [natoms] + imap : np.ndarray + The index map of atoms. Should be of shape [natoms] + neighbor_list : ase.neighborlist.NewPrimitiveNeighborList + ASE neighbor list. The following method or attribute will be + used/set: bothways, self_interaction, update, build, first_neigh, + pair_second, offset_vec. + + Returns + ------- + natoms_vec : np.ndarray + The number of atoms. This tensor has the length of Ntypes + 2 + natoms[0]: nloc + natoms[1]: nall + natoms[i]: 2 <= i < Ntypes+2, number of type i atoms for nloc + coords : np.ndarray + The coordinates of atoms, including ghost atoms. Should be of + shape [nframes, nall, 3] + atype : np.ndarray + The type of atoms, including ghost atoms. Should be of shape [nall] + mesh : np.ndarray + The mesh in nei_mode=4. + imap : np.ndarray + The index map of atoms. Should be of shape [nall] + ghost_map : np.ndarray + The index map of ghost atoms. Should be of shape [nghost] + """ + pbc = np.repeat(cell is not None, 3) + cell = cell.reshape(3, 3) + positions = coords.reshape(-1, 3) + neighbor_list.bothways = True + neighbor_list.self_interaction = False + if neighbor_list.update(pbc, cell, positions): + neighbor_list.build(pbc, cell, positions) + first_neigh = neighbor_list.first_neigh.copy() + pair_second = neighbor_list.pair_second.copy() + offset_vec = neighbor_list.offset_vec.copy() + # get out-of-box neighbors + out_mask = np.any(offset_vec != 0, axis=1) + out_idx = pair_second[out_mask] + out_offset = offset_vec[out_mask] + out_coords = positions[out_idx] + out_offset.dot(cell) + atype = np.array(atype, dtype=int) + out_atype = atype[out_idx] + + nloc = positions.shape[0] + nghost = out_idx.size + all_coords = np.concatenate((positions, out_coords), axis=0) + all_atype = np.concatenate((atype, out_atype), axis=0) + # convert neighbor indexes + ghost_map = pair_second[out_mask] + pair_second[out_mask] = np.arange(nloc, nloc + nghost) + # get the mesh + mesh = np.zeros(16 + nloc * 2 + pair_second.size, dtype=int) + mesh[0] = nloc + # ilist + mesh[16 : 16 + nloc] = np.arange(nloc) + # numnei + mesh[16 + nloc : 16 + nloc * 2] = first_neigh[1:] - first_neigh[:-1] + # jlist + mesh[16 + nloc * 2 :] = pair_second + + # natoms_vec + natoms_vec = np.zeros(self.ntypes + 2).astype(int) + natoms_vec[0] = nloc + natoms_vec[1] = nloc + nghost + for ii in range(self.ntypes): + natoms_vec[ii + 2] = np.count_nonzero(atype == ii) + # imap append ghost atoms + imap = np.concatenate((imap, np.arange(nloc, nloc + nghost))) + return natoms_vec, all_coords, all_atype, mesh, imap, ghost_map diff --git a/deepmd/infer/deep_polar.py b/deepmd/infer/deep_polar.py index 118f8c98a7..c1f981ef86 100644 --- a/deepmd/infer/deep_polar.py +++ b/deepmd/infer/deep_polar.py @@ -30,6 +30,8 @@ class DeepPolar(DeepTensor): If uses the default tf graph, otherwise build a new tf graph for evaluation input_map : dict, optional The input map for tf.import_graph_def. Only work with default tf graph + neighbor_list : ase.neighborlist.NeighborList, optional + The neighbor list object. If None, then build the native neighbor list. Warnings -------- @@ -44,6 +46,7 @@ def __init__( load_prefix: str = "load", default_tf_graph: bool = False, input_map: Optional[dict] = None, + neighbor_list=None, ) -> None: # use this in favor of dict update to move attribute from class to # instance namespace @@ -61,6 +64,7 @@ def __init__( load_prefix=load_prefix, default_tf_graph=default_tf_graph, input_map=input_map, + neighbor_list=neighbor_list, ) def get_dim_fparam(self) -> int: @@ -83,10 +87,16 @@ class DeepGlobalPolar(DeepTensor): The prefix in the load computational graph default_tf_graph : bool If uses the default tf graph, otherwise build a new tf graph for evaluation + neighbor_list : ase.neighborlist.NeighborList, optional + The neighbor list object. If None, then build the native neighbor list. """ def __init__( - self, model_file: str, load_prefix: str = "load", default_tf_graph: bool = False + self, + model_file: str, + load_prefix: str = "load", + default_tf_graph: bool = False, + neighbor_list=None, ) -> None: self.tensors.update( { @@ -101,6 +111,7 @@ def __init__( model_file, load_prefix=load_prefix, default_tf_graph=default_tf_graph, + neighbor_list=None, ) def eval( diff --git a/deepmd/infer/deep_pot.py b/deepmd/infer/deep_pot.py index fc9a6a76ed..81cfdde7a8 100644 --- a/deepmd/infer/deep_pot.py +++ b/deepmd/infer/deep_pot.py @@ -51,6 +51,9 @@ class DeepPot(DeepEval): as the initial batch size. input_map : dict, optional The input map for tf.import_graph_def. Only work with default tf graph + neighbor_list : ase.neighborlist.NewPrimitiveNeighborList, optional + The ASE neighbor list class to produce the neighbor list. If None, the + neighbor list will be built natively in the model. Examples -------- @@ -78,6 +81,7 @@ def __init__( default_tf_graph: bool = False, auto_batch_size: Union[bool, int, AutoBatchSize] = True, input_map: Optional[dict] = None, + neighbor_list=None, ) -> None: # add these tensors on top of what is defined by DeepTensor Class # use this in favor of dict update to move attribute from class to @@ -112,6 +116,7 @@ def __init__( default_tf_graph=default_tf_graph, auto_batch_size=auto_batch_size, input_map=input_map, + neighbor_list=neighbor_list, ) # load optional tensors @@ -479,8 +484,30 @@ def _prepare_feed_dict( aparam = np.reshape(aparam, [nframes, natoms * fdim]) # make natoms_vec and default_mesh - natoms_vec = self.make_natoms_vec(atom_types, mixed_type=mixed_type) - assert natoms_vec[0] == natoms + if self.neighbor_list is None: + natoms_vec = self.make_natoms_vec(atom_types, mixed_type=mixed_type) + assert natoms_vec[0] == natoms + mesh = make_default_mesh(pbc, mixed_type) + ghost_map = None + else: + if nframes > 1: + raise NotImplementedError( + "neighbor_list does not support multiple frames" + ) + ( + natoms_vec, + coords, + atom_types, + mesh, + imap, + ghost_map, + ) = self.build_neighbor_list( + coords, + cells if cells is not None else None, + atom_types, + imap, + self.neighbor_list, + ) # evaluate feed_dict_test = {} @@ -501,12 +528,12 @@ def _prepare_feed_dict( raise RuntimeError if self.has_efield: feed_dict_test[self.t_efield] = np.reshape(efield, [-1]) - feed_dict_test[self.t_mesh] = make_default_mesh(pbc, mixed_type) + feed_dict_test[self.t_mesh] = mesh if self.has_fparam: feed_dict_test[self.t_fparam] = np.reshape(fparam, [-1]) if self.has_aparam: feed_dict_test[self.t_aparam] = np.reshape(aparam, [-1]) - return feed_dict_test, imap, natoms_vec + return feed_dict_test, imap, natoms_vec, ghost_map def _eval_inner( self, @@ -522,10 +549,13 @@ def _eval_inner( natoms, nframes = self._get_natoms_and_nframes( coords, atom_types, mixed_type=mixed_type ) - feed_dict_test, imap, natoms_vec = self._prepare_feed_dict( + feed_dict_test, imap, natoms_vec, ghost_map = self._prepare_feed_dict( coords, cells, atom_types, fparam, aparam, efield, mixed_type=mixed_type ) + nloc = natoms_vec[0] + nall = natoms_vec[1] + t_out = [self.t_energy, self.t_force, self.t_virial] if atomic: t_out += [self.t_ae, self.t_av] @@ -548,6 +578,13 @@ def _eval_inner( ) else: natoms_real = natoms + if ghost_map is not None: + # add the value of ghost atoms to real atoms + force = np.reshape(force, [nframes, -1, 3]) + np.add.at(force[0], ghost_map, force[0, nloc:]) + if atomic: + av = np.reshape(av, [nframes, -1, 9]) + np.add.at(av[0], ghost_map, av[0, nloc:]) # reverse map of the outputs force = self.reverse_map(np.reshape(force, [nframes, -1, 3]), imap) @@ -556,11 +593,15 @@ def _eval_inner( av = self.reverse_map(np.reshape(av, [nframes, -1, 9]), imap) energy = np.reshape(energy, [nframes, 1]) - force = np.reshape(force, [nframes, natoms, 3]) + force = np.reshape(force, [nframes, nall, 3]) + if nloc < nall: + force = force[:, :nloc, :] virial = np.reshape(virial, [nframes, 9]) if atomic: ae = np.reshape(ae, [nframes, natoms_real, 1]) - av = np.reshape(av, [nframes, natoms, 9]) + av = np.reshape(av, [nframes, nall, 9]) + if nloc < nall: + av = av[:, :nloc, :] return energy, force, virial, ae, av else: return energy, force, virial @@ -640,10 +681,11 @@ def _eval_descriptor_inner( natoms, nframes = self._get_natoms_and_nframes( coords, atom_types, mixed_type=mixed_type ) - feed_dict_test, imap, natoms_vec = self._prepare_feed_dict( + feed_dict_test, imap, natoms_vec, ghost_map = self._prepare_feed_dict( coords, cells, atom_types, fparam, aparam, efield, mixed_type=mixed_type ) (descriptor,) = run_sess( self.sess, [self.t_descriptor], feed_dict=feed_dict_test ) + imap = imap[:natoms] return self.reverse_map(np.reshape(descriptor, [nframes, natoms, -1]), imap) diff --git a/deepmd/infer/deep_tensor.py b/deepmd/infer/deep_tensor.py index 268523e959..a803eb0c6b 100644 --- a/deepmd/infer/deep_tensor.py +++ b/deepmd/infer/deep_tensor.py @@ -39,6 +39,8 @@ class DeepTensor(DeepEval): If uses the default tf graph, otherwise build a new tf graph for evaluation input_map : dict, optional The input map for tf.import_graph_def. Only work with default tf graph + neighbor_list : ase.neighborlist.NeighborList, optional + The neighbor list object. If None, then build the native neighbor list. """ tensors: ClassVar[Dict[str, str]] = { @@ -63,6 +65,7 @@ def __init__( load_prefix: str = "load", default_tf_graph: bool = False, input_map: Optional[dict] = None, + neighbor_list=None, ) -> None: """Constructor.""" DeepEval.__init__( @@ -71,6 +74,7 @@ def __init__( load_prefix=load_prefix, default_tf_graph=default_tf_graph, input_map=input_map, + neighbor_list=neighbor_list, ) # check model type model_type = self.tensors["t_tensor"][2:-2] @@ -209,8 +213,29 @@ def eval( ) # make natoms_vec and default_mesh - natoms_vec = self.make_natoms_vec(atom_types, mixed_type=mixed_type) - assert natoms_vec[0] == natoms + if self.neighbor_list is None: + natoms_vec = self.make_natoms_vec(atom_types, mixed_type=mixed_type) + assert natoms_vec[0] == natoms + mesh = make_default_mesh(pbc, mixed_type) + else: + if nframes > 1: + raise NotImplementedError( + "neighbor_list does not support multiple frames" + ) + ( + natoms_vec, + coords, + atom_types, + mesh, + imap, + _, + ) = self.build_neighbor_list( + coords, + cells if cells is not None else None, + atom_types, + imap, + self.neighbor_list, + ) # evaluate feed_dict_test = {} @@ -223,7 +248,7 @@ def eval( ) feed_dict_test[self.t_coord] = np.reshape(coords, [-1]) feed_dict_test[self.t_box] = np.reshape(cells, [-1]) - feed_dict_test[self.t_mesh] = make_default_mesh(pbc, mixed_type) + feed_dict_test[self.t_mesh] = mesh if atomic: assert ( @@ -333,8 +358,30 @@ def eval_full( ) # make natoms_vec and default_mesh - natoms_vec = self.make_natoms_vec(atom_types, mixed_type=mixed_type) - assert natoms_vec[0] == natoms + if self.neighbor_list is None: + natoms_vec = self.make_natoms_vec(atom_types, mixed_type=mixed_type) + assert natoms_vec[0] == natoms + mesh = make_default_mesh(pbc, mixed_type) + ghost_map = None + else: + if nframes > 1: + raise NotImplementedError( + "neighbor_list does not support multiple frames" + ) + ( + natoms_vec, + coords, + atom_types, + mesh, + imap, + ghost_map, + ) = self.build_neighbor_list( + coords, + cells if cells is not None else None, + atom_types, + imap, + self.neighbor_list, + ) # evaluate feed_dict_test = {} @@ -347,7 +394,7 @@ def eval_full( ) feed_dict_test[self.t_coord] = np.reshape(coords, [-1]) feed_dict_test[self.t_box] = np.reshape(cells, [-1]) - feed_dict_test[self.t_mesh] = make_default_mesh(pbc, mixed_type) + feed_dict_test[self.t_mesh] = mesh t_out = [self.t_global_tensor, self.t_force, self.t_virial] if atomic: @@ -361,21 +408,39 @@ def eval_full( at = v_out[3] # atom tensor av = v_out[4] # atom virial + nloc = natoms_vec[0] + nall = natoms_vec[1] + + if ghost_map is not None: + # add the value of ghost atoms to real atoms + force = np.reshape(force, [nframes * nout, -1, 3]) + # TODO: is there some way not to use for loop? + for ii in range(nframes * nout): + np.add.at(force[ii], ghost_map, force[ii, nloc:]) + if atomic: + av = np.reshape(av, [nframes * nout, -1, 9]) + for ii in range(nframes * nout): + np.add.at(av[ii], ghost_map, av[ii, nloc:]) + # please note here the shape are wrong! - force = self.reverse_map(np.reshape(force, [nframes * nout, natoms, 3]), imap) + force = self.reverse_map(np.reshape(force, [nframes * nout, nall, 3]), imap) if atomic: at = self.reverse_map( np.reshape(at, [nframes, len(sel_at), nout]), sel_imap ) - av = self.reverse_map(np.reshape(av, [nframes * nout, natoms, 9]), imap) + av = self.reverse_map(np.reshape(av, [nframes * nout, nall, 9]), imap) # make sure the shapes are correct here gt = np.reshape(gt, [nframes, nout]) - force = np.reshape(force, [nframes, nout, natoms, 3]) + force = np.reshape(force, [nframes, nout, nall, 3]) + if nloc < nall: + force = force[:, :, :nloc, :] virial = np.reshape(virial, [nframes, nout, 9]) if atomic: at = np.reshape(at, [nframes, len(sel_at), self.output_dim]) - av = np.reshape(av, [nframes, nout, natoms, 9]) + av = np.reshape(av, [nframes, nout, nall, 9]) + if nloc < nall: + av = av[:, :, :nloc, :] return gt, force, virial, at, av else: return gt, force, virial diff --git a/source/tests/test_deepdipole.py b/source/tests/test_deepdipole.py index e26ad84a55..1d06b5fe92 100644 --- a/source/tests/test_deepdipole.py +++ b/source/tests/test_deepdipole.py @@ -2,6 +2,7 @@ import os import unittest +import ase.neighborlist import numpy as np from common import ( finite_difference, @@ -964,10 +965,6 @@ def test_1frame_full_atm(self): gt, ff, vv, at, av = self.dp.eval_full( self.coords, self.box, self.atype, atomic=True ) - for dd in at, ff, av: - print("\n\n") - print(", ".join(f"{ii:.18e}" for ii in dd.reshape(-1))) - print("\n\n") # check shape of the returns nframes = 1 natoms = len(self.atype) @@ -1035,3 +1032,30 @@ def test_1frame_full_atm_shuffle(self): np.testing.assert_almost_equal( vv.reshape([-1]), self.expected_gv.reshape([-1]), decimal=default_places ) + + +@unittest.skipIf( + parse_version(tf.__version__) < parse_version("1.15"), + f"The current tf version {tf.__version__} is too low to run the new testing model.", +) +class TestDeepDipoleNewPBCNeighborList(TestDeepDipoleNewPBC): + @classmethod + def setUpClass(cls): + convert_pbtxt_to_pb( + str(tests_path / os.path.join("infer", "deepdipole_new.pbtxt")), + "deepdipole_new.pb", + ) + cls.dp = DeepDipole( + "deepdipole_new.pb", + neighbor_list=ase.neighborlist.NewPrimitiveNeighborList( + cutoffs=6, bothways=True + ), + ) + + @unittest.skip("multiple frames not supported") + def test_2frame_full_atm(self): + pass + + @unittest.skip("multiple frames not supported") + def test_2frame_old_atm(self): + pass diff --git a/source/tests/test_deeppolar.py b/source/tests/test_deeppolar.py index 271d1650c0..9627851de4 100644 --- a/source/tests/test_deeppolar.py +++ b/source/tests/test_deeppolar.py @@ -2,6 +2,7 @@ import os import unittest +import ase.neighborlist import numpy as np from common import ( tests_path, @@ -980,12 +981,6 @@ def test_1frame_full_atm(self): self.coords, self.box, self.atype, atomic=True ) - # print the values - for dd in (at, ff, av): - print("\n\n") - print(", ".join(f"{i:.18e}" for i in dd.reshape(-1))) - print("\n\n") - # check shape of the returns nframes = 1 natoms = len(self.atype) @@ -1088,3 +1083,30 @@ def test_2frame_full_atm(self): np.testing.assert_almost_equal( vv.reshape([-1]), expected_gv.reshape([-1]), decimal=default_places ) + + +@unittest.skipIf( + parse_version(tf.__version__) < parse_version("1.15"), + f"The current tf version {tf.__version__} is too low to run the new testing model.", +) +class TestDeepPolarNewPBCNeighborList(unittest.TestCase): + @classmethod + def setUpClass(cls): + convert_pbtxt_to_pb( + str(tests_path / os.path.join("infer", "deeppolar_new.pbtxt")), + "deeppolar_new.pb", + ) + cls.dp = DeepPolar( + "deeppolar_new.pb", + neighbor_list=ase.neighborlist.NewPrimitiveNeighborList( + cutoffs=6, bothways=True + ), + ) + + @unittest.skip("multiple frames not supported") + def test_2frame_full_atm(self): + pass + + @unittest.skip("multiple frames not supported") + def test_2frame_old_atm(self): + pass diff --git a/source/tests/test_deeppot_a.py b/source/tests/test_deeppot_a.py index 1c6cdc4afc..c229b4302c 100644 --- a/source/tests/test_deeppot_a.py +++ b/source/tests/test_deeppot_a.py @@ -3,6 +3,7 @@ import shutil import unittest +import ase.neighborlist import numpy as np from common import ( run_dp, @@ -1096,3 +1097,25 @@ def test_2frame_atm_all_param(self): np.testing.assert_almost_equal(ee.ravel(), expected_se.ravel(), default_places) expected_sv = np.sum(expected_v.reshape([nframes, -1, 9]), axis=1) np.testing.assert_almost_equal(vv.ravel(), expected_sv.ravel(), default_places) + + +class TestDeepPotAPBCNeighborList(TestDeepPotAPBC): + @classmethod + def setUpClass(cls): + convert_pbtxt_to_pb( + str(tests_path / os.path.join("infer", "deeppot.pbtxt")), "deeppot.pb" + ) + cls.dp = DeepPot( + "deeppot.pb", + neighbor_list=ase.neighborlist.NewPrimitiveNeighborList( + cutoffs=6, bothways=True + ), + ) + + @unittest.skip("multiple frames not supported") + def test_2frame_atm(self): + pass + + @unittest.skip("Zero atoms not supported") + def test_zero_input(self): + pass From 2204ec197d669445e812139b0c16239ea72672f7 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 11 Dec 2023 00:23:37 -0500 Subject: [PATCH 35/97] fix GPU mapping error for Horovod + finetune (#3048) When fine-tuning with Horovod, the same error as https://github.com/deepmodeling/deepmd-kit/issues/2712 is thrown at the place I modified in this PR. It seems `tf.test.is_gpu_available` will try to use all GPUs, but `tf.config.get_visible_devices` won't. --------- Signed-off-by: Jinzhe Zeng Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- deepmd/utils/batch_size.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/deepmd/utils/batch_size.py b/deepmd/utils/batch_size.py index 2b3117d849..fe876a65a5 100644 --- a/deepmd/utils/batch_size.py +++ b/deepmd/utils/batch_size.py @@ -7,8 +7,12 @@ ) import numpy as np +from packaging.version import ( + Version, +) from deepmd.env import ( + TF_VERSION, tf, ) from deepmd.utils.errors import ( @@ -59,7 +63,10 @@ def __init__(self, initial_batch_size: int = 1024, factor: float = 2.0) -> None: self.minimal_not_working_batch_size = self.maximum_working_batch_size + 1 else: self.maximum_working_batch_size = initial_batch_size - if tf.test.is_gpu_available(): + if ( + Version(TF_VERSION) >= Version("1.14") + and tf.config.experimental.get_visible_devices("GPU") + ) or tf.test.is_gpu_available(): self.minimal_not_working_batch_size = 2**31 else: self.minimal_not_working_batch_size = ( From 7648d7ad9bff931a47f62a0b21f775905cb0d046 Mon Sep 17 00:00:00 2001 From: nahso <47053538+nahso@users.noreply.github.com> Date: Tue, 12 Dec 2023 09:02:38 +0800 Subject: [PATCH 36/97] remove unused codes in se_a.py (#3049) --- deepmd/descriptor/se_a.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/deepmd/descriptor/se_a.py b/deepmd/descriptor/se_a.py index 9beec2db1d..721bb0d534 100644 --- a/deepmd/descriptor/se_a.py +++ b/deepmd/descriptor/se_a.py @@ -1002,13 +1002,6 @@ def _filter_lower( [-1, two_side_type_embedding.shape[-1]], ) - atype_expand = tf.reshape(self.atype_nloc, [-1, 1]) - idx_i = tf.tile(atype_expand * padding_ntypes, [1, self.nnei]) - idx_j = tf.reshape(self.nei_type_vec, [-1, self.nnei]) - idx = idx_i + idx_j - index_of_two_side = tf.reshape(idx, [-1]) - self.extra_embedding_index = index_of_two_side - net_output = embedding_net( two_side_type_embedding, self.filter_neuron, From 406e8f77005d992af80c3936e268d30444d1684b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 09:03:15 +0800 Subject: [PATCH 37/97] Bump actions/deploy-pages from 2 to 3 (#3052) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/deploy-pages](https://github.com/actions/deploy-pages) from 2 to 3.
Release notes

Sourced from actions/deploy-pages's releases.

v3.0.0

Changelog


See details of all code changes since previous release.

:warning: For use with products other than GitHub.com, such as GitHub Enterprise Server, please consult the compatibility table.

v2.0.5

Changelog


See details of all code changes since previous release.

:warning: For use with products other than GitHub.com, such as GitHub Enterprise Server, please consult the compatibility table.

v2.0.4

Changelog


See details of all code changes since previous release.

... (truncated)

Commits
  • 13b55b3 Merge pull request #272 from kbdharun/main
  • c284911 chore/docs: update version, fix typos
  • ae44070 Merge pull request #266 from actions/dependabot/npm_and_yarn/eslint-8.55.0
  • 34a8f60 Bump eslint from 8.54.0 to 8.55.0
  • b65643c Merge pull request #267 from actions/dependabot/npm_and_yarn/nock-13.4.0
  • faceed1 Bump nock from 13.3.8 to 13.4.0
  • 230466c Merge pull request #268 from actions/dependabot/npm_and_yarn/eslint-config-pr...
  • 38d34f8 Bump eslint-config-prettier from 9.0.0 to 9.1.0
  • cd33125 Merge pull request #269 from actions/dependabot/npm_and_yarn/actions/core-1.10.1
  • dd970ae Update distributables after Dependabot 🤖
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/deploy-pages&package-manager=github_actions&previous-version=2&new-version=3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_wheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 67241e6e23..174d803146 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -189,7 +189,7 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@v3 pass: name: Pass testing build wheels From 8db5e6a33fa05d8bb118265f2101dc566dd92b55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 09:04:06 +0800 Subject: [PATCH 38/97] Bump actions/setup-python from 4 to 5 (#3051) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
Release notes

Sourced from actions/setup-python's releases.

v5.0.0

What's Changed

In scope of this release, we update node version runtime from node16 to node20 (actions/setup-python#772). Besides, we update dependencies to the latest versions.

Full Changelog: https://github.com/actions/setup-python/compare/v4.8.0...v5.0.0

v4.8.0

What's Changed

In scope of this release we added support for GraalPy (actions/setup-python#694). You can use this snippet to set up GraalPy:

steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
  with:
    python-version: 'graalpy-22.3'
- run: python my_script.py

Besides, the release contains such changes as:

New Contributors

Full Changelog: https://github.com/actions/setup-python/compare/v4...v4.8.0

v4.7.1

What's Changed

Full Changelog: https://github.com/actions/setup-python/compare/v4...v4.7.1

v4.7.0

In scope of this release, the support for reading python version from pyproject.toml was added (actions/setup-python#669).

      - name: Setup Python
        uses: actions/setup-python@v4
</tr></table>

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-python&package-manager=github_actions&previous-version=4&new-version=5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_cc.yml | 2 +- .github/workflows/build_wheel.yml | 4 ++-- .github/workflows/test_cc.yml | 2 +- .github/workflows/test_cuda.yml | 2 +- .github/workflows/test_python.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build_cc.yml b/.github/workflows/build_cc.yml index e6377f4fab..f029517d80 100644 --- a/.github/workflows/build_cc.yml +++ b/.github/workflows/build_cc.yml @@ -21,7 +21,7 @@ jobs: dp_variant: clang steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.11' cache: 'pip' diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 174d803146..e700109cce 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -87,7 +87,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 name: Install Python with: python-version: '3.11' @@ -164,7 +164,7 @@ jobs: with: name: artifact path: dist/packages - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 name: Install Python with: python-version: '3.11' diff --git a/.github/workflows/test_cc.yml b/.github/workflows/test_cc.yml index a98afa7a94..ef6fade8e5 100644 --- a/.github/workflows/test_cc.yml +++ b/.github/workflows/test_cc.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.11' cache: 'pip' diff --git a/.github/workflows/test_cuda.yml b/.github/workflows/test_cuda.yml index d8eddaa44f..e74c0abde2 100644 --- a/.github/workflows/test_cuda.yml +++ b/.github/workflows/test_cuda.yml @@ -18,7 +18,7 @@ jobs: - name: Make sudo and git work run: apt-get update && apt-get install -y sudo git - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.11' # cache: 'pip' diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml index b6011cb523..1bd78bfae0 100644 --- a/.github/workflows/test_python.yml +++ b/.github/workflows/test_python.yml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} cache: 'pip' From 558051e94d8a43a4b3eaa5637348200ee843f312 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 09:04:44 +0800 Subject: [PATCH 39/97] Bump actions/labeler from 4 to 5 (#3050) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/labeler](https://github.com/actions/labeler) from 4 to 5.
Release notes

Sourced from actions/labeler's releases.

v5.0.0

What's Changed

This release contains the following breaking changes:

  1. The ability to apply labels based on the names of base and/or head branches was added (#186 and #54). The match object for changed files was expanded with new combinations in order to make it more intuitive and flexible (#423 and #101). As a result, the configuration file structure was significantly redesigned and is not compatible with the structure of the previous version. Please read the action documentation to find out how to adapt your configuration files for use with the new action version.

  2. The bug related to the sync-labels input was fixed (#112). Now the input value is read correctly.

  3. By default, dot input is set to true. Now, paths starting with a dot (e.g. .github) are matched by default.

  4. Version 5 of this action updated the runtime to Node.js 20. All scripts are now run with Node.js 20 instead of Node.js 16 and are affected by any breaking changes between Node.js 16 and 20.

For more information, please read the action documentation.

New Contributors

Full Changelog: https://github.com/actions/labeler/compare/v4...v5.0.0

v5.0.0-beta.1

What's Changed

In scope of this beta release, the structure of the configuration file (.github/labeler.yml) was changed from

LabelName:
- any:
  - changed-files: ['list', 'of', 'globs']
  - base-branch: ['list', 'of', 'regexps']
  - head-branch: ['list', 'of', 'regexps']
- all:
  - changed-files: ['list', 'of', 'globs']
  - base-branch: ['list', 'of', 'regexps']
  - head-branch: ['list', 'of', 'regexps']

to

LabelName:
- any:
  - changed-files:
    - AnyGlobToAnyFile: ['list', 'of', 'globs']
    - AnyGlobToAllFiles: ['list', 'of', 'globs']
    - AllGlobsToAnyFile: ['list', 'of', 'globs']
    - AllGlobsToAllFiles: ['list', 'of', 'globs']
  - base-branch: ['list', 'of', 'regexps']
  - head-branch: ['list', 'of', 'regexps']
- all:
  - changed-files:
    - AnyGlobToAnyFile: ['list', 'of', 'globs']
    - AnyGlobToAllFiles: ['list', 'of', 'globs']
    - AllGlobsToAnyFile: ['list', 'of', 'globs']
</tr></table>

... (truncated)

Commits
  • 8558fd7 Merge pull request #709 from actions/v5.0.0-beta
  • 000ca75 Merge pull request #700 from MaksimZhukov/apply-suggestions-and-update-docume...
  • cb66c2f Update dist
  • 9181355 Apply suggestions for the beta vesrion and update the documentation
  • efe4c1c Merge pull request #699 from MaksimZhukov/update-node-runtime-and-dependencies
  • c0957ad Run Prettier
  • 8dc8d18 Update Node.js version in reusable workflows
  • d0d0bbe Update documentation
  • 1375c42 5.0.0
  • ab7411e Change version of Node.js runtime to node20
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/labeler&package-manager=github_actions&previous-version=4&new-version=5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/labeler.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 2c8ba30ba1..877c780f1f 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -9,6 +9,6 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v4 + - uses: actions/labeler@v5 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" From 33c2c8d6d95ddc540cdd397564eb6e5b90718c3f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 09:08:09 +0800 Subject: [PATCH 40/97] [pre-commit.ci] pre-commit autoupdate (#3055) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/isort: 5.12.0 → 5.13.0](https://github.com/PyCQA/isort/compare/5.12.0...5.13.0) - [github.com/astral-sh/ruff-pre-commit: v0.1.6 → v0.1.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.6...v0.1.7) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 64a061dd54..ce83792f10 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,14 +23,14 @@ repos: - id: check-toml # Python - repo: https://github.com/PyCQA/isort - rev: 5.12.0 + rev: 5.13.0 hooks: - id: isort files: \.py$ exclude: ^source/3rdparty - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.6 + rev: v0.1.7 hooks: - id: ruff args: ["--fix"] From e5c9c590cab12d8dd9e8d509706547d155f1bf9f Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 11 Dec 2023 20:09:55 -0500 Subject: [PATCH 41/97] docs: document external neighbor list (#3056) Signed-off-by: Jinzhe Zeng Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- doc/inference/python.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/inference/python.md b/doc/inference/python.md index 48eb1d7df0..b5d3ca1efc 100644 --- a/doc/inference/python.md +++ b/doc/inference/python.md @@ -27,3 +27,20 @@ model_devi = calc_model_devi(coord, cell, atype, graphs) ``` Note that if the model inference or model deviation is performed cyclically, one should avoid calling the same model multiple times. Otherwise, tensorFlow will never release the memory and this may lead to an out-of-memory (OOM) error. + +## External neighbor list algorithm + +The native neighbor list algorithm of the DeePMD-kit is in $O(N^2)$ complexity ($N$ is the number of atoms). +While this is not a problem for small systems that quantum methods can afford, the large systems for molecular dynamics have slow performance. +In this case, one may pass an external neighbor list that has lower complexity to {class}`DeepPot `, once it is compatible with {class}`ase.neighborlist.NewPrimitiveNeighborList`. + +```py +import ase.neighborlist + +neighbor_list = ase.neighborlist.NewPrimitiveNeighborList( + cutoffs=6, bothways=True, self_interaction=False +) +dp = DeepPot("graph.pb", neighbor_list=neighbor_list) +``` + +The `update` and `build` methods will be called by {class}`DeepPot `, and `first_neigh`, `pair_second`, and `offset_vec` properties will be used. From ddfa7819435d1665f1bae18460ec57665f0a9610 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 11 Dec 2023 20:10:37 -0500 Subject: [PATCH 42/97] print NaN loss when labeled data is not found (#3047) Currently, when loss is defined and the labeled data is not found, `lcurve.out` shows wrong RMSE (assuming data is all zero). In this case, printing NaN is better. --------- Signed-off-by: Jinzhe Zeng --- deepmd/loss/dos.py | 12 +++++++---- deepmd/loss/ener.py | 44 +++++++++++++++++++++++++++++------------ deepmd/loss/loss.py | 19 ++++++++++++++++++ deepmd/loss/tensor.py | 4 ++-- deepmd/train/trainer.py | 1 + 5 files changed, 61 insertions(+), 19 deletions(-) diff --git a/deepmd/loss/dos.py b/deepmd/loss/dos.py index fa30552486..7d38f2b17a 100644 --- a/deepmd/loss/dos.py +++ b/deepmd/loss/dos.py @@ -143,16 +143,20 @@ def build(self, learning_rate, natoms, model_dict, label_dict, suffix): more_loss = {} if self.has_dos: l2_loss += atom_norm_ener * (pref_dos * l2_dos_loss) - more_loss["l2_dos_loss"] = l2_dos_loss + more_loss["l2_dos_loss"] = self.display_if_exist(l2_dos_loss, find_dos) if self.has_cdf: l2_loss += atom_norm_ener * (pref_cdf * l2_cdf_loss) - more_loss["l2_cdf_loss"] = l2_cdf_loss + more_loss["l2_cdf_loss"] = self.display_if_exist(l2_cdf_loss, find_dos) if self.has_ados: l2_loss += global_cvt_2_ener_float(pref_ados * l2_atom_dos_loss) - more_loss["l2_atom_dos_loss"] = l2_atom_dos_loss + more_loss["l2_atom_dos_loss"] = self.display_if_exist( + l2_atom_dos_loss, find_atom_dos + ) if self.has_acdf: l2_loss += global_cvt_2_ener_float(pref_acdf * l2_atom_cdf_loss) - more_loss["l2_atom_cdf_loss"] = l2_atom_cdf_loss + more_loss["l2_atom_cdf_loss"] = self.display_if_exist( + l2_atom_cdf_loss, find_atom_dos + ) # only used when tensorboard was set as true self.l2_loss_summary = tf.summary.scalar("l2_loss_" + suffix, tf.sqrt(l2_loss)) diff --git a/deepmd/loss/ener.py b/deepmd/loss/ener.py index 95997bad10..d7f83f09e5 100644 --- a/deepmd/loss/ener.py +++ b/deepmd/loss/ener.py @@ -291,22 +291,32 @@ def build(self, learning_rate, natoms, model_dict, label_dict, suffix): more_loss = {} if self.has_e: l2_loss += atom_norm_ener * (pref_e * l2_ener_loss) - more_loss["l2_ener_loss"] = l2_ener_loss + more_loss["l2_ener_loss"] = self.display_if_exist(l2_ener_loss, find_energy) if self.has_f: l2_loss += global_cvt_2_ener_float(pref_f * l2_force_loss) - more_loss["l2_force_loss"] = l2_force_loss + more_loss["l2_force_loss"] = self.display_if_exist( + l2_force_loss, find_force + ) if self.has_v: l2_loss += global_cvt_2_ener_float(atom_norm * (pref_v * l2_virial_loss)) - more_loss["l2_virial_loss"] = l2_virial_loss + more_loss["l2_virial_loss"] = self.display_if_exist( + l2_virial_loss, find_virial + ) if self.has_ae: l2_loss += global_cvt_2_ener_float(pref_ae * l2_atom_ener_loss) - more_loss["l2_atom_ener_loss"] = l2_atom_ener_loss + more_loss["l2_atom_ener_loss"] = self.display_if_exist( + l2_atom_ener_loss, find_atom_ener + ) if self.has_pf: l2_loss += global_cvt_2_ener_float(pref_pf * l2_pref_force_loss) - more_loss["l2_pref_force_loss"] = l2_pref_force_loss + more_loss["l2_pref_force_loss"] = self.display_if_exist( + l2_pref_force_loss, find_atom_pref + ) if self.has_gf: l2_loss += global_cvt_2_ener_float(pref_gf * l2_gen_force_loss) - more_loss["l2_gen_force_loss"] = l2_gen_force_loss + more_loss["l2_gen_force_loss"] = self.display_if_exist( + l2_gen_force_loss, find_drdq + ) # only used when tensorboard was set as true self.l2_loss_summary = tf.summary.scalar("l2_loss_" + suffix, tf.sqrt(l2_loss)) @@ -553,19 +563,25 @@ def build(self, learning_rate, natoms, model_dict, label_dict, suffix): more_loss = {} if self.has_e: l2_loss += atom_norm_ener * (pref_e * l2_ener_loss) - more_loss["l2_ener_loss"] = l2_ener_loss + more_loss["l2_ener_loss"] = self.display_if_exist(l2_ener_loss, find_energy) if self.has_fr: l2_loss += global_cvt_2_ener_float(pref_fr * l2_force_r_loss) - more_loss["l2_force_r_loss"] = l2_force_r_loss + more_loss["l2_force_r_loss"] = self.display_if_exist( + l2_force_r_loss, find_force + ) if self.has_fm: l2_loss += global_cvt_2_ener_float(pref_fm * l2_force_m_loss) - more_loss["l2_force_m_loss"] = l2_force_m_loss + more_loss["l2_force_m_loss"] = self.display_if_exist( + l2_force_m_loss, find_force + ) if self.has_v: l2_loss += global_cvt_2_ener_float(atom_norm * (pref_v * l2_virial_loss)) - more_loss["l2_virial_loss"] = l2_virial_loss + more_loss["l2_virial_loss"] = self.display_if_exist(l2_virial_loss, find_virial) if self.has_ae: l2_loss += global_cvt_2_ener_float(pref_ae * l2_atom_ener_loss) - more_loss["l2_atom_ener_loss"] = l2_atom_ener_loss + more_loss["l2_atom_ener_loss"] = self.display_if_exist( + l2_atom_ener_loss, find_atom_ener + ) # only used when tensorboard was set as true self.l2_loss_summary = tf.summary.scalar("l2_loss", tf.sqrt(l2_loss)) @@ -785,8 +801,10 @@ def build(self, learning_rate, natoms, model_dict, label_dict, suffix): more_loss = {} l2_loss += atom_norm_ener * (pref_e * l2_ener_loss) l2_loss += global_cvt_2_ener_float(pref_ed * l2_ener_dipole_loss) - more_loss["l2_ener_loss"] = l2_ener_loss - more_loss["l2_ener_dipole_loss"] = l2_ener_dipole_loss + more_loss["l2_ener_loss"] = self.display_if_exist(l2_ener_loss, find_energy) + more_loss["l2_ener_dipole_loss"] = self.display_if_exist( + l2_ener_dipole_loss, find_ener_dipole + ) self.l2_loss_summary = tf.summary.scalar("l2_loss_" + suffix, tf.sqrt(l2_loss)) self.l2_loss_ener_summary = tf.summary.scalar( diff --git a/deepmd/loss/loss.py b/deepmd/loss/loss.py index 9324077691..a719a08d81 100644 --- a/deepmd/loss/loss.py +++ b/deepmd/loss/loss.py @@ -8,6 +8,8 @@ Tuple, ) +import numpy as np + from deepmd.env import ( tf, ) @@ -72,3 +74,20 @@ def eval( A dictionary that maps keys to values. It should contain key `natoms` """ + + @staticmethod + def display_if_exist(loss: tf.Tensor, find_property: float) -> tf.Tensor: + """Display NaN if labeled property is not found. + + Parameters + ---------- + loss : tf.Tensor + the loss tensor + find_property : float + whether the property is found + """ + return tf.cond( + tf.cast(find_property, tf.bool), + lambda: loss, + lambda: tf.cast(np.nan, dtype=loss.dtype), + ) diff --git a/deepmd/loss/tensor.py b/deepmd/loss/tensor.py index 74eb2b74dc..a40f95a18e 100644 --- a/deepmd/loss/tensor.py +++ b/deepmd/loss/tensor.py @@ -87,7 +87,7 @@ def build(self, learning_rate, natoms, model_dict, label_dict, suffix): local_loss = global_cvt_2_tf_float(find_atomic) * tf.reduce_mean( tf.square(self.scale * (polar - atomic_polar_hat)), name="l2_" + suffix ) - more_loss["local_loss"] = local_loss + more_loss["local_loss"] = self.display_if_exist(local_loss, find_atomic) l2_loss += self.local_weight * local_loss self.l2_loss_local_summary = tf.summary.scalar( "l2_local_loss_" + suffix, tf.sqrt(more_loss["local_loss"]) @@ -118,7 +118,7 @@ def build(self, learning_rate, natoms, model_dict, label_dict, suffix): tf.square(self.scale * (global_polar - polar_hat)), name="l2_" + suffix ) - more_loss["global_loss"] = global_loss + more_loss["global_loss"] = self.display_if_exist(global_loss, find_global) self.l2_loss_global_summary = tf.summary.scalar( "l2_global_loss_" + suffix, tf.sqrt(more_loss["global_loss"]) / global_cvt_2_tf_float(atoms), diff --git a/deepmd/train/trainer.py b/deepmd/train/trainer.py index bbcb305404..3b81740a93 100644 --- a/deepmd/train/trainer.py +++ b/deepmd/train/trainer.py @@ -943,6 +943,7 @@ def print_header(fp, train_results, valid_results, multi_task_mode=False): for k in train_results[fitting_key].keys(): print_str += prop_fmt % (k + "_trn") print_str += " %8s\n" % (fitting_key + "_lr") + print_str += "# If there is no available reference data, rmse_*_{val,trn} will print nan\n" fp.write(print_str) fp.flush() From 06cd3c1dd4d4ecfdbe3bf37f50c7fab70199c0ee Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Thu, 14 Dec 2023 03:13:20 -0500 Subject: [PATCH 43/97] fix labeler.yml with actions/labeler v5 (#3059) See https://github.com/actions/labeler/tree/main?tab=readme-ov-file#breaking-changes-in-v5; The action version was bumped by #3050 Signed-off-by: Jinzhe Zeng --- .github/labeler.yml | 52 +++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index 049c9badff..b0a85679de 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,15 +1,39 @@ Python: -- deepmd/**/* -- deepmd_utils/**/* -- source/tests/**/* -Docs: doc/**/* -Examples: examples/**/* -Core: source/lib/**/* -CUDA: source/lib/src/gpu/**/* -ROCM: source/lib/src/gpu/**/* -OP: source/op/**/* -C++: source/api_cc/**/* -C: source/api_c/**/* -LAMMPS: source/lmp/**/* -Gromacs: source/gmx/**/* -i-Pi: source/ipi/**/* +- changed-files: + - any-glob-to-any-file: + - deepmd/**/* + - deepmd_utils/**/* + - source/tests/**/* +Docs: +- changed-files: + - any-glob-to-any-file: doc/**/* +Examples: +- changed-files: + - any-glob-to-any-file: examples/**/* +Core: +- changed-files: + - any-glob-to-any-file: source/lib/**/* +CUDA: +- changed-files: + - any-glob-to-any-file: source/lib/src/gpu/**/* +ROCM: +- changed-files: + - any-glob-to-any-file: source/lib/src/gpu/**/* +OP: +- changed-files: + - any-glob-to-any-file: source/op/**/* +C++: +- changed-files: + - any-glob-to-any-file: source/api_cc/**/* +C: +- changed-files: + - any-glob-to-any-file: source/api_c/**/* +LAMMPS: +- changed-files: + - any-glob-to-any-file: source/lmp/**/* +Gromacs: +- changed-files: + - any-glob-to-any-file: source/gmx/**/* +i-Pi: +- changed-files: + - any-glob-to-any-file: source/ipi/**/* From 1a7e25209a234fc446fcb5b1ffdd1eee5a7df8af Mon Sep 17 00:00:00 2001 From: LiuGroupHNU <55585514+LiuGroupHNU@users.noreply.github.com> Date: Thu, 14 Dec 2023 16:31:36 +0800 Subject: [PATCH 44/97] nvnmd: init-model feature and 256 neighbors (#3058) 1. Add init-modele feature. you can initialize the CNN model by: `dp train-nvnmd train_cnn.json -s s1 -i nvnmd_cnn_bck/model.ckpt `. 2. The maximum number of neighbors has been increased to 256. 3. Update the doc of nvnmd. --------- Co-authored-by: LiuGroupHNU Co-authored-by: MoPinghui Co-authored-by: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- deepmd/fit/ener.py | 5 ++ deepmd/nvnmd/data/data.py | 46 ++++++++++++++ deepmd/nvnmd/descriptor/se_a.py | 9 ++- deepmd/nvnmd/descriptor/se_atten.py | 9 ++- deepmd/nvnmd/entrypoints/freeze.py | 2 + deepmd/nvnmd/entrypoints/mapt.py | 28 ++++++++- deepmd/nvnmd/entrypoints/train.py | 3 + deepmd/nvnmd/entrypoints/wrap.py | 56 ++++++++++++++--- deepmd/nvnmd/utils/argcheck.py | 2 + deepmd/nvnmd/utils/config.py | 52 +++++++++++++--- deepmd_utils/main.py | 16 +++++ doc/nvnmd/nvnmd.md | 11 ++++ examples/nvnmd/train/train_cnn.json | 1 + examples/nvnmd/train/train_qnn.json | 1 + source/op/prod_env_mat_multi_device_nvnmd.cc | 64 +++++++++++++++----- source/tests/test_nvnmd_entrypoints.py | 4 +- 16 files changed, 269 insertions(+), 40 deletions(-) diff --git a/deepmd/fit/ener.py b/deepmd/fit/ener.py index e74d4a7e6d..4c15e57124 100644 --- a/deepmd/fit/ener.py +++ b/deepmd/fit/ener.py @@ -514,6 +514,11 @@ def build( self.bias_atom_e[type_i] = self.bias_atom_e[type_i] self.bias_atom_e = self.bias_atom_e[:ntypes_atom] + if nvnmd_cfg.enable: + # fix the bug: CNN and QNN have different t_bias_atom_e. + if "t_bias_atom_e" in nvnmd_cfg.weight.keys(): + self.bias_atom_e = nvnmd_cfg.weight["t_bias_atom_e"] + with tf.variable_scope("fitting_attr" + suffix, reuse=reuse): t_dfparam = tf.constant(self.numb_fparam, name="dfparam", dtype=tf.int32) t_daparam = tf.constant(self.numb_aparam, name="daparam", dtype=tf.int32) diff --git a/deepmd/nvnmd/data/data.py b/deepmd/nvnmd/data/data.py index 29c8b84a37..9e6dd4cc89 100644 --- a/deepmd/nvnmd/data/data.py +++ b/deepmd/nvnmd/data/data.py @@ -60,6 +60,7 @@ }, "ctrl": { # NSTDM + "MAX_NNEI": 128, "NSTDM": 64, "NSTDM_M1": 32, "NSTDM_M2": 2, @@ -67,6 +68,7 @@ "NSEL": "NSTDM*NTYPE_MAX", "NSADV": "NSTDM+1", "VERSION": 0, + "SUB_VERSION": 1, }, "nbit": { # general @@ -116,6 +118,22 @@ "end": "", } +# change the configuration accordng to the max_nnei +jdata_config_v0_ni128 = jdata_config_v0.copy() +jdata_config_v0_ni256 = jdata_config_v0.copy() +jdata_config_v0_ni256["ctrl"] = { + "MAX_NNEI": 256, + "NSTDM": 128, + "NSTDM_M1": 32, + "NSTDM_M2": 4, + "NSTDM_M1X": 8, + "NSEL": "NSTDM*NTYPE_MAX", + "NSADV": "NSTDM+1", + "VERSION": 0, + "SUB_VERSION": 1, +} +jdata_config_v0_ni256["nbit"]["NBIT_NEIB"] = 9 + jdata_config_v1 = { "dscp": { # basic config from deepmd model @@ -174,6 +192,7 @@ }, "ctrl": { # NSTDM + "MAX_NNEI": 128, "NSTDM": 64, "NSTDM_M1": 32, "NSTDM_M2": 2, @@ -181,6 +200,7 @@ "NSEL": "NSTDM", "NSADV": "NSTDM+1", "VERSION": 1, + "SUB_VERSION": 1, }, "nbit": { # general @@ -230,6 +250,22 @@ "end": "", } +# change the configuration accordng to the max_nnei +jdata_config_v1_ni128 = jdata_config_v1.copy() +jdata_config_v1_ni256 = jdata_config_v1.copy() +jdata_config_v1_ni256["ctrl"] = { + "MAX_NNEI": 256, + "NSTDM": 128, + "NSTDM_M1": 32, + "NSTDM_M2": 4, + "NSTDM_M1X": 8, + "NSEL": "NSTDM", + "NSADV": "NSTDM+1", + "VERSION": 1, + "SUB_VERSION": 1, +} +jdata_config_v1_ni256["nbit"]["NBIT_NEIB"] = 9 + jdata_deepmd_input_v0 = { "model": { "descriptor": { @@ -247,6 +283,7 @@ }, "nvnmd": { "version": 0, + "max_nnei": 128, # 128 or 256 "net_size": 128, "config_file": "none", "weight_file": "none", @@ -286,6 +323,10 @@ }, } +jdata_deepmd_input_v0_ni128 = jdata_deepmd_input_v0.copy() +jdata_deepmd_input_v0_ni256 = jdata_deepmd_input_v0.copy() +jdata_deepmd_input_v0_ni256["nvnmd"]["max_nnei"] = 256 + jdata_deepmd_input_v1 = { "model": { "descriptor": { @@ -308,6 +349,7 @@ }, "nvnmd": { "version": 1, + "max_nnei": 128, # 128 or 256 "net_size": 128, "config_file": "none", "weight_file": "none", @@ -347,6 +389,10 @@ }, } +jdata_deepmd_input_v1_ni128 = jdata_deepmd_input_v1.copy() +jdata_deepmd_input_v1_ni256 = jdata_deepmd_input_v1.copy() +jdata_deepmd_input_v1_ni256["nvnmd"]["max_nnei"] = 256 + NVNMD_WELCOME = ( r" _ _ __ __ _ _ __ __ ____ ", r"| \ | | \ \ / / | \ | | | \/ | | _ \ ", diff --git a/deepmd/nvnmd/descriptor/se_a.py b/deepmd/nvnmd/descriptor/se_a.py index 67ea45924b..816f17cfa3 100644 --- a/deepmd/nvnmd/descriptor/se_a.py +++ b/deepmd/nvnmd/descriptor/se_a.py @@ -50,12 +50,17 @@ def check_switch_range(davg, dstd): else: min_dist = nvnmd_cfg.weight["train_attr.min_nbor_dist"] else: - min_dist = rmin + min_dist = None + + # fix the bug: if model initial mode is 'init_from_model', + # we need dmin to calculate smin and smax in mapt.py + if min_dist is not None: + nvnmd_cfg.dscp["dmin"] = min_dist + nvnmd_cfg.save() # if davg and dstd is None, the model initial mode is in # 'init_from_model', 'restart', 'init_from_frz_model', 'finetune' if (davg is not None) and (dstd is not None): - nvnmd_cfg.dscp["dmin"] = min_dist nvnmd_cfg.get_s_range(davg, dstd) diff --git a/deepmd/nvnmd/descriptor/se_atten.py b/deepmd/nvnmd/descriptor/se_atten.py index 727a93ca45..cfffb8a90b 100644 --- a/deepmd/nvnmd/descriptor/se_atten.py +++ b/deepmd/nvnmd/descriptor/se_atten.py @@ -49,7 +49,13 @@ def check_switch_range(davg, dstd): else: min_dist = nvnmd_cfg.weight["train_attr.min_nbor_dist"] else: - min_dist = rmin + min_dist = None + + # fix the bug: if model initial mode is 'init_from_model', + # we need dmin to calculate smin and smax in mapt.py + if min_dist is not None: + nvnmd_cfg.dscp["dmin"] = min_dist + nvnmd_cfg.save() # if davg and dstd is None, the model initial mode is in # 'init_from_model', 'restart', 'init_from_frz_model', 'finetune' @@ -58,7 +64,6 @@ def check_switch_range(davg, dstd): davg = np.zeros([ntype, ndescrpt]) if dstd is None: dstd = np.ones([ntype, ndescrpt]) - nvnmd_cfg.dscp["dmin"] = min_dist nvnmd_cfg.get_s_range(davg, dstd) diff --git a/deepmd/nvnmd/entrypoints/freeze.py b/deepmd/nvnmd/entrypoints/freeze.py index 6c356c6118..e56a0c2130 100644 --- a/deepmd/nvnmd/entrypoints/freeze.py +++ b/deepmd/nvnmd/entrypoints/freeze.py @@ -52,6 +52,7 @@ def filter_tensorVariableList(tensorVariableList) -> dict: p1 = p1 or name.startswith("filter_type_") p1 = p1 or name.startswith("layer_") p1 = p1 or name.startswith("final_layer") + p1 = p1 or name.endswith("t_bias_atom_e") p2 = "Adam" not in name p3 = "XXX" not in name if p1 and p2 and p3: @@ -75,4 +76,5 @@ def save_weight(sess, file_name: str = "nvnmd/weight.npy"): else: min_dist = 0.0 dic_key_value["train_attr.min_nbor_dist"] = min_dist + dic_key_value["t_bias_atom_e"] = dic_key_value["fitting_attr.t_bias_atom_e"] FioDic().save(file_name, dic_key_value) diff --git a/deepmd/nvnmd/entrypoints/mapt.py b/deepmd/nvnmd/entrypoints/mapt.py index eb77913983..1299d7a74e 100644 --- a/deepmd/nvnmd/entrypoints/mapt.py +++ b/deepmd/nvnmd/entrypoints/mapt.py @@ -87,9 +87,22 @@ def __init__(self, config_file: str, weight_file: str, map_file: str): jdata["weight_file"] = weight_file jdata["enable"] = True + # 0 : xyz_scatter = xyz_scatter * two_embd + xyz_scatter; + # Gs + 1, Gt + 0 + # 1 : xyz_scatter = xyz_scatter * two_embd + two_embd ; + # Gs + 0, Gt + 1 + self.Gs_Gt_mode = 1 + nvnmd_cfg.init_from_jdata(jdata) def build_map(self): + if self.Gs_Gt_mode == 0: + self.shift_Gs = 1 + self.shift_Gt = 0 + if self.Gs_Gt_mode == 1: + self.shift_Gs = 0 + self.shift_Gt = 1 + # M = nvnmd_cfg.dscp["M1"] if nvnmd_cfg.version == 0: ndim = nvnmd_cfg.dscp["ntype"] @@ -482,7 +495,7 @@ def build_s2g_grad(self): shift = 0 if nvnmd_cfg.version == 1: ndim = 1 - shift = 1 + shift = self.shift_Gs # dic_ph = {} dic_ph["s"] = tf.placeholder(tf.float64, [None, 1], "t_s") @@ -496,6 +509,13 @@ def run_s2g(self): r"""Build s-> graph and run it to get value of mapping table.""" smin = nvnmd_cfg.dscp["smin"] smax = nvnmd_cfg.dscp["smax"] + # fix the bug: if model initial mode is 'init_from_model', + # we need dmin to calculate smin and smax in mapt.py + if smin == -2: + davg, dstd = get_normalize(nvnmd_cfg.weight) + nvnmd_cfg.get_s_range(davg, dstd) + smin = nvnmd_cfg.dscp["smin"] + smax = nvnmd_cfg.dscp["smax"] tf.reset_default_graph() dic_ph = self.build_s2g_grad() @@ -567,9 +587,11 @@ def build_t2g(self): two_side_type_embedding, [-1, two_side_type_embedding.shape[-1]], ) - + # see se_atten.py in dp wbs = [get_filter_type_weight(nvnmd_cfg.weight, ll) for ll in range(1, 5)] - dic_ph["gt"] = self.build_embedding_net(two_side_type_embedding, wbs) + dic_ph["gt"] = ( + self.build_embedding_net(two_side_type_embedding, wbs) + self.shift_Gt + ) return dic_ph def run_t2g(self): diff --git a/deepmd/nvnmd/entrypoints/train.py b/deepmd/nvnmd/entrypoints/train.py index cb3dad0792..6e14b6f865 100644 --- a/deepmd/nvnmd/entrypoints/train.py +++ b/deepmd/nvnmd/entrypoints/train.py @@ -100,6 +100,7 @@ def normalized_input_qnn(jdata, PATH_QNN, CONFIG_CNN, WEIGHT_CNN, MAP_CNN): jdata_nvnmd = jdata_deepmd_input_v0["nvnmd"] jdata_nvnmd["enable"] = True jdata_nvnmd["version"] = nvnmd_cfg.version + jdata_nvnmd["max_nnei"] = nvnmd_cfg.max_nnei jdata_nvnmd["config_file"] = CONFIG_CNN jdata_nvnmd["weight_file"] = WEIGHT_CNN jdata_nvnmd["map_file"] = MAP_CNN @@ -117,6 +118,7 @@ def normalized_input_qnn(jdata, PATH_QNN, CONFIG_CNN, WEIGHT_CNN, MAP_CNN): def train_nvnmd( *, INPUT: str, + init_model: Optional[str], restart: Optional[str], step: str, skip_neighbor_stat: bool = False, @@ -142,6 +144,7 @@ def train_nvnmd( jdata = jdata_cmd_train.copy() jdata["INPUT"] = INPUT_CNN jdata["log_path"] = LOG_CNN + jdata["init_model"] = init_model jdata["restart"] = restart jdata["skip_neighbor_stat"] = skip_neighbor_stat train(**jdata) diff --git a/deepmd/nvnmd/entrypoints/wrap.py b/deepmd/nvnmd/entrypoints/wrap.py index 455dd999df..1ba2ed7384 100644 --- a/deepmd/nvnmd/entrypoints/wrap.py +++ b/deepmd/nvnmd/entrypoints/wrap.py @@ -156,33 +156,75 @@ def wrap_head(self, nhs, nws): r"""Wrap the head information. version + nhead nheight - nweight - rcut + nwidth + rcut cut-off radius + ntype number of atomic species + nnei number of neighbors + atom_ener atom bias energy """ nbit = nvnmd_cfg.nbit ctrl = nvnmd_cfg.ctrl + dscp = nvnmd_cfg.dscp + fitn = nvnmd_cfg.fitn + weight = nvnmd_cfg.weight VERSION = ctrl["VERSION"] + SUB_VERSION = ctrl["SUB_VERSION"] + MAX_NNEI = ctrl["MAX_NNEI"] + nhead = 128 NBIT_MODEL_HEAD = nbit["NBIT_MODEL_HEAD"] NBIT_FIXD_FL = nbit["NBIT_FIXD_FL"] - rcut = nvnmd_cfg.dscp["rcut"] + rcut = dscp["rcut"] + ntype = dscp["ntype"] + SEL = dscp["SEL"] bs = "" e = Encode() # version - bs = e.dec2bin(VERSION, NBIT_MODEL_HEAD)[0] + bs + vv = VERSION + 256 * SUB_VERSION + 256 * 256 * MAX_NNEI + bs = e.dec2bin(vv, NBIT_MODEL_HEAD)[0] + bs + # nhead + bs = e.dec2bin(nhead, NBIT_MODEL_HEAD)[0] + bs # height for n in nhs: bs = e.dec2bin(n, NBIT_MODEL_HEAD)[0] + bs - # weight + # width for n in nws: bs = e.dec2bin(n, NBIT_MODEL_HEAD)[0] + bs - # dscp + # rcut RCUT = e.qr(rcut, NBIT_FIXD_FL) bs = e.dec2bin(RCUT, NBIT_MODEL_HEAD)[0] + bs + # ntype + bs = e.dec2bin(ntype, NBIT_MODEL_HEAD)[0] + bs + # nnei + if VERSION == 0: + for tt in range(ntype): + bs = e.dec2bin(SEL[tt], NBIT_MODEL_HEAD)[0] + bs + if VERSION == 1: + bs = e.dec2bin(SEL, NBIT_MODEL_HEAD)[0] + bs + # atom_ener + # fix the bug: the different energy between qnn and lammps + if "t_bias_atom_e" in weight.keys(): + atom_ener = weight["t_bias_atom_e"] + else: + atom_ener = [0] * 32 + nlayer_fit = fitn["nlayer_fit"] + if VERSION == 0: + for tt in range(ntype): + w, b, _idt = get_fitnet_weight(weight, tt, nlayer_fit - 1, nlayer_fit) + shift = atom_ener[tt] + b[0] + SHIFT = e.qr(shift, NBIT_FIXD_FL) + bs = e.dec2bin(SHIFT, NBIT_MODEL_HEAD, signed=True)[0] + bs + if VERSION == 1: + for tt in range(ntype): + w, b, _idt = get_fitnet_weight(weight, 0, nlayer_fit - 1, nlayer_fit) + shift = atom_ener[tt] + b[0] + SHIFT = e.qr(shift, NBIT_FIXD_FL) + bs = e.dec2bin(SHIFT, NBIT_MODEL_HEAD, signed=True)[0] + bs # extend hs = e.bin2hex(bs) - hs = e.extend_hex(hs, NBIT_MODEL_HEAD * 32) + hs = e.extend_hex(hs, NBIT_MODEL_HEAD * nhead) return hs def wrap_dscp(self): diff --git a/deepmd/nvnmd/utils/argcheck.py b/deepmd/nvnmd/utils/argcheck.py index 2cbff3cbdc..2dc17ebc27 100644 --- a/deepmd/nvnmd/utils/argcheck.py +++ b/deepmd/nvnmd/utils/argcheck.py @@ -8,6 +8,7 @@ def nvnmd_args(): doc_version = ( "configuration the nvnmd version (0 | 1), 0 for 4 types, 1 for 32 types" ) + doc_max_nnei = "configuration the max number of neighbors, 128|256 for version 0, 128 for version 1" doc_net_size_file = ( "configuration the number of nodes of fitting_net, just can be set as 128" ) @@ -25,6 +26,7 @@ def nvnmd_args(): doc_quantize_fitting_net = "enable the quantizatioin of fitting_net" args = [ Argument("version", int, optional=False, default=0, doc=doc_version), + Argument("max_nnei", int, optional=False, default=128, doc=doc_max_nnei), Argument("net_size", int, optional=False, default=128, doc=doc_net_size_file), Argument("map_file", str, optional=False, default="none", doc=doc_map_file), Argument( diff --git a/deepmd/nvnmd/utils/config.py b/deepmd/nvnmd/utils/config.py index 96ca74c4c9..5bfd9ea54f 100644 --- a/deepmd/nvnmd/utils/config.py +++ b/deepmd/nvnmd/utils/config.py @@ -7,9 +7,15 @@ NVNMD_CITATION, NVNMD_WELCOME, jdata_config_v0, - jdata_config_v1, + jdata_config_v0_ni128, + jdata_config_v0_ni256, + jdata_config_v1_ni128, + jdata_config_v1_ni256, jdata_deepmd_input_v0, - jdata_deepmd_input_v1, + jdata_deepmd_input_v0_ni128, + jdata_deepmd_input_v0_ni256, + jdata_deepmd_input_v1_ni128, + jdata_deepmd_input_v1_ni256, ) from deepmd.nvnmd.utils.fio import ( FioDic, @@ -50,6 +56,7 @@ def init_from_jdata(self, jdata: dict = {}): return None self.version = jdata["version"] + self.max_nnei = jdata["max_nnei"] self.net_size = jdata["net_size"] self.map_file = jdata["map_file"] self.config_file = jdata["config_file"] @@ -65,7 +72,7 @@ def init_from_jdata(self, jdata: dict = {}): self.map = FioDic().load(self.map_file, {}) self.weight = FioDic().load(self.weight_file, {}) - self.init_config_by_version(self.version) + self.init_config_by_version(self.version, self.max_nnei) load_config = FioDic().load(self.config_file, self.config) self.init_from_config(load_config) # if load the file, set net_size @@ -106,7 +113,11 @@ def init_from_config(self, jdata): r"""Initialize member element one by one.""" if "ctrl" in jdata.keys(): if "VERSION" in jdata["ctrl"].keys(): - self.init_config_by_version(jdata["ctrl"]["VERSION"]) + if "MAX_NNEI" not in jdata["ctrl"].keys(): + jdata["ctrl"]["MAX_NNEI"] = 128 + self.init_config_by_version( + jdata["ctrl"]["VERSION"], jdata["ctrl"]["MAX_NNEI"] + ) # self.config = FioDic().update(jdata, self.config) self.config["dscp"] = self.init_dscp(self.config["dscp"], self.config) @@ -117,16 +128,29 @@ def init_from_config(self, jdata): self.config["nbit"] = self.init_nbit(self.config["nbit"], self.config) self.init_value() - def init_config_by_version(self, version): + def init_config_by_version(self, version, max_nnei): r"""Initialize version-dependent parameters.""" self.version = version + self.max_nnei = max_nnei log.debug("#Set nvnmd version as %d " % self.version) if self.version == 0: - self.jdata_deepmd_input = jdata_deepmd_input_v0.copy() - self.config = jdata_config_v0.copy() + if self.max_nnei == 128: + self.jdata_deepmd_input = jdata_deepmd_input_v0_ni128.copy() + self.config = jdata_config_v0_ni128.copy() + elif self.max_nnei == 256: + self.jdata_deepmd_input = jdata_deepmd_input_v0_ni256.copy() + self.config = jdata_config_v0_ni256.copy() + else: + log.error("The max_nnei only can be set as 128|256 for version 0") if self.version == 1: - self.jdata_deepmd_input = jdata_deepmd_input_v1.copy() - self.config = jdata_config_v1.copy() + if self.max_nnei == 128: + self.jdata_deepmd_input = jdata_deepmd_input_v1_ni128.copy() + self.config = jdata_config_v1_ni128.copy() + elif self.max_nnei == 256: + self.jdata_deepmd_input = jdata_deepmd_input_v1_ni256.copy() + self.config = jdata_config_v1_ni256.copy() + else: + log.error("The max_nnei only can be set as 128|256 for version 1") def init_net_size(self): r"""Initialize net_size.""" @@ -154,10 +178,15 @@ def init_dscp(self, jdata: dict, jdata_parent: dict = {}) -> dict: jdata["M1"] = jdata["neuron"][-1] jdata["M2"] = jdata["axis_neuron"] jdata["SEL"] = (jdata["sel"] + [0, 0, 0, 0])[0:4] + for s in jdata["sel"]: + if s > self.max_nnei: + log.error("The sel cannot be greater than the max_nnei") + exit(1) jdata["NNODE_FEAS"] = [1] + jdata["neuron"] jdata["nlayer_fea"] = len(jdata["neuron"]) jdata["same_net"] = 1 if jdata["type_one_side"] else 0 # neighbor + jdata["NI"] = self.max_nnei jdata["NIDP"] = int(np.sum(jdata["sel"])) jdata["NIX"] = 2 ** int(np.ceil(np.log2(jdata["NIDP"] / 1.5))) # type @@ -168,10 +197,14 @@ def init_dscp(self, jdata: dict, jdata_parent: dict = {}) -> dict: jdata["M1"] = jdata["neuron"][-1] jdata["M2"] = jdata["axis_neuron"] jdata["SEL"] = jdata["sel"] + if jdata["sel"] > self.max_nnei: + log.error("The sel cannot be greater than the max_nnei") + exit(1) jdata["NNODE_FEAS"] = [1] + jdata["neuron"] jdata["nlayer_fea"] = len(jdata["neuron"]) jdata["same_net"] = 1 if jdata["type_one_side"] else 0 # neighbor + jdata["NI"] = self.max_nnei jdata["NIDP"] = int(jdata["sel"]) jdata["NIX"] = 2 ** int(np.ceil(np.log2(jdata["NIDP"] / 1.5))) # type @@ -306,6 +339,7 @@ def get_nvnmd_jdata(self): r"""Generate `nvnmd` in input script.""" jdata = self.jdata_deepmd_input["nvnmd"] jdata["net_size"] = self.net_size + jdata["max_nnei"] = self.max_nnei jdata["config_file"] = self.config_file jdata["weight_file"] = self.weight_file jdata["map_file"] = self.map_file diff --git a/deepmd_utils/main.py b/deepmd_utils/main.py index 3dc54db052..19afaeee1f 100644 --- a/deepmd_utils/main.py +++ b/deepmd_utils/main.py @@ -552,10 +552,26 @@ def main_parser() -> argparse.ArgumentParser: parents=[parser_log], help="train nvnmd model", formatter_class=argparse.ArgumentDefaultsHelpFormatter, + epilog=textwrap.dedent( + """\ + examples: + dp train-nvnmd input_cnn.json -s s1 + dp train-nvnmd input_qnn.json -s s2 + dp train-nvnmd input_cnn.json -s s1 --restart model.ckpt + dp train-nvnmd input_cnn.json -s s2 --init-model model.ckpt + """ + ), ) parser_train_nvnmd.add_argument( "INPUT", help="the input parameter file in json format" ) + parser_train_nvnmd.add_argument( + "-i", + "--init-model", + type=str, + default=None, + help="Initialize the model by the provided path prefix of checkpoint files.", + ) parser_train_nvnmd.add_argument( "-r", "--restart", diff --git a/doc/nvnmd/nvnmd.md b/doc/nvnmd/nvnmd.md index 7a11e3170e..c11fee0bc9 100644 --- a/doc/nvnmd/nvnmd.md +++ b/doc/nvnmd/nvnmd.md @@ -60,6 +60,7 @@ The "nvnmd" section is defined as ```json { "version": 0, + "max_nnei":128, "net_size":128, "sel":[60, 60], "rcut":6.0, @@ -73,6 +74,7 @@ where items are defined as: | Item | Mean | Optional Value | | --------- | --------------------------- | --------------------------------------------- | | version | the version of network structure | 0 or 1 | +| max_nnei | the maximum number of neighbors that do not distinguish element types | 128 or 256 | | net_size | the size of nueral network | 128 | | sel | the number of neighbors | version 0: integer list of lengths 1 to 4 are acceptable; version 1: integer | | rcut | the cutoff radial | (0, 8.0] | @@ -187,6 +189,15 @@ You can also restart the CNN training from the path prefix of checkpoint files ( dp train-nvnmd train_cnn.json -r nvnmd_cnn/model.ckpt -s s1 ``` +You can also initialize the CNN model and train it by + +``` bash +mv nvnmd_cnn nvnmd_cnn_bck +cp train_cnn.json train_cnn2.json +# please edit train_cnn2.json +dp train-nvnmd train_cnn2.json -s s1 -i nvnmd_cnn_bck/model.ckpt +``` + # Testing diff --git a/examples/nvnmd/train/train_cnn.json b/examples/nvnmd/train/train_cnn.json index c89c8b13d6..1865106909 100644 --- a/examples/nvnmd/train/train_cnn.json +++ b/examples/nvnmd/train/train_cnn.json @@ -1,6 +1,7 @@ { "nvnmd": { "version": 0, + "max_nnei": 128, "net_size": 128, "sel": [ 60, diff --git a/examples/nvnmd/train/train_qnn.json b/examples/nvnmd/train/train_qnn.json index 0235575f52..72b299f70d 100644 --- a/examples/nvnmd/train/train_qnn.json +++ b/examples/nvnmd/train/train_qnn.json @@ -1,6 +1,7 @@ { "nvnmd": { "version": 0, + "max_nnei": 128, "net_size": 128, "sel": [ 60, diff --git a/source/op/prod_env_mat_multi_device_nvnmd.cc b/source/op/prod_env_mat_multi_device_nvnmd.cc index abca947f0a..1cbfb968f1 100644 --- a/source/op/prod_env_mat_multi_device_nvnmd.cc +++ b/source/op/prod_env_mat_multi_device_nvnmd.cc @@ -411,6 +411,9 @@ class ProdEnvMatANvnmdQuantizeOp : public OpKernel { // no pbc assert(nloc == nall); nei_mode = -1; + } else if (mesh_tensor.shape().dim_size(0) > 16) { + // pass neighbor list inside the tensor + nei_mode = 4; } else if (mesh_tensor.shape().dim_size(0) == 7 || mesh_tensor.shape().dim_size(0) == 1) { throw deepmd::deepmd_exception( @@ -422,16 +425,16 @@ class ProdEnvMatANvnmdQuantizeOp : public OpKernel { // Create output tensors TensorShape descrpt_shape; descrpt_shape.AddDim(nsamples); - descrpt_shape.AddDim(nloc * ndescrpt); + descrpt_shape.AddDim(int_64(nloc) * ndescrpt); TensorShape descrpt_deriv_shape; descrpt_deriv_shape.AddDim(nsamples); - descrpt_deriv_shape.AddDim(nloc * ndescrpt * 3); + descrpt_deriv_shape.AddDim(int_64(nloc) * ndescrpt * 3); TensorShape rij_shape; rij_shape.AddDim(nsamples); - rij_shape.AddDim(nloc * nnei * 3); + rij_shape.AddDim(int_64(nloc) * nnei * 3); TensorShape nlist_shape; nlist_shape.AddDim(nsamples); - nlist_shape.AddDim(nloc * nnei); + nlist_shape.AddDim(int_64(nloc) * nnei); // define output tensor int context_output_index = 0; Tensor* descrpt_tensor = NULL; @@ -460,8 +463,16 @@ class ProdEnvMatANvnmdQuantizeOp : public OpKernel { const FPTYPE* std = std_tensor.flat().data(); const int* p_type = type_tensor.flat().data(); + // must declar out of if, otherwise the memory will be destroyed! + Tensor int_temp; + Tensor uint64_temp; + std::vector tensor_list(7); + if (device == "GPU") { + // UNDEFINE + } + // loop over samples - for (int ff = 0; ff < nsamples; ++ff) { + for (int_64 ff = 0; ff < nsamples; ++ff) { FPTYPE* em = p_em + ff * nloc * ndescrpt; FPTYPE* em_deriv = p_em_deriv + ff * nloc * ndescrpt * 3; FPTYPE* rij = p_rij + ff * nloc * nnei * 3; @@ -633,15 +644,18 @@ class ProdEnvMatAMixNvnmdQuantizeOp : public OpKernel { if (mesh_tensor.shape().dim_size(0) == 16) { // lammps neighbor list nei_mode = 3; - } else if (mesh_tensor.shape().dim_size(0) == 6) { + } else if (mesh_tensor.shape().dim_size(0) == 6 || + mesh_tensor.shape().dim_size(0) == 7) { // manual copied pbc - assert(nloc == nall); nei_mode = 1; b_nlist_map = true; - } else if (mesh_tensor.shape().dim_size(0) == 0) { + } else if (mesh_tensor.shape().dim_size(0) == 0 || + mesh_tensor.shape().dim_size(0) == 1) { // no pbc - assert(nloc == nall); nei_mode = -1; + } else if (mesh_tensor.shape().dim_size(0) > 16) { + // pass neighbor list inside the tensor + nei_mode = 4; } else { throw deepmd::deepmd_exception("invalid mesh tensor"); } @@ -691,6 +705,12 @@ class ProdEnvMatAMixNvnmdQuantizeOp : public OpKernel { context->allocate_output(context_output_index++, nmask_shape, &nmask_tensor)); + Tensor fake_type_tensor; // all zeros + TensorShape fake_type_shape; + fake_type_shape.AddDim(nsamples * nall); + OP_REQUIRES_OK(context, context->allocate_temp(DT_INT32, fake_type_shape, + &fake_type_tensor)); + FPTYPE* p_em = descrpt_tensor->flat().data(); FPTYPE* p_em_deriv = descrpt_deriv_tensor->flat().data(); FPTYPE* p_rij = rij_tensor->flat().data(); @@ -702,7 +722,25 @@ class ProdEnvMatAMixNvnmdQuantizeOp : public OpKernel { const FPTYPE* avg = avg_tensor.flat().data(); const FPTYPE* std = std_tensor.flat().data(); const int* p_type = type_tensor.flat().data(); + int* p_f_type = fake_type_tensor.flat().data(); + + if (device == "GPU") { +#if GOOGLE_CUDA || TENSORFLOW_USE_ROCM +// UNDEFINE +#endif + } else if (device == "CPU") { + for (int ii = 0; ii < nsamples * nall; ii++) { + p_f_type[ii] = (p_type[ii] < 0) ? -1 : 0; + } + } + // must declar out of if, otherwise the memory will be destroyed! + Tensor int_temp; + Tensor uint64_temp; + std::vector tensor_list(7); + if (device == "GPU") { + // UNDEFINE + } // loop over samples for (int_64 ff = 0; ff < nsamples; ++ff) { FPTYPE* em = p_em + ff * nloc * ndescrpt; @@ -714,6 +752,7 @@ class ProdEnvMatAMixNvnmdQuantizeOp : public OpKernel { const FPTYPE* coord = p_coord + ff * nall * 3; const FPTYPE* box = p_box + ff * 9; const int* type = p_type + ff * nall; + const int* f_type = p_f_type + ff * nall; if (device == "GPU") { #if GOOGLE_CUDA || TENSORFLOW_USE_ROCM @@ -729,13 +768,6 @@ class ProdEnvMatAMixNvnmdQuantizeOp : public OpKernel { std::vector coord_cpy; std::vector type_cpy; int frame_nall = nall; - std::vector fake_type(nall, 0); - for (int ii = 0; ii < nall; ii++) { - if (type[ii] < 0) { - fake_type[ii] = -1; - } - } - const int* f_type = &fake_type[0]; // prepare coord and nlist _prepare_coord_nlist_cpu( context, &coord, coord_cpy, &f_type, type_cpy, idx_mapping, inlist, diff --git a/source/tests/test_nvnmd_entrypoints.py b/source/tests/test_nvnmd_entrypoints.py index 3e721516f1..d82c905024 100644 --- a/source/tests/test_nvnmd_entrypoints.py +++ b/source/tests/test_nvnmd_entrypoints.py @@ -521,6 +521,7 @@ def test_mapt_cnn_v1(self): map_file = str(tests_path / "nvnmd" / "out" / "map_v1_cnn.npy") # mapt mapObj = MapTable(config_file, weight_file, map_file) + mapObj.Gs_Gt_mode = 0 mapt = mapObj.build_map() # N = 32 @@ -859,8 +860,9 @@ def test_wrap_qnn_v1(self): # test data = FioBin().load(jdata["nvnmd_model"]) idx = [0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384] + idx = [i + 128 * 4 for i in idx] pred = [data[i] for i in idx] - red_dout = [1, 0, 0, 128, 0, 0, 0, 8, 249, 0, 0, 0, 91, 252, 183, 254] + red_dout = [249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 95, 24, 176] np.testing.assert_equal(pred, red_dout) # close nvnmd_cfg.enable = False From e048389846ecf49f764ba3717bdef27a9723ddff Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Thu, 14 Dec 2023 19:55:51 -0500 Subject: [PATCH 45/97] Fix possible memory leak in constructors (#3062) When a constructor throws an exception, it will not call the destructor as the constructor is not finished. The memory leak happens here and is detected by LeakSanitizer (thanks, @Cloudac7, for reminding me to use it). We must catch the exception, delete the memory, and re-throw the exception. --------- Signed-off-by: Jinzhe Zeng Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- source/api_cc/src/DataModifier.cc | 8 +++++++- source/api_cc/src/DeepPot.cc | 18 ++++++++++++++++-- source/api_cc/src/DeepTensor.cc | 8 +++++++- source/api_cc/tests/test_deepmd_exception.cc | 20 +++++++++++++++++++- 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/source/api_cc/src/DataModifier.cc b/source/api_cc/src/DataModifier.cc index 658ec68442..d687c02e75 100644 --- a/source/api_cc/src/DataModifier.cc +++ b/source/api_cc/src/DataModifier.cc @@ -11,7 +11,13 @@ DipoleChargeModifier::DipoleChargeModifier(const std::string& model, const int& gpu_rank, const std::string& name_scope_) : inited(false), name_scope(name_scope_), graph_def(new GraphDef()) { - init(model, gpu_rank, name_scope_); + try { + init(model, gpu_rank, name_scope_); + } catch (...) { + // Clean up and rethrow, as the destructor will not be called + delete graph_def; + throw; + } } DipoleChargeModifier::~DipoleChargeModifier() { delete graph_def; }; diff --git a/source/api_cc/src/DeepPot.cc b/source/api_cc/src/DeepPot.cc index 23a0a7e663..018c3aca09 100644 --- a/source/api_cc/src/DeepPot.cc +++ b/source/api_cc/src/DeepPot.cc @@ -404,7 +404,13 @@ DeepPot::DeepPot(const std::string& model, const int& gpu_rank, const std::string& file_content) : inited(false), init_nbor(false), graph_def(new GraphDef()) { - init(model, gpu_rank, file_content); + try { + init(model, gpu_rank, file_content); + } catch (...) { + // Clean up and rethrow, as the destructor will not be called + delete graph_def; + throw; + } } DeepPot::~DeepPot() { delete graph_def; } @@ -1236,7 +1242,15 @@ DeepPotModelDevi::DeepPotModelDevi( const int& gpu_rank, const std::vector& file_contents) : inited(false), init_nbor(false), numb_models(0) { - init(models, gpu_rank, file_contents); + try { + init(models, gpu_rank, file_contents); + } catch (...) { + // Clean up and rethrow, as the destructor will not be called + for (unsigned ii = 0; ii < numb_models; ++ii) { + delete graph_defs[ii]; + } + throw; + } } DeepPotModelDevi::~DeepPotModelDevi() { diff --git a/source/api_cc/src/DeepTensor.cc b/source/api_cc/src/DeepTensor.cc index 30ff99497c..655819e086 100644 --- a/source/api_cc/src/DeepTensor.cc +++ b/source/api_cc/src/DeepTensor.cc @@ -10,7 +10,13 @@ DeepTensor::DeepTensor(const std::string &model, const int &gpu_rank, const std::string &name_scope_) : inited(false), name_scope(name_scope_), graph_def(new GraphDef()) { - init(model, gpu_rank, name_scope_); + try { + init(model, gpu_rank, name_scope_); + } catch (...) { + // Clean up and rethrow, as the destructor will not be called + delete graph_def; + throw; + } } DeepTensor::~DeepTensor() { delete graph_def; } diff --git a/source/api_cc/tests/test_deepmd_exception.cc b/source/api_cc/tests/test_deepmd_exception.cc index 1cbec270b5..dd97f2786f 100644 --- a/source/api_cc/tests/test_deepmd_exception.cc +++ b/source/api_cc/tests/test_deepmd_exception.cc @@ -10,7 +10,9 @@ #include #include +#include "DataModifier.h" #include "DeepPot.h" +#include "DeepTensor.h" #include "errors.h" TEST(TestDeepmdException, deepmdexception) { std::string expected_error_message = "DeePMD-kit Error: unittest"; @@ -21,6 +23,22 @@ TEST(TestDeepmdException, deepmdexception) { } } -TEST(TestDeepmdException, deepmdexception_nofile) { +TEST(TestDeepmdException, deepmdexception_nofile_deeppot) { ASSERT_THROW(deepmd::DeepPot("_no_such_file.pb"), deepmd::deepmd_exception); } + +TEST(TestDeepmdException, deepmdexception_nofile_deeppotmodeldevi) { + ASSERT_THROW( + deepmd::DeepPotModelDevi({"_no_such_file.pb", "_no_such_file.pb"}), + deepmd::deepmd_exception); +} + +TEST(TestDeepmdException, deepmdexception_nofile_deeptensor) { + ASSERT_THROW(deepmd::DeepTensor("_no_such_file.pb"), + deepmd::deepmd_exception); +} + +TEST(TestDeepmdException, deepmdexception_nofile_dipolechargemodifier) { + ASSERT_THROW(deepmd::DipoleChargeModifier("_no_such_file.pb"), + deepmd::deepmd_exception); +} From 18902be6358e54a65c166a601be20ab7cc1b84c9 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Thu, 14 Dec 2023 19:58:35 -0500 Subject: [PATCH 46/97] fix memory leaks related to `char*` (#3063) Make sure no leaks reported from `string_to_char` by LeakSanitizer. Most memory leaks happen only once, but `DP_CHECK_OK` causes 1 byte leaking every step, meaning 10 MB leaks for 10 million steps. --------- Signed-off-by: Jinzhe Zeng --- source/api_c/include/c_api.h | 7 +++++++ source/api_c/include/deepmd.hpp | 18 ++++++++++++------ source/api_c/src/c_api.cc | 2 ++ source/api_c/tests/test_deeppot_a.cc | 1 + 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/source/api_c/include/c_api.h b/source/api_c/include/c_api.h index b0c030962a..d05f790bf9 100644 --- a/source/api_c/include/c_api.h +++ b/source/api_c/include/c_api.h @@ -1271,6 +1271,13 @@ void DP_SelectMapInt(const int* in, const int nall2, int* out); +/** + * @brief Destroy a char array. + * + * @param c_str The char array. + */ +void DP_DeleteChar(const char* c_str); + #ifdef __cplusplus } /* end extern "C" */ #endif diff --git a/source/api_c/include/deepmd.hpp b/source/api_c/include/deepmd.hpp index 90c1c1c918..4a376e0bec 100644 --- a/source/api_c/include/deepmd.hpp +++ b/source/api_c/include/deepmd.hpp @@ -35,10 +35,14 @@ struct deepmd_exception : public std::runtime_error { /** * @brief Check if any exceptions throw in the C++ API. Throw if possible. */ -#define DP_CHECK_OK(check_func, dp) \ - const char *err_msg = check_func(dp); \ - if (std::strlen(err_msg)) \ - throw deepmd::hpp::deepmd_exception(std::string(err_msg)); +#define DP_CHECK_OK(check_func, dp) \ + const char *err_msg = check_func(dp); \ + if (std::strlen(err_msg)) { \ + std::string err_msg_str = std::string(err_msg); \ + DP_DeleteChar(err_msg); \ + throw deepmd::hpp::deepmd_exception(err_msg_str); \ + } \ + DP_DeleteChar(err_msg); template inline void _DP_DeepPotCompute(DP_DeepPot *dp, @@ -1019,7 +1023,7 @@ class DeepPot { void get_type_map(std::string &type_map) { const char *type_map_c = DP_DeepPotGetTypeMap(dp); type_map.assign(type_map_c); - delete[] type_map_c; + DP_DeleteChar(type_map_c); }; /** * @brief Print the summary of DeePMD-kit, including the version and the build @@ -1864,7 +1868,7 @@ class DeepTensor { void get_type_map(std::string &type_map) { const char *type_map_c = DP_DeepTensorGetTypeMap(dt); type_map.assign(type_map_c); - delete[] type_map_c; + DP_DeleteChar(type_map_c); }; private: @@ -2009,9 +2013,11 @@ void inline read_file_to_string(std::string model, std::string &file_content) { if (size < 0) { // negtive size indicates error std::string error_message = std::string(c_file_content, -size); + DP_DeleteChar(c_file_content); throw deepmd::hpp::deepmd_exception(error_message); } file_content = std::string(c_file_content, size); + DP_DeleteChar(c_file_content); }; /** diff --git a/source/api_c/src/c_api.cc b/source/api_c/src/c_api.cc index 9d1ed7d323..935e812cf0 100644 --- a/source/api_c/src/c_api.cc +++ b/source/api_c/src/c_api.cc @@ -1421,4 +1421,6 @@ void DP_SelectMapInt(const int* in, } } +void DP_DeleteChar(const char* c_str) { delete[] c_str; } + } // extern "C" diff --git a/source/api_c/tests/test_deeppot_a.cc b/source/api_c/tests/test_deeppot_a.cc index 50e8131cc0..63f53e16e9 100644 --- a/source/api_c/tests/test_deeppot_a.cc +++ b/source/api_c/tests/test_deeppot_a.cc @@ -172,6 +172,7 @@ TEST_F(TestInferDeepPotA, type_map) { const char* type_map = DP_DeepPotGetTypeMap(dp); char expected_type_map[] = "O H"; EXPECT_EQ(strcmp(type_map, expected_type_map), 0); + DP_DeleteChar(type_map); } class TestInferDeepPotANoPBC : public ::testing::Test { From a266b4888925d829f59f3aba63589c72cb05f83b Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Fri, 15 Dec 2023 03:22:59 -0500 Subject: [PATCH 47/97] add utils for DP native model format (#3064) Split from #2987. Signed-off-by: Jinzhe Zeng --- deepmd_utils/model_format.py | 240 ++++++++++++++++++++++++ source/tests/test_model_format_utils.py | 73 +++++++ 2 files changed, 313 insertions(+) create mode 100644 deepmd_utils/model_format.py create mode 100644 source/tests/test_model_format_utils.py diff --git a/deepmd_utils/model_format.py b/deepmd_utils/model_format.py new file mode 100644 index 0000000000..68a6d4045b --- /dev/null +++ b/deepmd_utils/model_format.py @@ -0,0 +1,240 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +"""Native DP model format for multiple backends. + +See issue #2982 for more information. +""" +import json +from typing import ( + List, + Optional, +) + +import h5py +import numpy as np + +try: + from deepmd_utils._version import version as __version__ +except ImportError: + __version__ = "unknown" + + +def traverse_model_dict(model_obj, callback: callable, is_variable: bool = False): + """Traverse a model dict and call callback on each variable. + + Parameters + ---------- + model_obj : object + The model object to traverse. + callback : callable + The callback function to call on each variable. + is_variable : bool, optional + Whether the current node is a variable. + + Returns + ------- + object + The model object after traversing. + """ + if isinstance(model_obj, dict): + for kk, vv in model_obj.items(): + model_obj[kk] = traverse_model_dict( + vv, callback, is_variable=is_variable or kk == "@variables" + ) + elif isinstance(model_obj, list): + for ii, vv in enumerate(model_obj): + model_obj[ii] = traverse_model_dict(vv, callback, is_variable=is_variable) + elif is_variable: + model_obj = callback(model_obj) + return model_obj + + +class Counter: + """A callable counter. + + Examples + -------- + >>> counter = Counter() + >>> counter() + 0 + >>> counter() + 1 + """ + + def __init__(self): + self.count = -1 + + def __call__(self): + self.count += 1 + return self.count + + +def save_dp_model(filename: str, model_dict: dict, extra_info: Optional[dict] = None): + """Save a DP model to a file in the native format. + + Parameters + ---------- + filename : str + The filename to save to. + model_dict : dict + The model dict to save. + extra_info : dict, optional + Extra meta information to save. + """ + model_dict = model_dict.copy() + variable_counter = Counter() + if extra_info is not None: + extra_info = extra_info.copy() + else: + extra_info = {} + with h5py.File(filename, "w") as f: + model_dict = traverse_model_dict( + model_dict, + lambda x: f.create_dataset( + f"variable_{variable_counter():04d}", data=x + ).name, + ) + save_dict = { + "model": model_dict, + "software": "deepmd-kit", + "version": __version__, + **extra_info, + } + f.attrs["json"] = json.dumps(save_dict, separators=(",", ":")) + + +def load_dp_model(filename: str) -> dict: + """Load a DP model from a file in the native format. + + Parameters + ---------- + filename : str + The filename to load from. + + Returns + ------- + dict + The loaded model dict, including meta information. + """ + with h5py.File(filename, "r") as f: + model_dict = json.loads(f.attrs["json"]) + model_dict = traverse_model_dict(model_dict, lambda x: f[x][()].copy()) + return model_dict + + +class NativeLayer: + """Native representation of a layer. + + Parameters + ---------- + w : np.ndarray, optional + The weights of the layer. + b : np.ndarray, optional + The biases of the layer. + idt : np.ndarray, optional + The identity matrix of the layer. + """ + + def __init__( + self, + w: Optional[np.ndarray] = None, + b: Optional[np.ndarray] = None, + idt: Optional[np.ndarray] = None, + ) -> None: + self.w = w + self.b = b + self.idt = idt + + def serialize(self) -> dict: + """Serialize the layer to a dict. + + Returns + ------- + dict + The serialized layer. + """ + data = { + "w": self.w, + "b": self.b, + } + if self.idt is not None: + data["idt"] = self.idt + return data + + @classmethod + def deserialize(cls, data: dict) -> "NativeLayer": + """Deserialize the layer from a dict. + + Parameters + ---------- + data : dict + The dict to deserialize from. + """ + return cls(data["w"], data["b"], data.get("idt", None)) + + def __setitem__(self, key, value): + if key in ("w", "matrix"): + self.w = value + elif key in ("b", "bias"): + self.b = value + elif key == "idt": + self.idt = value + else: + raise KeyError(key) + + def __getitem__(self, key): + if key in ("w", "matrix"): + return self.w + elif key in ("b", "bias"): + return self.b + elif key == "idt": + return self.idt + else: + raise KeyError(key) + + +class NativeNet: + """Native representation of a neural network. + + Parameters + ---------- + layers : list[NativeLayer], optional + The layers of the network. + """ + + def __init__(self, layers: Optional[List[NativeLayer]] = None) -> None: + if layers is None: + layers = [] + self.layers = layers + + def serialize(self) -> dict: + """Serialize the network to a dict. + + Returns + ------- + dict + The serialized network. + """ + return {"layers": [layer.serialize() for layer in self.layers]} + + @classmethod + def deserialize(cls, data: dict) -> "NativeNet": + """Deserialize the network from a dict. + + Parameters + ---------- + data : dict + The dict to deserialize from. + """ + return cls([NativeLayer.deserialize(layer) for layer in data["layers"]]) + + def __getitem__(self, key): + assert isinstance(key, int) + if len(self.layers) <= key: + self.layers.extend([NativeLayer()] * (key - len(self.layers) + 1)) + return self.layers[key] + + def __setitem__(self, key, value): + assert isinstance(key, int) + if len(self.layers) <= key: + self.layers.extend([NativeLayer()] * (key - len(self.layers) + 1)) + self.layers[key] = value diff --git a/source/tests/test_model_format_utils.py b/source/tests/test_model_format_utils.py new file mode 100644 index 0000000000..b959ace3f6 --- /dev/null +++ b/source/tests/test_model_format_utils.py @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +import os +import unittest +from copy import ( + deepcopy, +) + +import numpy as np + +from deepmd_utils.model_format import ( + NativeNet, + load_dp_model, + save_dp_model, +) + + +class TestNativeNet(unittest.TestCase): + def setUp(self) -> None: + self.w = np.full((3, 2), 3.0) + self.b = np.full((3,), 4.0) + + def test_serialize(self): + network = NativeNet() + network[1]["w"] = self.w + network[1]["b"] = self.b + network[0]["w"] = self.w + network[0]["b"] = self.b + jdata = network.serialize() + np.testing.assert_array_equal(jdata["layers"][0]["w"], self.w) + np.testing.assert_array_equal(jdata["layers"][0]["b"], self.b) + np.testing.assert_array_equal(jdata["layers"][1]["w"], self.w) + np.testing.assert_array_equal(jdata["layers"][1]["b"], self.b) + + def test_deserialize(self): + network = NativeNet.deserialize( + { + "layers": [ + {"w": self.w, "b": self.b}, + {"w": self.w, "b": self.b}, + ] + } + ) + np.testing.assert_array_equal(network[0]["w"], self.w) + np.testing.assert_array_equal(network[0]["b"], self.b) + np.testing.assert_array_equal(network[1]["w"], self.w) + np.testing.assert_array_equal(network[1]["b"], self.b) + + +class TestDPModel(unittest.TestCase): + def setUp(self) -> None: + self.w = np.full((3, 2), 3.0) + self.b = np.full((3,), 4.0) + self.model_dict = { + "type": "some_type", + "@variables": { + "layers": [ + {"w": self.w, "b": self.b}, + {"w": self.w, "b": self.b}, + ] + }, + } + self.filename = "test_dp_model_format.dp" + + def test_save_load_model(self): + save_dp_model(self.filename, deepcopy(self.model_dict)) + model = load_dp_model(self.filename) + np.testing.assert_equal(model["model"], self.model_dict) + assert "software" in model + assert "version" in model + + def tearDown(self) -> None: + if os.path.exists(self.filename): + os.remove(self.filename) From a0f30f4f1cda17565b740ffb5bfcf9dbb7a30fda Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 17 Dec 2023 22:56:00 -0500 Subject: [PATCH 48/97] bump LAMMPS to stable_2Aug2023_update2 (#3066) --- backend/dynamic_metadata.py | 2 +- doc/install/install-lammps.md | 22 +++++++++++----------- pyproject.toml | 4 ++-- source/install/build_cc.sh | 2 +- source/install/build_from_c.sh | 2 +- source/install/build_lammps.sh | 2 +- source/install/test_cc.sh | 2 +- source/install/test_cc_local.sh | 2 +- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/backend/dynamic_metadata.py b/backend/dynamic_metadata.py index dad9c5b597..ab955c3cf8 100644 --- a/backend/dynamic_metadata.py +++ b/backend/dynamic_metadata.py @@ -57,7 +57,7 @@ def dynamic_metadata( "sphinxcontrib-bibtex", ], "lmp": [ - "lammps~=2023.8.2.1.0", + "lammps~=2023.8.2.2.0", *find_libpython_requires, ], "ipi": [ diff --git a/doc/install/install-lammps.md b/doc/install/install-lammps.md index e643660cd1..5dbf690c67 100644 --- a/doc/install/install-lammps.md +++ b/doc/install/install-lammps.md @@ -14,10 +14,10 @@ make lammps DeePMD-kit will generate a module called `USER-DEEPMD` in the `build` directory, which supports either double or single float precision interface. Now download the LAMMPS code, and uncompress it. ```bash cd /some/workspace -wget https://github.com/lammps/lammps/archive/stable_2Aug2023_update1.tar.gz -tar xf stable_2Aug2023_update1.tar.gz +wget https://github.com/lammps/lammps/archive/stable_2Aug2023_update2.tar.gz +tar xf stable_2Aug2023_update2.tar.gz ``` -The source code of LAMMPS is stored in the directory `lammps-stable_2Aug2023_update1`. +The source code of LAMMPS is stored in the directory `lammps-stable_2Aug2023_update2`. Then, you can [build LAMMPS](https://docs.lammps.org/Build.html) with either make or CMake. @@ -25,7 +25,7 @@ Then, you can [build LAMMPS](https://docs.lammps.org/Build.html) with either mak Now go into the LAMMPS code and copy the DeePMD-kit module like this ```bash -cd lammps-stable_2Aug2023_update1/src/ +cd lammps-stable_2Aug2023_update2/src/ cp -r $deepmd_source_dir/source/build/USER-DEEPMD . make yes-kspace make yes-extra-fix @@ -51,8 +51,8 @@ make no-user-deepmd Now go into the LAMMPS directory and create a directory called `build`: ```bash -mkdir -p lammps-stable_2Aug2023_update1/build/ -cd lammps-stable_2Aug2023_update1/build/ +mkdir -p lammps-stable_2Aug2023_update2/build/ +cd lammps-stable_2Aug2023_update2/build/ ``` Patch the LAMMPS `CMakeLists.txt` file: @@ -81,15 +81,15 @@ Starting from `8Apr2021`, LAMMPS also provides a plugin mode, allowing one to bu Now download the LAMMPS code (`8Apr2021` or later), and uncompress it: ```bash cd /some/workspace -wget https://github.com/lammps/lammps/archive/stable_2Aug2023_update1.tar.gz -tar xf stable_2Aug2023_update1.tar.gz +wget https://github.com/lammps/lammps/archive/stable_2Aug2023_update2.tar.gz +tar xf stable_2Aug2023_update2.tar.gz ``` -The source code of LAMMPS is stored in the directory `lammps-stable_2Aug2023_update1`. The directory of the source code should be specified as the CMAKE argument `LAMMPS_SOURCE_ROOT` during installation of the DeePMD-kit C++ interface. Now go into the LAMMPS directory and create a directory called `build` +The source code of LAMMPS is stored in the directory `lammps-stable_2Aug2023_update2`. The directory of the source code should be specified as the CMAKE argument `LAMMPS_SOURCE_ROOT` during installation of the DeePMD-kit C++ interface. Now go into the LAMMPS directory and create a directory called `build` ```bash -mkdir -p lammps-stable_2Aug2023_update1/build/ -cd lammps-stable_2Aug2023_update1/build/ +mkdir -p lammps-stable_2Aug2023_update2/build/ +cd lammps-stable_2Aug2023_update2/build/ ``` Now build LAMMPS. Note that `PLUGIN` must be enabled, and `BUILD_SHARED_LIBS` must be set to `yes`. You can install any other package you want. ```bash diff --git a/pyproject.toml b/pyproject.toml index fdd4904eb5..7b733adc81 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -139,7 +139,7 @@ manylinux-x86_64-image = "quay.io/pypa/manylinux_2_28_x86_64:2022-11-19-1b19e81" manylinux-aarch64-image = "manylinux_2_28" [tool.cibuildwheel.macos] -environment = { PIP_PREFER_BINARY="1", DP_LAMMPS_VERSION="stable_2Aug2023_update1", DP_ENABLE_IPI="1" } +environment = { PIP_PREFER_BINARY="1", DP_LAMMPS_VERSION="stable_2Aug2023_update2", DP_ENABLE_IPI="1" } before-all = [ """if [[ "$CIBW_BUILD" != *macosx_arm64* ]]; then brew install mpich; fi""", ] @@ -156,7 +156,7 @@ environment-pass = [ "CUDA_VERSION", "DP_PKG_NAME", ] -environment = { PIP_PREFER_BINARY="1", DP_LAMMPS_VERSION="stable_2Aug2023_update1", DP_ENABLE_IPI="1", MPI_HOME="/usr/lib64/mpich", PATH="/usr/lib64/mpich/bin:$PATH" } +environment = { PIP_PREFER_BINARY="1", DP_LAMMPS_VERSION="stable_2Aug2023_update2", DP_ENABLE_IPI="1", MPI_HOME="/usr/lib64/mpich", PATH="/usr/lib64/mpich/bin:$PATH" } before-all = [ """if [ ! -z "${DP_PKG_NAME}" ]; then sed -i "s/name = \\"deepmd-kit\\"/name = \\"${DP_PKG_NAME}\\"/g" pyproject.toml; fi""", """{ if [ "$(uname -m)" = "x86_64" ] ; then yum config-manager --add-repo http://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/cuda-rhel8.repo && yum install -y cuda-nvcc-${CUDA_VERSION/./-} cuda-cudart-devel-${CUDA_VERSION/./-}; fi }""", diff --git a/source/install/build_cc.sh b/source/install/build_cc.sh index 74e3835b74..fef9e82ebc 100755 --- a/source/install/build_cc.sh +++ b/source/install/build_cc.sh @@ -20,7 +20,7 @@ NPROC=$(nproc --all) BUILD_TMP_DIR=${SCRIPT_PATH}/../build mkdir -p ${BUILD_TMP_DIR} cd ${BUILD_TMP_DIR} -cmake -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DUSE_TF_PYTHON_LIBS=TRUE ${CUDA_ARGS} -DLAMMPS_VERSION=stable_2Aug2023_update1 .. +cmake -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DUSE_TF_PYTHON_LIBS=TRUE ${CUDA_ARGS} -DLAMMPS_VERSION=stable_2Aug2023_update2 .. cmake --build . -j${NPROC} cmake --install . diff --git a/source/install/build_from_c.sh b/source/install/build_from_c.sh index cd0aeca089..c1188252ab 100755 --- a/source/install/build_from_c.sh +++ b/source/install/build_from_c.sh @@ -13,7 +13,7 @@ NPROC=$(nproc --all) BUILD_TMP_DIR=${SCRIPT_PATH}/../build mkdir -p ${BUILD_TMP_DIR} cd ${BUILD_TMP_DIR} -cmake -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DDEEPMD_C_ROOT=${DEEPMD_C_ROOT} -DLAMMPS_VERSION=stable_2Aug2023_update1 .. +cmake -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DDEEPMD_C_ROOT=${DEEPMD_C_ROOT} -DLAMMPS_VERSION=stable_2Aug2023_update2 .. cmake --build . -j${NPROC} cmake --install . cmake --build . --target=lammps diff --git a/source/install/build_lammps.sh b/source/install/build_lammps.sh index c8cfa6ea54..2b5bf0a643 100755 --- a/source/install/build_lammps.sh +++ b/source/install/build_lammps.sh @@ -14,7 +14,7 @@ BUILD_TMP_DIR=${SCRIPT_PATH}/../build_lammps mkdir -p ${BUILD_TMP_DIR} cd ${BUILD_TMP_DIR} # download LAMMMPS -LAMMPS_VERSION=stable_2Aug2023_update1 +LAMMPS_VERSION=stable_2Aug2023_update2 if [ ! -d "lammps-${LAMMPS_VERSION}" ]; then curl -L -o lammps.tar.gz https://github.com/lammps/lammps/archive/refs/tags/${LAMMPS_VERSION}.tar.gz tar vxzf lammps.tar.gz diff --git a/source/install/test_cc.sh b/source/install/test_cc.sh index 0a8700b275..0dd35f5615 100755 --- a/source/install/test_cc.sh +++ b/source/install/test_cc.sh @@ -17,7 +17,7 @@ INSTALL_PREFIX=${SCRIPT_PATH}/../../dp_test BUILD_TMP_DIR=${SCRIPT_PATH}/../build_tests mkdir -p ${BUILD_TMP_DIR} cd ${BUILD_TMP_DIR} -cmake -DINSTALL_TENSORFLOW=TRUE -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DTENSORFLOW_ROOT=${INSTALL_PREFIX} -DBUILD_TESTING:BOOL=TRUE -DLAMMPS_VERSION=stable_2Aug2023_update1 ${CUDA_ARGS} .. +cmake -DINSTALL_TENSORFLOW=TRUE -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DTENSORFLOW_ROOT=${INSTALL_PREFIX} -DBUILD_TESTING:BOOL=TRUE -DLAMMPS_VERSION=stable_2Aug2023_update2 ${CUDA_ARGS} .. cmake --build . -j${NPROC} cmake --install . ctest --output-on-failure diff --git a/source/install/test_cc_local.sh b/source/install/test_cc_local.sh index 74477a8c2a..22d22a27f6 100755 --- a/source/install/test_cc_local.sh +++ b/source/install/test_cc_local.sh @@ -18,7 +18,7 @@ INSTALL_PREFIX=${SCRIPT_PATH}/../../dp_test BUILD_TMP_DIR=${SCRIPT_PATH}/../build_tests mkdir -p ${BUILD_TMP_DIR} cd ${BUILD_TMP_DIR} -cmake -DINSTALL_TENSORFLOW=FALSE -DUSE_TF_PYTHON_LIBS=TRUE -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DBUILD_TESTING:BOOL=TRUE -DLAMMPS_VERSION=stable_2Aug2023_update1 ${CUDA_ARGS} .. +cmake -DINSTALL_TENSORFLOW=FALSE -DUSE_TF_PYTHON_LIBS=TRUE -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} -DBUILD_TESTING:BOOL=TRUE -DLAMMPS_VERSION=stable_2Aug2023_update2 ${CUDA_ARGS} .. cmake --build . -j${NPROC} cmake --install . ctest --output-on-failure From a47cd0623f8e7293b7aa0fd1a4e1dfcde433746e Mon Sep 17 00:00:00 2001 From: Ye Ding Date: Thu, 21 Dec 2023 09:33:00 +0800 Subject: [PATCH 49/97] Update the path to training and validation data dir in zinc_se_a_mask.json (#3068) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- deepmd/descriptor/se_a_mask.py | 13 +++++++++++++ examples/zinc_protein/zinc_se_a_mask.json | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/deepmd/descriptor/se_a_mask.py b/deepmd/descriptor/se_a_mask.py index 780b34d294..cc2e6b4fc8 100644 --- a/deepmd/descriptor/se_a_mask.py +++ b/deepmd/descriptor/se_a_mask.py @@ -417,3 +417,16 @@ def prod_force_virial( atom_virial = tf.zeros([1, natoms[1], 9], dtype=force.dtype) return force, virial, atom_virial + + @classmethod + def update_sel(cls, global_jdata: dict, local_jdata: dict): + """Update the selection and perform neighbor statistics. + + Parameters + ---------- + global_jdata : dict + The global data, containing the training section + local_jdata : dict + The local data refer to the current class + """ + return local_jdata diff --git a/examples/zinc_protein/zinc_se_a_mask.json b/examples/zinc_protein/zinc_se_a_mask.json index b23987cf5d..04f63aa4ed 100644 --- a/examples/zinc_protein/zinc_se_a_mask.json +++ b/examples/zinc_protein/zinc_se_a_mask.json @@ -68,14 +68,14 @@ "training": { "training_data": { "systems": [ - "example/zinc_protein/train_data_dp_mask/" + "examples/zinc_protein/train_data_dp_mask/" ], "batch_size": 2, "_comment7": "that's all" }, "validation_data": { "systems": [ - "example/zinc_protein/val_data_dp_mask/" + "examples/zinc_protein/val_data_dp_mask/" ], "batch_size": 2, "_comment8": "that's all" From 2b52187e32a302796720f159dfdb0d1ca36e7710 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:38:33 +0800 Subject: [PATCH 50/97] [pre-commit.ci] pre-commit autoupdate (#3073) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/isort: 5.13.0 → 5.13.2](https://github.com/PyCQA/isort/compare/5.13.0...5.13.2) - [github.com/astral-sh/ruff-pre-commit: v0.1.7 → v0.1.8](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.7...v0.1.8) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ce83792f10..edca939faa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,14 +23,14 @@ repos: - id: check-toml # Python - repo: https://github.com/PyCQA/isort - rev: 5.13.0 + rev: 5.13.2 hooks: - id: isort files: \.py$ exclude: ^source/3rdparty - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.7 + rev: v0.1.8 hooks: - id: ruff args: ["--fix"] From 0032f5d5ae19d4fa4cbdb2529beec663744307d4 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 20 Dec 2023 20:48:10 -0500 Subject: [PATCH 51/97] add CodeQL checks (#3075) It can scan the codes and report as follows: ![image](https://github.com/deepmodeling/deepmd-kit/assets/9496702/77b518b9-56f5-414a-b116-68da3aa9d67a) --------- Signed-off-by: Jinzhe Zeng --- .github/workflows/codeql.yml | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..a9a162432c --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,58 @@ +name: "CodeQL" + +on: + push: + pull_request: + schedule: + - cron: '45 2 * * 2' + +jobs: + analyze: + name: Analyze + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'c-cpp', 'javascript-typescript', 'python' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + cache: 'pip' + if: matrix.language == 'c-cpp' + - name: "Setup dependencies" + if: matrix.language == 'c-cpp' + run: | + wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.0-1_all.deb \ + && sudo dpkg -i cuda-keyring_1.0-1_all.deb \ + && sudo apt-get update \ + && sudo apt-get -y install cuda-cudart-dev-12-2 cuda-nvcc-12-2 + python -m pip install tensorflow + env: + DEBIAN_FRONTEND: noninteractive + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + queries: security-extended,security-and-quality + - name: "Run, Build Application using script" + run: source/install/build_cc.sh + env: + DP_VARIANT: cuda + DOWNLOAD_TENSORFLOW: "FALSE" + if: matrix.language == 'c-cpp' + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" From f79eac1f9c5b1d661a5e2425afbcfcf63ebe2af1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:49:38 +0800 Subject: [PATCH 52/97] Bump actions/upload-artifact from 3 to 4 (#3070) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
Release notes

Sourced from actions/upload-artifact's releases.

v4.0.0

What's Changed

The release of upload-artifact@v4 and download-artifact@v4 are major changes to the backend architecture of Artifacts. They have numerous performance and behavioral improvements.

For more information, see the @​actions/artifact documentation.

New Contributors

Full Changelog: https://github.com/actions/upload-artifact/compare/v3...v4.0.0

v3.1.3

What's Changed

Full Changelog: https://github.com/actions/upload-artifact/compare/v3...v3.1.3

v3.1.2

  • Update all @actions/* NPM packages to their latest versions- #374
  • Update all dev dependencies to their most recent versions - #375

v3.1.1

  • Update actions/core package to latest version to remove set-output deprecation warning #351

v3.1.0

What's Changed

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=3&new-version=4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jinzhe Zeng --- .github/workflows/build_wheel.yml | 19 +++++++++++-------- .github/workflows/package_c.yml | 9 +++++---- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index e700109cce..40fc036419 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -77,8 +77,9 @@ jobs: DP_VARIANT: ${{ matrix.dp_variant }} CUDA_VERSION: ${{ matrix.cuda_version }} DP_PKG_NAME: ${{ matrix.dp_pkg_name }} - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: + name: cibw-cp${{ matrix.python }}-${{ matrix.platform_id }}-cu${{ matrix.cuda_version }}-${{ strategy.job-index }} path: ./wheelhouse/*.whl build_sdist: name: Build source distribution @@ -96,8 +97,9 @@ jobs: - name: Build sdist run: python -m build --sdist - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: + name: cibw-sdist path: dist/*.tar.gz upload_pypi: @@ -108,10 +110,11 @@ jobs: id-token: write if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v') steps: - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: - name: artifact + pattern: cibw-* path: dist + merge-multiple: true - uses: pypa/gh-action-pypi-publish@release/v1 build_docker: @@ -128,10 +131,10 @@ jobs: cuda_version: "11" steps: - uses: actions/checkout@v4 - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: - name: artifact path: source/install/docker/dist + merge-multiple: true - name: Log in to the Container registry uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d with: @@ -160,10 +163,10 @@ jobs: needs: [build_wheels, build_sdist] runs-on: ubuntu-latest steps: - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: - name: artifact path: dist/packages + merge-multiple: true - uses: actions/setup-python@v5 name: Install Python with: diff --git a/.github/workflows/package_c.yml b/.github/workflows/package_c.yml index 2b5f74b97d..5594c79181 100644 --- a/.github/workflows/package_c.yml +++ b/.github/workflows/package_c.yml @@ -28,9 +28,9 @@ jobs: if: matrix.filename != 'libdeepmd_c.tar.gz' # for download and debug - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: libdeepmd_c + name: libdeepmd_c-${{ strategy.job-index }}-${{ matrix.filename }} path: ${{ matrix.filename }} - name: Test C library run: ./source/install/docker_test_package_c.sh @@ -46,9 +46,10 @@ jobs: steps: - uses: actions/checkout@v4 - name: Download artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: libdeepmd_c + pattern: libdeepmd_c-* + merge-multiple: true - run: tar -vxzf ./libdeepmd_c.tar.gz - name: Test C library run: ./source/install/build_from_c.sh From b4fe171a75d466bccc7e2f2b8052483696872c87 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 20 Dec 2023 20:55:51 -0500 Subject: [PATCH 53/97] Fix catching by value (#3077) Fix: - https://github.com/deepmodeling/deepmd-kit/security/code-scanning/1229 - https://github.com/deepmodeling/deepmd-kit/security/code-scanning/1230 - https://github.com/deepmodeling/deepmd-kit/security/code-scanning/1231 - https://github.com/deepmodeling/deepmd-kit/security/code-scanning/1232 --- source/api_cc/src/DeepPot.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/api_cc/src/DeepPot.cc b/source/api_cc/src/DeepPot.cc index 018c3aca09..bb39a9fd60 100644 --- a/source/api_cc/src/DeepPot.cc +++ b/source/api_cc/src/DeepPot.cc @@ -474,7 +474,7 @@ void DeepPot::init(const std::string& model, ntypes = get_scalar("descrpt_attr/ntypes"); try { ntypes_spin = get_scalar("spin_attr/ntypes_spin"); - } catch (deepmd::deepmd_exception) { + } catch (const deepmd::deepmd_exception) { ntypes_spin = 0; } dfparam = get_scalar("fitting_attr/dfparam"); @@ -488,7 +488,7 @@ void DeepPot::init(const std::string& model, if (daparam > 0) { try { aparam_nall = get_scalar("fitting_attr/aparam_nall"); - } catch (deepmd::deepmd_exception) { + } catch (const deepmd::deepmd_exception) { aparam_nall = false; } } else { @@ -1331,7 +1331,7 @@ void DeepPotModelDevi::init(const std::vector& models, ntypes = get_scalar("descrpt_attr/ntypes"); try { ntypes_spin = get_scalar("spin_attr/ntypes_spin"); - } catch (deepmd::deepmd_exception) { + } catch (const deepmd::deepmd_exception) { ntypes_spin = 0; } dfparam = get_scalar("fitting_attr/dfparam"); @@ -1345,7 +1345,7 @@ void DeepPotModelDevi::init(const std::vector& models, if (daparam > 0) { try { aparam_nall = get_scalar("fitting_attr/aparam_nall"); - } catch (deepmd::deepmd_exception) { + } catch (const deepmd::deepmd_exception) { aparam_nall = false; } } else { From 39f13c00cedd0a1fcac089e5fd1e7007800afca6 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sun, 24 Dec 2023 20:42:06 -0500 Subject: [PATCH 54/97] docs: update documentation for pre-compiled C library (#3083) The link was changed by #3070. --- doc/install/easy-install-dev.md | 4 ++-- doc/install/install-from-c-library.md | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/install/easy-install-dev.md b/doc/install/easy-install-dev.md index 6fd9171730..f3cf52c1f5 100644 --- a/doc/install/easy-install-dev.md +++ b/doc/install/easy-install-dev.md @@ -26,8 +26,8 @@ pip install -U --pre deepmd-kit[gpu,cu12,lmp] --extra-index-url https://deepmode ## Download pre-compiled C Library -The [pre-comiled C library](./install-from-c-library.md) can be downloaded from [here](https://nightly.link/deepmodeling/deepmd-kit/workflows/package_c/devel/libdeepmd_c.zip), or via a shell command: +The [pre-comiled C library](./install-from-c-library.md) can be downloaded from [here](https://nightly.link/deepmodeling/deepmd-kit/workflows/package_c/devel/libdeepmd_c-0-libdeepmd_c.tar.gz.zip), or via a shell command: ```sh -wget https://nightly.link/deepmodeling/deepmd-kit/workflows/package_c/devel/libdeepmd_c.zip && unzip libdeepmd_c.zip +wget https://nightly.link/deepmodeling/deepmd-kit/workflows/package_c/devel/libdeepmd_c-0-libdeepmd_c.tar.gz.zip && unzip libdeepmd_c-0-libdeepmd_c.tar.gz.zip ``` diff --git a/doc/install/install-from-c-library.md b/doc/install/install-from-c-library.md index eb89538277..7613fdb772 100644 --- a/doc/install/install-from-c-library.md +++ b/doc/install/install-from-c-library.md @@ -1,6 +1,12 @@ # Install from pre-compiled C library DeePMD-kit provides pre-compiled C library package (`libdeepmd_c.tar.gz`) in each [release](https://github.com/deepmodeling/deepmd-kit/releases). It can be used to build the [LAMMPS plugin](./install-lammps.md) and [GROMACS patch](./install-gromacs.md), as well as many [third-party software packages](../third-party/out-of-deepmd-kit.md), without building TensorFlow and DeePMD-kit on one's own. +It can be downloaded via the shell command: + +```sh +wget https://github.com/deepmodeling/deepmd-kit/releases/latest/download/libdeepmd_c.tar.gz +tar xzf libdeepmd_c.tar.gz +``` The library is built in Linux (GLIBC 2.17) with CUDA 12.2 (`libdeepmd_c.tar.gz`) or 11.8 (`libdeepmd_c_cu11.tar.gz`). It's noted that this package does not contain CUDA Toolkit and cuDNN, so one needs to download them from the NVIDIA website. From 412bc3771851a2f04337557acf69976c6eb04510 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Dec 2023 07:43:49 +0800 Subject: [PATCH 55/97] Bump actions/deploy-pages from 3 to 4 (#3085) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/deploy-pages](https://github.com/actions/deploy-pages) from 3 to 4.
Release notes

Sourced from actions/deploy-pages's releases.

v4.0.0

Changelog

  • Deploy pages using artifact IDs @​konradpabjan (#251)
  • This version requires the permission actions: read in the workflows which use it.

ℹ️ This version of actions/deploy-pages is ONLY compatible with artifacts uploaded by either:

See details of all code changes since previous release.

:warning: For use with products other than GitHub.com, such as GitHub Enterprise Server, please consult the compatibility table.

v3.0.1

Changelog

🧰 Maintenance


See details of all code changes since previous release.

:warning: For use with products other than GitHub.com, such as GitHub Enterprise Server, please consult the compatibility table.

Commits
  • 7a9bd94 Merge pull request #290 from actions/dependabot/npm_and_yarn/undici-6.2.1
  • eee8a27 Update distributables after Dependabot 🤖
  • b6e5c85 Bump undici from 6.0.1 to 6.2.1
  • b8d2528 Merge pull request #282 from actions/dependabot/github_actions/github/codeql-...
  • 53d1eac Bump github/codeql-action from 2 to 3
  • 3f0ef9d Merge pull request #281 from actions/dependabot/github_actions/actions/upload...
  • 8275104 Bump actions/upload-artifact from 3 to 4
  • 9be9d73 Merge pull request #280 from actions/dependabot/npm_and_yarn/eslint-8.56.0
  • d8afefa Bump eslint from 8.55.0 to 8.56.0
  • 304d0b7 Merge pull request #277 from actions/dependabot/github_actions/actions/publis...
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/deploy-pages&package-manager=github_actions&previous-version=3&new-version=4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_wheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 40fc036419..1f59e5173b 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -192,7 +192,7 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v3 + uses: actions/deploy-pages@v4 pass: name: Pass testing build wheels From 6819b8ed7667c0bfbe90e27c139adb58405c9809 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Dec 2023 07:44:08 +0800 Subject: [PATCH 56/97] Bump docker/metadata-action from 5.3.0 to 5.4.0 (#3086) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 5.3.0 to 5.4.0.
Release notes

Sourced from docker/metadata-action's releases.

v5.4.0

Full Changelog: https://github.com/docker/metadata-action/compare/v5.3.0...v5.4.0

Commits
  • 9dc751f Merge pull request #369 from docker/dependabot/npm_and_yarn/docker/actions-to...
  • c94c54c chore: update generated content
  • 187f092 chore(deps): Bump @​docker/actions-toolkit from 0.15.0 to 0.16.0
  • 6d6eaf3 Merge pull request #365 from docker/dependabot/npm_and_yarn/csv-parse-5.5.3
  • 1484a7e chore(deps): Bump csv-parse from 5.5.2 to 5.5.3
  • See full diff in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/metadata-action&package-manager=github_actions&previous-version=5.3.0&new-version=5.4.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_wheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 1f59e5173b..18767d2137 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -144,7 +144,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@31cebacef4805868f9ce9a0cb03ee36c32df2ac4 + uses: docker/metadata-action@9dc751fe249ad99385a2583ee0d084c400eee04e with: images: ghcr.io/deepmodeling/deepmd-kit From 54e5988501890030d5b3c87f0d16e4c2938fe25a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Dec 2023 20:05:23 -0500 Subject: [PATCH 57/97] Bump actions/upload-pages-artifact from 2 to 3 (#3087) --- .github/workflows/build_wheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index 18767d2137..e47f14b1f4 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -176,7 +176,7 @@ jobs: ls dist/packages > package_list.txt dumb-pypi --output-dir dist --packages-url ../../packages --package-list package_list.txt --title "DeePMD-kit Developed Packages" - name: Upload Pages artifact - uses: actions/upload-pages-artifact@v2 + uses: actions/upload-pages-artifact@v3 with: path: dist deploy_pypi_index: From 228711136f245cada12e9a5e4332173da577f702 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 28 Dec 2023 17:58:13 +0800 Subject: [PATCH 58/97] [pre-commit.ci] pre-commit autoupdate (#3089) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.1.8 → v0.1.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.8...v0.1.9) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index edca939faa..efa2bc1675 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,7 +30,7 @@ repos: exclude: ^source/3rdparty - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.8 + rev: v0.1.9 hooks: - id: ruff args: ["--fix"] From 985a88676745f6f68af161a6aba693210796ff7d Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 1 Jan 2024 19:45:06 -0500 Subject: [PATCH 59/97] lmp: Register styles when using CMake (#3097) Fix #3092. --- source/lmp/builtin.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/lmp/builtin.cmake b/source/lmp/builtin.cmake index 507fe7bf1a..f29e9d3319 100644 --- a/source/lmp/builtin.cmake +++ b/source/lmp/builtin.cmake @@ -29,3 +29,7 @@ target_include_directories( ${LAMMPS_SOURCE_DIR}/KSPACE ${LAMMPS_SOURCE_DIR}/EXTRA-FIX) target_compile_definitions( lammps PRIVATE "LAMMPS_VERSION_NUMBER=${LAMMPS_VERSION_NUMBER}") + +# register styles +registerstyles(${CMAKE_CURRENT_LIST_DIR}) +generatestyleheaders(${LAMMPS_STYLE_HEADERS_DIR}) From a905817f77a59306e2a393e91f34ee4e62f611c6 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Tue, 2 Jan 2024 21:41:46 -0500 Subject: [PATCH 60/97] Add pairwise tabulation as an independent model (#3101) Add pairwise tabulation as an independent model, which can be summed with DP (DP + PairTab) by the linear model, other than interpolation. PairTab can be used for any pairwise potentials, e.g., d3, LJ, ZBL, etc. Fix #3099. --------- Signed-off-by: Jinzhe Zeng --- README.md | 2 +- deepmd/model/model.py | 5 + deepmd/model/pairtab.py | 288 +++++++++++++++++++++++++++++ deepmd/utils/argcheck.py | 21 +++ doc/model/index.md | 2 +- doc/model/pairtab.md | 55 +++++- examples/water/d3/README.md | 11 ++ examples/water/d3/dftd3.txt | 100 ++++++++++ examples/water/d3/input.json | 95 ++++++++++ source/tests/test_model_pairtab.py | 127 +++++++++++++ 10 files changed, 703 insertions(+), 3 deletions(-) create mode 100644 deepmd/model/pairtab.py create mode 100644 examples/water/d3/README.md create mode 100644 examples/water/d3/dftd3.txt create mode 100644 examples/water/d3/input.json create mode 100644 source/tests/test_model_pairtab.py diff --git a/README.md b/README.md index a1e9c9484a..81fdead098 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ A full [document](doc/train/train-input-auto.rst) on options in the training inp - [Deep potential long-range](doc/model/dplr.md) - [Deep Potential - Range Correction (DPRc)](doc/model/dprc.md) - [Linear model](doc/model/linear.md) - - [Interpolation with a pairwise potential](doc/model/pairtab.md) + - [Interpolation or combination with a pairwise potential](doc/model/pairtab.md) - [Training](doc/train/index.md) - [Training a model](doc/train/training.md) - [Advanced options](doc/train/training-advanced.md) diff --git a/deepmd/model/model.py b/deepmd/model/model.py index dd439056b4..6117b4942d 100644 --- a/deepmd/model/model.py +++ b/deepmd/model/model.py @@ -97,6 +97,9 @@ def get_class_by_input(cls, input: dict): from deepmd.model.multi import ( MultiModel, ) + from deepmd.model.pairtab import ( + PairTabModel, + ) from deepmd.model.pairwise_dprc import ( PairwiseDPRc, ) @@ -112,6 +115,8 @@ def get_class_by_input(cls, input: dict): return FrozenModel elif model_type == "linear_ener": return LinearEnergyModel + elif model_type == "pairtab": + return PairTabModel else: raise ValueError(f"unknown model type: {model_type}") diff --git a/deepmd/model/pairtab.py b/deepmd/model/pairtab.py new file mode 100644 index 0000000000..38934818e6 --- /dev/null +++ b/deepmd/model/pairtab.py @@ -0,0 +1,288 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +from enum import ( + Enum, +) +from typing import ( + List, + Optional, + Union, +) + +import numpy as np + +from deepmd.env import ( + GLOBAL_TF_FLOAT_PRECISION, + MODEL_VERSION, + global_cvt_2_ener_float, + op_module, + tf, +) +from deepmd.fit.fitting import ( + Fitting, +) +from deepmd.loss.loss import ( + Loss, +) +from deepmd.model.model import ( + Model, +) +from deepmd.utils.pair_tab import ( + PairTab, +) + + +class PairTabModel(Model): + """Pairwise tabulation energy model. + + This model can be used to tabulate the pairwise energy between atoms for either + short-range or long-range interactions, such as D3, LJ, ZBL, etc. It should not + be used alone, but rather as one submodel of a linear (sum) model, such as + DP+D3. + + Do not put the model on the first model of a linear model, since the linear + model fetches the type map from the first model. + + At this moment, the model does not smooth the energy at the cutoff radius, so + one needs to make sure the energy has been smoothed to zero. + + Parameters + ---------- + tab_file : str + The path to the tabulation file. + rcut : float + The cutoff radius + sel : int or list[int] + The maxmum number of atoms in the cut-off radius + """ + + model_type = "ener" + + def __init__( + self, tab_file: str, rcut: float, sel: Union[int, List[int]], **kwargs + ): + super().__init__() + self.tab_file = tab_file + self.tab = PairTab(self.tab_file) + self.ntypes = self.tab.ntypes + self.rcut = rcut + if isinstance(sel, int): + self.sel = sel + elif isinstance(sel, list): + self.sel = sum(sel) + else: + raise TypeError("sel must be int or list[int]") + + def build( + self, + coord_: tf.Tensor, + atype_: tf.Tensor, + natoms: tf.Tensor, + box: tf.Tensor, + mesh: tf.Tensor, + input_dict: dict, + frz_model: Optional[str] = None, + ckpt_meta: Optional[str] = None, + suffix: str = "", + reuse: Optional[Union[bool, Enum]] = None, + ): + """Build the model. + + Parameters + ---------- + coord_ : tf.Tensor + The coordinates of atoms + atype_ : tf.Tensor + The atom types of atoms + natoms : tf.Tensor + The number of atoms + box : tf.Tensor + The box vectors + mesh : tf.Tensor + The mesh vectors + input_dict : dict + The input dict + frz_model : str, optional + The path to the frozen model + ckpt_meta : str, optional + The path prefix of the checkpoint and meta files + suffix : str, optional + The suffix of the scope + reuse : bool or tf.AUTO_REUSE, optional + Whether to reuse the variables + + Returns + ------- + dict + The output dict + """ + tab_info, tab_data = self.tab.get() + with tf.variable_scope("model_attr" + suffix, reuse=reuse): + self.tab_info = tf.get_variable( + "t_tab_info", + tab_info.shape, + dtype=tf.float64, + trainable=False, + initializer=tf.constant_initializer(tab_info, dtype=tf.float64), + ) + self.tab_data = tf.get_variable( + "t_tab_data", + tab_data.shape, + dtype=tf.float64, + trainable=False, + initializer=tf.constant_initializer(tab_data, dtype=tf.float64), + ) + t_tmap = tf.constant(" ".join(self.type_map), name="tmap", dtype=tf.string) + t_mt = tf.constant(self.model_type, name="model_type", dtype=tf.string) + t_ver = tf.constant(MODEL_VERSION, name="model_version", dtype=tf.string) + + with tf.variable_scope("fitting_attr" + suffix, reuse=reuse): + t_dfparam = tf.constant(0, name="dfparam", dtype=tf.int32) + t_daparam = tf.constant(0, name="daparam", dtype=tf.int32) + with tf.variable_scope("descrpt_attr" + suffix, reuse=reuse): + t_ntypes = tf.constant(self.ntypes, name="ntypes", dtype=tf.int32) + t_rcut = tf.constant( + self.rcut, name="rcut", dtype=GLOBAL_TF_FLOAT_PRECISION + ) + coord = tf.reshape(coord_, [-1, natoms[1] * 3]) + atype = tf.reshape(atype_, [-1, natoms[1]]) + box = tf.reshape(box, [-1, 9]) + # perhaps we need a OP that only outputs rij and nlist + ( + _, + _, + rij, + nlist, + _, + _, + ) = op_module.prod_env_mat_a_mix( + coord, + atype, + natoms, + box, + mesh, + np.zeros([self.ntypes, self.sel * 4]), + np.ones([self.ntypes, self.sel * 4]), + rcut_a=-1, + rcut_r=self.rcut, + rcut_r_smth=self.rcut, + sel_a=[self.sel], + sel_r=[0], + ) + scale = tf.ones([tf.shape(coord)[0], natoms[0]], dtype=tf.float64) + tab_atom_ener, tab_force, tab_atom_virial = op_module.pair_tab( + self.tab_info, + self.tab_data, + atype, + rij, + nlist, + natoms, + scale, + sel_a=[self.sel], + sel_r=[0], + ) + energy_raw = tf.reshape( + tab_atom_ener, [-1, natoms[0]], name="o_atom_energy" + suffix + ) + energy = tf.reduce_sum( + global_cvt_2_ener_float(energy_raw), axis=1, name="o_energy" + suffix + ) + force = tf.reshape(tab_force, [-1, 3 * natoms[1]], name="o_force" + suffix) + virial = tf.reshape( + tf.reduce_sum(tf.reshape(tab_atom_virial, [-1, natoms[1], 9]), axis=1), + [-1, 9], + name="o_virial" + suffix, + ) + atom_virial = tf.reshape( + tab_atom_virial, [-1, 9 * natoms[1]], name="o_atom_virial" + suffix + ) + model_dict = {} + model_dict["energy"] = energy + model_dict["force"] = force + model_dict["virial"] = virial + model_dict["atom_ener"] = energy_raw + model_dict["atom_virial"] = atom_virial + model_dict["coord"] = coord + model_dict["atype"] = atype + + return model_dict + + def init_variables( + self, + graph: tf.Graph, + graph_def: tf.GraphDef, + model_type: str = "original_model", + suffix: str = "", + ) -> None: + """Init the embedding net variables with the given frozen model. + + Parameters + ---------- + graph : tf.Graph + The input frozen model graph + graph_def : tf.GraphDef + The input frozen model graph_def + model_type : str + the type of the model + suffix : str + suffix to name scope + """ + # skip. table can be initialized from the file + + def get_fitting(self) -> Union[Fitting, dict]: + """Get the fitting(s).""" + # nothing needs to do + return {} + + def get_loss(self, loss: dict, lr) -> Optional[Union[Loss, dict]]: + """Get the loss function(s).""" + # nothing nees to do + return + + def get_rcut(self) -> float: + """Get cutoff radius of the model.""" + return self.rcut + + def get_ntypes(self) -> int: + """Get the number of types.""" + return self.ntypes + + def data_stat(self, data: dict): + """Data staticis.""" + # nothing needs to do + + def enable_compression(self, suffix: str = "") -> None: + """Enable compression. + + Parameters + ---------- + suffix : str + suffix to name scope + """ + # nothing needs to do + + @classmethod + def update_sel(cls, global_jdata: dict, local_jdata: dict) -> dict: + """Update the selection and perform neighbor statistics. + + Notes + ----- + Do not modify the input data without copying it. + + Parameters + ---------- + global_jdata : dict + The global data, containing the training section + local_jdata : dict + The local data refer to the current class + + Returns + ------- + dict + The updated local data + """ + from deepmd.entrypoints.train import ( + update_one_sel, + ) + + local_jdata_cpy = local_jdata.copy() + return update_one_sel(global_jdata, local_jdata_cpy, True) diff --git a/deepmd/utils/argcheck.py b/deepmd/utils/argcheck.py index 8d09d25577..2c1d235801 100644 --- a/deepmd/utils/argcheck.py +++ b/deepmd/utils/argcheck.py @@ -927,6 +927,7 @@ def model_args(exclude_hybrid=False): standard_model_args(), multi_model_args(), frozen_model_args(), + pairtab_model_args(), *hybrid_models, ], optional=True, @@ -1013,6 +1014,26 @@ def frozen_model_args() -> Argument: return ca +def pairtab_model_args() -> Argument: + doc_tab_file = "Path to the tabulation file." + doc_rcut = "The cut-off radius." + doc_sel = 'This parameter set the number of selected neighbors. Note that this parameter is a little different from that in other descriptors. Instead of separating each type of atoms, only the summation matters. And this number is highly related with the efficiency, thus one should not make it too large. Usually 200 or less is enough, far away from the GPU limitation 4096. It can be:\n\n\ + - `int`. The maximum number of neighbor atoms to be considered. We recommend it to be less than 200. \n\n\ + - `List[int]`. The length of the list should be the same as the number of atom types in the system. `sel[i]` gives the selected number of type-i neighbors. Only the summation of `sel[i]` matters, and it is recommended to be less than 200.\ + - `str`. Can be "auto:factor" or "auto". "factor" is a float number larger than 1. This option will automatically determine the `sel`. In detail it counts the maximal number of neighbors with in the cutoff radius for each type of neighbor, then multiply the maximum by the "factor". Finally the number is wraped up to 4 divisible. The option "auto" is equivalent to "auto:1.1".' + ca = Argument( + "pairtab", + dict, + [ + Argument("tab_file", str, optional=False, doc=doc_tab_file), + Argument("rcut", float, optional=False, doc=doc_rcut), + Argument("sel", [int, List[int], str], optional=False, doc=doc_sel), + ], + doc="Pairwise tabulation energy model.", + ) + return ca + + def linear_ener_model_args() -> Argument: doc_weights = ( "If the type is list of float, a list of weights for each model. " diff --git a/doc/model/index.md b/doc/model/index.md index 6c128028a6..589b39b2b5 100644 --- a/doc/model/index.md +++ b/doc/model/index.md @@ -17,4 +17,4 @@ - [Deep potential long-range](dplr.md) - [Deep Potential - Range Correction (DPRc)](dprc.md) - [Linear model](linear.md) -- [Interpolation with a pairwise potential](pairtab.md) +- [Interpolation or combination with a pairwise potential](pairtab.md) diff --git a/doc/model/pairtab.md b/doc/model/pairtab.md index e3f0118f2c..115345796a 100644 --- a/doc/model/pairtab.md +++ b/doc/model/pairtab.md @@ -1,4 +1,4 @@ -# Interpolation with a pairwise potential +# Interpolation or combination with a pairwise potential ## Theory In applications like the radiation damage simulation, the interatomic distance may become too close, so that the DFT calculations fail. @@ -33,3 +33,56 @@ where the scale $\alpha_s$ is a tunable scale of the interatomic distance $r_{ij The pairwise potential $u^{\textrm{pair}}(r)$ is defined by a user-defined table that provides the value of $u^{\textrm{pair}}$ on an evenly discretized grid from 0 to the cutoff distance.[^1] [^1]: This section is built upon Jinzhe Zeng, Duo Zhang, Denghui Lu, Pinghui Mo, Zeyu Li, Yixiao Chen, Marián Rynik, Li'ang Huang, Ziyao Li, Shaochen Shi, Yingze Wang, Haotian Ye, Ping Tuo, Jiabin Yang, Ye Ding, Yifan Li, Davide Tisi, Qiyu Zeng, Han Bao, Yu Xia, Jiameng Huang, Koki Muraoka, Yibo Wang, Junhan Chang, Fengbo Yuan, Sigbjørn Løland Bore, Chun Cai, Yinnian Lin, Bo Wang, Jiayan Xu, Jia-Xin Zhu, Chenxing Luo, Yuzhi Zhang, Rhys E. A. Goodall, Wenshuo Liang, Anurag Kumar Singh, Sikai Yao, Jingchao Zhang, Renata Wentzcovitch, Jiequn Han, Jie Liu, Weile Jia, Darrin M. York, Weinan E, Roberto Car, Linfeng Zhang, Han Wang, [J. Chem. Phys. 159, 054801 (2023)](https://doi.org/10.1063/5.0155600) licensed under a [Creative Commons Attribution (CC BY) license](http://creativecommons.org/licenses/by/4.0/). + +DeePMD-kit also supports combination with a pairwise potential: + +```math + E_i = E_i^{\mathrm{DP}} + E_i^{\mathrm{pair}}, +``` + +## Table file + +The table file should be a text file that can be read by {py:meth}`numpy.loadtxt`. +The first column is the distance between two atoms, where upper range should be larger than the cutoff radius. +Other columns are two-body interaction energies for pairs of certain types, +in the order of Type_0-Type_0, Type_0-Type_1, ..., Type_0-Type_N, Type_1-Type_1, ..., Type_1-Type_N, ..., and Type_N-Type_N. + +The interaction should be smooth at the cut-off distance. + +## Interpolation with a short-range pairwise potential + +```json +"model": { + "use_srtab": "H2O_tab_potential.txt", + "smin_alpha": 0.1, + "sw_rmin": 0.8, + "sw_rmax": 1.0, + "_comment": "Below uses a normal DP model" +} +``` + +{ref}`sw_rmin ` and {ref}`sw_rmax ` must be smaller than the cutoff radius of the DP model. + +## Combination with a pairwise potential + +To combine with a pairwise potential, use the [linear model](./linear.md): + +```json +"model": { + "type": "linear_ener", + "weights": "sum", + "models": [ + { + "_comment": "Here uses a normal DP model" + }, + { + "type": "pairtab", + "tab_file": "dftd3.txt", + "rcut": 10.0, + "sel": 534 + } + ] +} +``` + +The {ref}`rcut ` can be larger than that of the DP model. diff --git a/examples/water/d3/README.md b/examples/water/d3/README.md new file mode 100644 index 0000000000..bd75960010 --- /dev/null +++ b/examples/water/d3/README.md @@ -0,0 +1,11 @@ +# DPD3 + +`dftd3.txt` tabulates D3 dispersion for each pair of types (O-O, O-H, H-H). +It can be generated by [simple-dftd3](https://github.com/dftd3/simple-dftd3). + +## Note + +As an example, it cannot be used in production: + +- For small file sizes in the repository, the distance interval in the tabulation is only 0.1. +- The example training data does not contain dispersion interaction. diff --git a/examples/water/d3/dftd3.txt b/examples/water/d3/dftd3.txt new file mode 100644 index 0000000000..bbc9726134 --- /dev/null +++ b/examples/water/d3/dftd3.txt @@ -0,0 +1,100 @@ +1.000000000000000056e-01 -5.836993924755046366e-03 -3.207255698139210940e-03 -1.843064837882633228e-03 +2.000000000000000111e-01 -5.836993806911452108e-03 -3.207255613696154226e-03 -1.843064776130543892e-03 +3.000000000000000444e-01 -5.836992560106194113e-03 -3.207254720510349828e-03 -1.843064123123401392e-03 +4.000000000000000222e-01 -5.836986225627246658e-03 -3.207250184384043221e-03 -1.843060811677158526e-03 +5.000000000000000000e-01 -5.836964436915091821e-03 -3.207234589497737730e-03 -1.843052788205641135e-03 +5.999999999999999778e-01 -5.836905460107320170e-03 -3.207192410957825698e-03 -1.843338972660025360e-03 +7.000000000000000666e-01 -5.836769626930583300e-03 -3.207096085246822614e-03 -1.851839876215982238e-03 +8.000000000000000444e-01 -5.836491030513121618e-03 -3.206924889333430135e-03 -2.035200426069873857e-03 +9.000000000000000222e-01 -5.835967602710929840e-03 -3.206999537190755728e-03 -3.724418810291191088e-03 +1.000000000000000000e+00 -5.835053775792304297e-03 -3.210477055685919626e-03 -4.311009958284344433e-03 +1.100000000000000089e+00 -5.833591489567684953e-03 -3.237527828601436623e-03 -4.381510573223419171e-03 +1.200000000000000178e+00 -5.831652981781070173e-03 -3.454845258034439960e-03 -4.394419437232751843e-03 +1.300000000000000266e+00 -5.830520601296543433e-03 -4.478070067533340692e-03 -4.394683688871586433e-03 +1.400000000000000133e+00 -5.835353622834494637e-03 -5.097530655625692915e-03 -4.389691198859401421e-03 +1.500000000000000222e+00 -5.863290690264541874e-03 -5.215500241204417201e-03 -4.380686516072217034e-03 +1.600000000000000089e+00 -6.007605076700822840e-03 -5.234994618743306349e-03 -4.367337507268855175e-03 +1.700000000000000178e+00 -6.481613230242359684e-03 -5.228094160806716871e-03 -4.348706108547779198e-03 +1.800000000000000266e+00 -6.814114687600298335e-03 -5.208252365588400719e-03 -4.323505520547227775e-03 +1.900000000000000133e+00 -6.876286379079538276e-03 -5.177988357772074675e-03 -4.290186895355558444e-03 +2.000000000000000000e+00 -6.858440816799354217e-03 -5.136887568332395605e-03 -4.246989919717190920e-03 +2.100000000000000089e+00 -6.810730159155128395e-03 -5.083475665301987606e-03 -4.192000168715152505e-03 +2.200000000000000178e+00 -6.742330737387775344e-03 -5.015815334399144516e-03 -4.123231519970332187e-03 +2.300000000000000266e+00 -6.653841351238824232e-03 -4.931782661310191510e-03 -4.038743210125123918e-03 +2.400000000000000355e+00 -6.543651317938833402e-03 -4.829269294496830317e-03 -3.936795390727530070e-03 +2.500000000000000444e+00 -6.409559281498313811e-03 -4.706385522261587705e-03 -3.816040239463167755e-03 +2.600000000000000089e+00 -6.249406635892575460e-03 -4.561685215972477100e-03 -3.675736338668155346e-03 +2.700000000000000178e+00 -6.061478463281754457e-03 -4.394408172892586353e-03 -3.515962176363645990e-03 +2.800000000000000266e+00 -5.844844934626365965e-03 -4.204716954930251029e-03 -3.337792190764940319e-03 +2.900000000000000355e+00 -5.599669004675433479e-03 -3.993889719587391009e-03 -3.143390268473208755e-03 +3.000000000000000444e+00 -5.327453506642119106e-03 -3.764420755089863558e-03 -2.935977648106832729e-03 +3.100000000000000089e+00 -5.031178000843260223e-03 -3.519982860915751074e-03 -2.719650568099894056e-03 +3.200000000000000178e+00 -4.715273672783852794e-03 -3.265225882759082918e-03 -2.499057451653833965e-03 +3.300000000000000266e+00 -4.385404785641488362e-03 -3.005422601424333727e-03 -2.278985743812388717e-03 +3.400000000000000355e+00 -4.048065433713449700e-03 -2.746015696661484231e-03 -2.063937321866260270e-03 +3.500000000000000444e+00 -3.710048572169818114e-03 -2.492149763588673555e-03 -1.857774171128685628e-03 +3.600000000000000089e+00 -3.377881092113224713e-03 -2.248275746149775312e-03 -1.663491260531681313e-03 +3.700000000000000178e+00 -3.057327225182689644e-03 -2.017890114824574810e-03 -1.483133951195727196e-03 +3.800000000000000266e+00 -2.753038981057491941e-03 -1.803430168074075671e-03 -1.317840750738439540e-03 +3.900000000000000355e+00 -2.468388171389931940e-03 -1.606308000309067743e-03 -1.167971059502070875e-03 +4.000000000000000000e+00 -2.205469013267805957e-03 -1.427041871266797194e-03 -1.033273795673775699e-03 +4.099999999999999645e+00 -1.965228953751702902e-03 -1.265437879541002862e-03 -9.130610310879381641e-04 +4.200000000000000178e+00 -1.747673832278765806e-03 -1.120782158543769547e-03 -8.063636493380576522e-04 +4.299999999999999822e+00 -1.552098284175109895e-03 -9.920168984562682292e-04 -7.120580835032176920e-04 +4.399999999999999467e+00 -1.377305748647780163e-03 -8.778864597897169646e-04 -6.289618864203703032e-04 +4.500000000000000000e+00 -1.221797526507303194e-03 -7.770496638083513111e-04 -5.559009474092405914e-04 +4.599999999999999645e+00 -1.083922782809847944e-03 -6.881603844395511003e-04 -4.917533939693695443e-04 +4.700000000000000178e+00 -9.619897379282633162e-04 -6.099214740721333600e-04 -4.354756390957214944e-04 +4.799999999999999822e+00 -8.543428352989788704e-04 -5.411178648690499965e-04 -3.861155118068372257e-04 +4.900000000000000355e+00 -7.594124385866309881e-04 -4.806343247547230249e-04 -3.428165131289927659e-04 +5.000000000000000000e+00 -6.757436744162991990e-04 -4.274624687438948085e-04 -3.048162971647301774e-04 +5.099999999999999645e+00 -6.020102408497160842e-04 -3.807006248475114439e-04 -2.714416410742632600e-04 +5.200000000000000178e+00 -5.370178955485286568e-04 -3.395492294862310413e-04 -2.421014916366724180e-04 +5.299999999999999822e+00 -4.797012289428498875e-04 -3.033036596191310643e-04 -2.162791601488694472e-04 +5.400000000000000355e+00 -4.291163603974148220e-04 -2.713458112672340397e-04 -1.935243599692976007e-04 +5.500000000000000000e+00 -3.844314156775488251e-04 -2.431352896687036106e-04 -1.734455139070628909e-04 +5.599999999999999645e+00 -3.449160478270333653e-04 -2.182007570692257958e-04 -1.557025751017268144e-04 +5.700000000000000178e+00 -3.099308250478081581e-04 -1.961317615550248216e-04 -1.400004825033046053e-04 +5.799999999999999822e+00 -2.789169965744946232e-04 -1.765712194195623135e-04 -1.260832928664179986e-04 +5.900000000000000355e+00 -2.513869308376957498e-04 -1.592086242469989389e-04 -1.137289820430557137e-04 +6.000000000000000000e+00 -2.269153740910770769e-04 -1.437739928526920498e-04 -1.027448796326863424e-04 +6.099999999999999645e+00 -2.051315821421489645e-04 -1.300325201124615134e-04 -9.296368585686617101e-05 +6.200000000000000178e+00 -1.857123177371916057e-04 -1.177798933810950252e-04 -8.424001307773229020e-05 +6.299999999999999822e+00 -1.683756703844696025e-04 -1.068382068924710331e-04 -7.644739339328402133e-05 +6.400000000000000355e+00 -1.528756359693242027e-04 -9.705241326038571551e-05 -6.947569600606938272e-05 +6.500000000000000000e+00 -1.389973847900246836e-04 -8.828725024164000819e-05 -6.322890211399061677e-05 +6.599999999999999645e+00 -1.265531447216864910e-04 -8.042458445906290783e-05 -5.762318996708282935e-05 +6.700000000000000178e+00 -1.153786284350462083e-04 -7.336111861455703732e-05 -5.258528787829301387e-05 +6.799999999999999822e+00 -1.053299381724164837e-04 -6.700641408290249014e-05 -4.805105801105378322e-05 +6.900000000000000355e+00 -9.628088734156424651e-05 -6.128118618925484863e-05 -4.396427848897285724e-05 +7.000000000000000000e+00 -8.812068437769617318e-05 -5.611583465513190913e-05 -4.027559568117881135e-05 +7.099999999999999645e+00 -8.075193047879847589e-05 -5.144917649553730292e-05 -3.694162237238345173e-05 +7.200000000000000178e+00 -7.408888866698059216e-05 -4.722735299269381154e-05 -3.392416093003276399e-05 +7.299999999999999822e+00 -6.805598702152939358e-05 -4.340288624040664528e-05 -3.118953355495664799e-05 +7.400000000000000355e+00 -6.258652380321327402e-05 -3.993386415929820209e-05 -2.870800428147100793e-05 +7.500000000000000000e+00 -5.762154653038724025e-05 -3.678323585657680581e-05 -2.645327961777798337e-05 +7.599999999999999645e+00 -5.310888089285451013e-05 -3.391820178292012157e-05 -2.440207662848582849e-05 +7.700000000000000178e+00 -4.900228873380196631e-05 -3.130968536501008690e-05 -2.253374889733842244e-05 +7.799999999999999822e+00 -4.526073723647751752e-05 -2.893187470658392955e-05 -2.082996220611386151e-05 +7.900000000000000355e+00 -4.184776396661089387e-05 -2.676182459276817884e-05 -1.927441295794754013e-05 +8.000000000000000000e+00 -3.873092458939377268e-05 -2.477911043795883125e-05 -1.785258338919504348e-05 +8.099999999999999645e+00 -3.588131194417033489e-05 -2.296552701898519263e-05 -1.655152847892165657e-05 +8.199999999999999289e+00 -3.327313676038550535e-05 -2.130482586144845337e-05 -1.535969020138178571e-05 +8.300000000000000711e+00 -3.088336167038252842e-05 -1.978248602307972753e-05 -1.426673539356727330e-05 +8.400000000000000355e+00 -2.869138134992016182e-05 -1.838551376555334571e-05 -1.326341404347894562e-05 +8.500000000000000000e+00 -2.667874262351516647e-05 -1.710226724425689568e-05 -1.234143525923654349e-05 +8.599999999999999645e+00 -2.482889923305170253e-05 -1.592230289025118773e-05 -1.149335856644029766e-05 +8.699999999999999289e+00 -2.312699670543422217e-05 -1.483624062390156494e-05 -1.071249851148625846e-05 +8.800000000000000711e+00 -2.155968338640409072e-05 -1.383564543725925445e-05 -9.992840830439041262e-06 +8.900000000000000355e+00 -2.011494424844594071e-05 -1.291292322228744002e-05 -9.328968683880578804e-06 +9.000000000000000000e+00 -1.878195454422273937e-05 -1.206122901303710759e-05 -8.715997664073560640e-06 +9.099999999999999645e+00 -1.755095077450199208e-05 -1.127438605916122122e-05 -8.149518457037649769e-06 +9.199999999999999289e+00 -1.641311678073074286e-05 -1.054681436190059537e-05 -7.625546193173260002e-06 +9.300000000000000711e+00 -1.536048306550537418e-05 -9.873467487129955082e-06 -7.140475649634374041e-06 +9.400000000000000355e+00 -1.438583769617946587e-05 -9.249776627676899564e-06 -6.691041578929334717e-06 +9.500000000000000000e+00 -1.348264736372320039e-05 -8.671601022702781346e-06 -6.274283533910064576e-06 +9.599999999999999645e+00 -1.264498735578012246e-05 -8.135183958678718279e-06 -5.887514641681122086e-06 +9.700000000000001066e+00 -1.186747936398473687e-05 -7.637113677130612127e-06 -5.528293849956352819e-06 +9.800000000000000711e+00 -1.114523618469756001e-05 -7.174288601187318493e-06 -5.194401230658985063e-06 +9.900000000000000355e+00 -1.047381249252528874e-05 -6.743886368019750717e-06 -4.883815978498405921e-06 +1.000000000000000000e+01 0.000000000000000e00e+00 0.000000000000000e00e+00 0.000000000000000e00e+00 diff --git a/examples/water/d3/input.json b/examples/water/d3/input.json new file mode 100644 index 0000000000..bbe7a2c8a9 --- /dev/null +++ b/examples/water/d3/input.json @@ -0,0 +1,95 @@ +{ + "_comment1": " model parameters", + "model": { + "type": "linear_ener", + "weights": "sum", + "models": [ + { + "type_map": [ + "O", + "H" + ], + "descriptor": { + "type": "se_e2_a", + "sel": [ + 46, + 92 + ], + "rcut_smth": 0.50, + "rcut": 6.00, + "neuron": [ + 25, + 50, + 100 + ], + "resnet_dt": false, + "axis_neuron": 16, + "precision": "float64", + "seed": 1, + "_comment2": " that's all" + }, + "fitting_net": { + "neuron": [ + 240, + 240, + 240 + ], + "resnet_dt": true, + "precision": "float64", + "seed": 1, + "_comment3": " that's all" + }, + "_comment4": " that's all" + }, + { + "type": "pairtab", + "tab_file": "dftd3.txt", + "rcut": 10.0, + "sel": 534 + } + ] + }, + "learning_rate": { + "type": "exp", + "decay_steps": 5000, + "start_lr": 0.001, + "stop_lr": 3.51e-8, + "_comment5": "that's all" + }, + "loss": { + "type": "ener", + "start_pref_e": 0.02, + "limit_pref_e": 1, + "start_pref_f": 1000, + "limit_pref_f": 1, + "start_pref_v": 0, + "limit_pref_v": 0, + "_comment6": " that's all" + }, + "training": { + "training_data": { + "systems": [ + "../data/data_0/", + "../data/data_1/", + "../data/data_2/" + ], + "batch_size": "auto", + "_comment7": "that's all" + }, + "validation_data": { + "systems": [ + "../data/data_3" + ], + "batch_size": 1, + "numb_btch": 3, + "_comment8": "that's all" + }, + "numb_steps": 1000000, + "seed": 10, + "disp_file": "lcurve.out", + "disp_freq": 100, + "save_freq": 1000, + "_comment9": "that's all" + }, + "_comment10": "that's all" +} diff --git a/source/tests/test_model_pairtab.py b/source/tests/test_model_pairtab.py new file mode 100644 index 0000000000..fd678894b5 --- /dev/null +++ b/source/tests/test_model_pairtab.py @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +import numpy as np +import scipy.spatial.distance +from common import ( + DataSystem, + gen_data, + j_loader, +) + +from deepmd.common import ( + j_must_have, +) +from deepmd.env import ( + tf, +) +from deepmd.model.model import ( + Model, +) + +GLOBAL_ENER_FLOAT_PRECISION = tf.float64 +GLOBAL_TF_FLOAT_PRECISION = tf.float64 +GLOBAL_NP_FLOAT_PRECISION = np.float64 + + +class TestModel(tf.test.TestCase): + def setUp(self): + gen_data() + + def test_model(self): + jfile = "water.json" + jdata = j_loader(jfile) + systems = j_must_have(jdata, "systems") + set_pfx = j_must_have(jdata, "set_prefix") + batch_size = 1 + test_size = 1 + + tab_filename = "test_pairtab_tab.txt" + jdata["model"] = { + "type": "pairtab", + "tab_file": tab_filename, + "rcut": 6, + "sel": [6], + } + rcut = j_must_have(jdata["model"], "rcut") + + def pair_pot(r: float): + # LJ, as exmaple + return 4 * (1 / r**12 - 1 / r**6) + + dx = 1e-4 + d = np.arange(dx, rcut + dx, dx) + tab = np.array( + [ + d, + pair_pot(d), + pair_pot(d), + pair_pot(d), + ] + ).T + np.savetxt(tab_filename, tab) + + data = DataSystem(systems, set_pfx, batch_size, test_size, rcut, run_opt=None) + + test_data = data.get_test() + numb_test = 1 + + model = Model( + **jdata["model"], + ) + + t_prop_c = tf.placeholder(tf.float32, [5], name="t_prop_c") + t_energy = tf.placeholder(GLOBAL_ENER_FLOAT_PRECISION, [None], name="t_energy") + t_force = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name="t_force") + t_virial = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name="t_virial") + t_atom_ener = tf.placeholder( + GLOBAL_TF_FLOAT_PRECISION, [None], name="t_atom_ener" + ) + t_coord = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None], name="i_coord") + t_type = tf.placeholder(tf.int32, [None], name="i_type") + t_natoms = tf.placeholder(tf.int32, [model.ntypes + 2], name="i_natoms") + t_box = tf.placeholder(GLOBAL_TF_FLOAT_PRECISION, [None, 9], name="i_box") + t_mesh = tf.placeholder(tf.int32, [None], name="i_mesh") + is_training = tf.placeholder(tf.bool) + t_fparam = None + + model_pred = model.build( + t_coord, + t_type, + t_natoms, + t_box, + t_mesh, + t_fparam, + suffix="test_pairtab", + reuse=False, + ) + energy = model_pred["energy"] + force = model_pred["force"] + virial = model_pred["virial"] + + feed_dict_test = { + t_prop_c: test_data["prop_c"], + t_energy: test_data["energy"][:numb_test], + t_force: np.reshape(test_data["force"][:numb_test, :], [-1]), + t_virial: np.reshape(test_data["virial"][:numb_test, :], [-1]), + t_atom_ener: np.reshape(test_data["atom_ener"][:numb_test, :], [-1]), + t_coord: np.reshape(test_data["coord"][:numb_test, :], [-1]), + t_box: test_data["box"][:numb_test, :], + t_type: np.reshape(test_data["type"][:numb_test, :], [-1]), + t_natoms: test_data["natoms_vec"], + t_mesh: [], # nopbc + is_training: False, + } + + with self.cached_session() as sess: + sess.run(tf.global_variables_initializer()) + [e, _, _] = sess.run([energy, force, virial], feed_dict=feed_dict_test) + + e = e.reshape([-1]) + + coord = test_data["coord"][0, :].reshape(-1, 3) + distance = scipy.spatial.distance.cdist(coord, coord).ravel() + refe = [np.sum(pair_pot(distance[np.nonzero(distance)])) / 2] + + refe = np.reshape(refe, [-1]) + + places = 10 + np.testing.assert_almost_equal(e, refe, places) From 674ea1784dc162fb301fadc3e43d448b806003ff Mon Sep 17 00:00:00 2001 From: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> Date: Fri, 5 Jan 2024 09:41:42 +0800 Subject: [PATCH 61/97] rm rcut from DeepmdDataSystem (#3106) Co-authored-by: Han Wang --- deepmd/utils/data_system.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deepmd/utils/data_system.py b/deepmd/utils/data_system.py index bf05b5faa7..65cfdc053f 100644 --- a/deepmd/utils/data_system.py +++ b/deepmd/utils/data_system.py @@ -37,7 +37,7 @@ def __init__( systems: List[str], batch_size: int, test_size: int, - rcut: float, + rcut: Optional[float] = None, set_prefix: str = "set", shuffle_test: bool = True, type_map: Optional[List[str]] = None, @@ -59,7 +59,7 @@ def __init__( test_size The size of test data rcut - The cut-off radius + The cut-off radius. Not used. set_prefix Prefix for the directories of different sets shuffle_test @@ -91,7 +91,7 @@ def __init__( descriptors except mixed types. """ # init data - self.rcut = rcut + del rcut self.system_dirs = systems self.nsystems = len(self.system_dirs) self.data_systems = [] From 61ee4f22770d737b50db6e6f1631aada410aac27 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Fri, 5 Jan 2024 00:15:39 -0500 Subject: [PATCH 62/97] fix segfault in ~Region (#3108) When debuging #3103, I notice a segfault in `~Region`, preventing the actual error message thrown. `_norm_copy_coord_gpu` replaces `boxt` and `rec_boxt` of `Region` with GPU pointers, runs `deepmd::copy_coord_gpu`, and finnally recover the original pointer that can be deleted. However, `deepmd::copy_coord_gpu` might throw CUDA errors for any reason, and the pointers are not recovered. `~Region` tries to delete a pointer that it doesn't own, causing the segfault. The CUDA error message is not visible due to segfault. The segfault in #2895 may be also caused by it. This PR adds a new constructor to `Region` to accept the external pointers. `~Region` will delete `boxt` and`rec_boxt` only when the pointer is not external. We still need to figure out the reason for the error of `copy_coord_gpu` behind the segfault. --------- Signed-off-by: Jinzhe Zeng --- source/lib/include/region.h | 4 ++ source/lib/src/region.cc | 14 +++++- source/lib/tests/test_coord.cc | 56 +++------------------- source/lib/tests/test_simulation_region.cc | 8 +--- source/op/prod_env_mat_multi_device.cc | 8 +--- source/tests/test_auto_batch_size.py | 4 +- 6 files changed, 28 insertions(+), 66 deletions(-) diff --git a/source/lib/include/region.h b/source/lib/include/region.h index 2f6dbbf4e0..ee11b5b8ac 100644 --- a/source/lib/include/region.h +++ b/source/lib/include/region.h @@ -8,7 +8,11 @@ struct Region { FPTYPE* boxt; FPTYPE* rec_boxt; Region(); + Region(FPTYPE* extern_boxt, FPTYPE* extern_rec_boxt); ~Region(); + + private: + bool self_allocated; }; template diff --git a/source/lib/src/region.cc b/source/lib/src/region.cc index 36a739d90a..6c5f5493e6 100644 --- a/source/lib/src/region.cc +++ b/source/lib/src/region.cc @@ -14,12 +14,22 @@ template Region::Region() { boxt = new FPTYPE[BOXT_DIM]; rec_boxt = new FPTYPE[BOXT_DIM]; + self_allocated = true; +} + +template +Region::Region(FPTYPE* extern_boxt, FPTYPE* extern_rec_boxt) { + boxt = extern_boxt; + rec_boxt = extern_rec_boxt; + self_allocated = false; } template Region::~Region() { - delete[] boxt; - delete[] rec_boxt; + if (self_allocated) { + delete[] boxt; + delete[] rec_boxt; + } } template struct deepmd::Region; diff --git a/source/lib/tests/test_coord.cc b/source/lib/tests/test_coord.cc index af320ca3f7..c939dd6fa6 100644 --- a/source/lib/tests/test_coord.cc +++ b/source/lib/tests/test_coord.cc @@ -62,9 +62,6 @@ TEST_F(TestNormCoord, cpu_case2) { #if GOOGLE_CUDA || TENSORFLOW_USE_ROCM TEST_F(TestNormCoord, gpu_case0) { deepmd::Region region; - deepmd::Region region_dev; - double* new_boxt = region_dev.boxt; - double* new_rec_boxt = region_dev.rec_boxt; init_region_cpu(region, &boxt[0]); std::vector box_info; box_info.resize(18); @@ -75,11 +72,8 @@ TEST_F(TestNormCoord, gpu_case0) { std::vector out_c(r0); deepmd::malloc_device_memory_sync(box_info_dev, box_info); deepmd::malloc_device_memory_sync(out_c_dev, out_c); - region_dev.boxt = box_info_dev; - region_dev.rec_boxt = box_info_dev + 9; + deepmd::Region region_dev(box_info_dev, box_info_dev + 9); deepmd::normalize_coord_gpu(out_c_dev, natoms, region_dev); - region_dev.boxt = new_boxt; - region_dev.rec_boxt = new_rec_boxt; deepmd::memcpy_device_to_host(out_c_dev, out_c); deepmd::delete_device_memory(box_info_dev); deepmd::delete_device_memory(out_c_dev); @@ -90,9 +84,6 @@ TEST_F(TestNormCoord, gpu_case0) { TEST_F(TestNormCoord, gpu_case1) { deepmd::Region region; - deepmd::Region region_dev; - double* new_boxt = region_dev.boxt; - double* new_rec_boxt = region_dev.rec_boxt; init_region_cpu(region, &boxt[0]); std::vector box_info; box_info.resize(18); @@ -103,11 +94,8 @@ TEST_F(TestNormCoord, gpu_case1) { std::vector out_c(r1); deepmd::malloc_device_memory_sync(box_info_dev, box_info); deepmd::malloc_device_memory_sync(out_c_dev, out_c); - region_dev.boxt = box_info_dev; - region_dev.rec_boxt = box_info_dev + 9; + deepmd::Region region_dev(box_info_dev, box_info_dev + 9); deepmd::normalize_coord_gpu(out_c_dev, natoms, region_dev); - region_dev.boxt = new_boxt; - region_dev.rec_boxt = new_rec_boxt; deepmd::memcpy_device_to_host(out_c_dev, out_c); deepmd::delete_device_memory(box_info_dev); deepmd::delete_device_memory(out_c_dev); @@ -118,9 +106,6 @@ TEST_F(TestNormCoord, gpu_case1) { TEST_F(TestNormCoord, gpu_case2) { deepmd::Region region; - deepmd::Region region_dev; - double* new_boxt = region_dev.boxt; - double* new_rec_boxt = region_dev.rec_boxt; init_region_cpu(region, &boxt[0]); std::vector box_info; box_info.resize(18); @@ -131,11 +116,8 @@ TEST_F(TestNormCoord, gpu_case2) { std::vector out_c(r2); deepmd::malloc_device_memory_sync(box_info_dev, box_info); deepmd::malloc_device_memory_sync(out_c_dev, out_c); - region_dev.boxt = box_info_dev; - region_dev.rec_boxt = box_info_dev + 9; + deepmd::Region region_dev(box_info_dev, box_info_dev + 9); deepmd::normalize_coord_gpu(out_c_dev, natoms, region_dev); - region_dev.boxt = new_boxt; - region_dev.rec_boxt = new_rec_boxt; deepmd::memcpy_device_to_host(out_c_dev, out_c); deepmd::delete_device_memory(box_info_dev); deepmd::delete_device_memory(out_c_dev); @@ -298,9 +280,6 @@ TEST_F(TestCopyCoord, gpu) { std::vector cell_info; cell_info.resize(23); deepmd::Region region; - deepmd::Region region_dev; - double* new_boxt = region_dev.boxt; - double* new_rec_boxt = region_dev.rec_boxt; init_region_cpu(region, &boxt[0]); deepmd::compute_cell_info(&cell_info[0], rc, region); std::vector box_info; @@ -325,14 +304,11 @@ TEST_F(TestCopyCoord, gpu) { int_data_dev, nloc * 3 + loc_cellnum + total_cellnum * 3 + total_cellnum * 3 + loc_cellnum + 1 + total_cellnum + 1 + nloc); - region_dev.boxt = box_info_dev; - region_dev.rec_boxt = box_info_dev + 9; + deepmd::Region region_dev(box_info_dev, box_info_dev + 9); int ret = deepmd::copy_coord_gpu(out_c_dev, out_t_dev, mapping_dev, &nall, int_data_dev, in_c_dev, in_t_dev, nloc, mem_size, loc_cellnum, total_cellnum, cell_info_dev, region_dev); - region_dev.boxt = new_boxt; - region_dev.rec_boxt = new_rec_boxt; deepmd::memcpy_device_to_host(out_c_dev, out_c); deepmd::memcpy_device_to_host(out_t_dev, out_t); deepmd::memcpy_device_to_host(mapping_dev, mapping); @@ -373,9 +349,6 @@ TEST_F(TestCopyCoord, gpu_lessmem) { std::vector cell_info; cell_info.resize(23); deepmd::Region region; - deepmd::Region region_dev; - double* new_boxt = region_dev.boxt; - double* new_rec_boxt = region_dev.rec_boxt; init_region_cpu(region, &boxt[0]); deepmd::compute_cell_info(&cell_info[0], rc, region); std::vector box_info; @@ -400,14 +373,11 @@ TEST_F(TestCopyCoord, gpu_lessmem) { int_data_dev, nloc * 3 + loc_cellnum + total_cellnum * 3 + total_cellnum * 3 + loc_cellnum + 1 + total_cellnum + 1 + nloc); - region_dev.boxt = box_info_dev; - region_dev.rec_boxt = box_info_dev + 9; + deepmd::Region region_dev(box_info_dev, box_info_dev + 9); int ret = deepmd::copy_coord_gpu(out_c_dev, out_t_dev, mapping_dev, &nall, int_data_dev, in_c_dev, in_t_dev, nloc, mem_size, loc_cellnum, total_cellnum, cell_info_dev, region_dev); - region_dev.boxt = new_boxt; - region_dev.rec_boxt = new_rec_boxt; deepmd::memcpy_device_to_host(out_c_dev, out_c); deepmd::memcpy_device_to_host(out_t_dev, out_t); deepmd::memcpy_device_to_host(mapping_dev, mapping); @@ -544,9 +514,6 @@ TEST_F(TestCopyCoordMoreCell, gpu) { std::vector cell_info; cell_info.resize(23); deepmd::Region region; - deepmd::Region region_dev; - double* new_boxt = region_dev.boxt; - double* new_rec_boxt = region_dev.rec_boxt; init_region_cpu(region, &boxt[0]); deepmd::compute_cell_info(&cell_info[0], rc, region); std::vector box_info; @@ -571,14 +538,11 @@ TEST_F(TestCopyCoordMoreCell, gpu) { int_data_dev, nloc * 3 + loc_cellnum + total_cellnum * 3 + total_cellnum * 3 + loc_cellnum + 1 + total_cellnum + 1 + nloc); - region_dev.boxt = box_info_dev; - region_dev.rec_boxt = box_info_dev + 9; + deepmd::Region region_dev(box_info_dev, box_info_dev + 9); int ret = deepmd::copy_coord_gpu(out_c_dev, out_t_dev, mapping_dev, &nall, int_data_dev, in_c_dev, in_t_dev, nloc, mem_size, loc_cellnum, total_cellnum, cell_info_dev, region_dev); - region_dev.boxt = new_boxt; - region_dev.rec_boxt = new_rec_boxt; deepmd::memcpy_device_to_host(out_c_dev, out_c); deepmd::memcpy_device_to_host(out_t_dev, out_t); deepmd::memcpy_device_to_host(mapping_dev, mapping); @@ -619,9 +583,6 @@ TEST_F(TestCopyCoordMoreCell, gpu_lessmem) { std::vector cell_info; cell_info.resize(23); deepmd::Region region; - deepmd::Region region_dev; - double* new_boxt = region_dev.boxt; - double* new_rec_boxt = region_dev.rec_boxt; init_region_cpu(region, &boxt[0]); deepmd::compute_cell_info(&cell_info[0], rc, region); std::vector box_info; @@ -646,14 +607,11 @@ TEST_F(TestCopyCoordMoreCell, gpu_lessmem) { int_data_dev, nloc * 3 + loc_cellnum + total_cellnum * 3 + total_cellnum * 3 + loc_cellnum + 1 + total_cellnum + 1 + nloc); - region_dev.boxt = box_info_dev; - region_dev.rec_boxt = box_info_dev + 9; + deepmd::Region region_dev(box_info_dev, box_info_dev + 9); int ret = deepmd::copy_coord_gpu(out_c_dev, out_t_dev, mapping_dev, &nall, int_data_dev, in_c_dev, in_t_dev, nloc, mem_size, loc_cellnum, total_cellnum, cell_info_dev, region_dev); - region_dev.boxt = new_boxt; - region_dev.rec_boxt = new_rec_boxt; deepmd::memcpy_device_to_host(out_c_dev, out_c); deepmd::memcpy_device_to_host(out_t_dev, out_t); deepmd::memcpy_device_to_host(mapping_dev, mapping); diff --git a/source/lib/tests/test_simulation_region.cc b/source/lib/tests/test_simulation_region.cc index 98da9ec350..5f64d3f531 100644 --- a/source/lib/tests/test_simulation_region.cc +++ b/source/lib/tests/test_simulation_region.cc @@ -77,9 +77,6 @@ TEST_F(TestRegion, cpu) { TEST_F(TestRegion, gpu) { // check rec_box deepmd::Region region; - deepmd::Region region_dev; - double* new_boxt = region_dev.boxt; - double* new_rec_boxt = region_dev.rec_boxt; double *boxt_dev = NULL, *rec_boxt_dev = NULL; double *ref_rp_dev = NULL, *ref_ri_dev = NULL; init_region_cpu(region, &ref_boxt[0]); @@ -90,8 +87,7 @@ TEST_F(TestRegion, gpu) { deepmd::malloc_device_memory_sync(rec_boxt_dev, region.rec_boxt, 9); deepmd::malloc_device_memory_sync(ref_rp_dev, ref_rp); deepmd::malloc_device_memory_sync(ref_ri_dev, ref_ri); - region_dev.boxt = boxt_dev; - region_dev.rec_boxt = rec_boxt_dev; + deepmd::Region region_dev(boxt_dev, rec_boxt_dev); // check volume double vol[1]; double* vol_dev = NULL; @@ -141,8 +137,6 @@ TEST_F(TestRegion, gpu) { deepmd::delete_device_memory(rp2_dev); deepmd::delete_device_memory(rp_dev); deepmd::delete_device_memory(ri2_dev); - region_dev.boxt = new_boxt; - region_dev.rec_boxt = new_rec_boxt; } #endif // GOOGLE_CUDA || TENSORFLOW_USE_ROCM diff --git a/source/op/prod_env_mat_multi_device.cc b/source/op/prod_env_mat_multi_device.cc index 048237e042..22654b5f3a 100644 --- a/source/op/prod_env_mat_multi_device.cc +++ b/source/op/prod_env_mat_multi_device.cc @@ -1496,11 +1496,7 @@ static int _norm_copy_coord_gpu(OpKernelContext* context, int* int_data_dev = cell_info_dev + 23; deepmd::memcpy_host_to_device(box_info_dev, box_info, 18); deepmd::memcpy_host_to_device(cell_info_dev, cell_info, 23); - deepmd::Region region_dev; - FPTYPE* new_boxt = region_dev.boxt; - FPTYPE* new_rec_boxt = region_dev.rec_boxt; - region_dev.boxt = box_info_dev; - region_dev.rec_boxt = box_info_dev + 9; + deepmd::Region region_dev(box_info_dev, box_info_dev + 9); deepmd::normalize_coord_gpu(tmp_coord, nall, region_dev); int tt; for (tt = 0; tt < max_cpy_trial; ++tt) { @@ -1531,8 +1527,6 @@ static int _norm_copy_coord_gpu(OpKernelContext* context, } } } - region_dev.boxt = new_boxt; - region_dev.rec_boxt = new_rec_boxt; return (tt != max_cpy_trial); } diff --git a/source/tests/test_auto_batch_size.py b/source/tests/test_auto_batch_size.py index 93a96c9c29..5a349f70b9 100644 --- a/source/tests/test_auto_batch_size.py +++ b/source/tests/test_auto_batch_size.py @@ -45,8 +45,10 @@ def test_execute_oom_gpu(self, mock_is_gpu_available): self.assertEqual(result.shape, (256, 2)) @unittest.mock.patch("tensorflow.compat.v1.test.is_gpu_available") - def test_execute_oom_cpu(self, mock_is_gpu_available): + @unittest.mock.patch("tensorflow.compat.v1.config.experimental.get_visible_devices") + def test_execute_oom_cpu(self, mock_is_gpu_available, mock_get_visible_devices): mock_is_gpu_available.return_value = False + mock_get_visible_devices.return_value = [] # initial batch size 256 = 128 * 2, nb is always 128 auto_batch_size = AutoBatchSize(256, 2.0) nb, result = auto_batch_size.execute(self.oom, 1, 2) From db22812de47f4300ccb2a3a6e14e40334bad9f63 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Fri, 5 Jan 2024 00:16:09 -0500 Subject: [PATCH 63/97] add activation_function and resnet arguments and NumPy implementation to NativeLayer (#3109) Signed-off-by: Jinzhe Zeng --- deepmd_utils/model_format.py | 94 +++++++++++++++++++++++-- source/tests/test_model_format_utils.py | 52 ++++++++++---- 2 files changed, 129 insertions(+), 17 deletions(-) diff --git a/deepmd_utils/model_format.py b/deepmd_utils/model_format.py index 68a6d4045b..0b67131c4d 100644 --- a/deepmd_utils/model_format.py +++ b/deepmd_utils/model_format.py @@ -4,6 +4,9 @@ See issue #2982 for more information. """ import json +from abc import ( + ABC, +) from typing import ( List, Optional, @@ -121,7 +124,15 @@ def load_dp_model(filename: str) -> dict: return model_dict -class NativeLayer: +class NativeOP(ABC): + """The unit operation of a native model.""" + + def call(self, *args, **kwargs): + """Forward pass in NumPy implementation.""" + raise NotImplementedError + + +class NativeLayer(NativeOP): """Native representation of a layer. Parameters @@ -132,6 +143,10 @@ class NativeLayer: The biases of the layer. idt : np.ndarray, optional The identity matrix of the layer. + activation_function : str, optional + The activation function of the layer. + resnet : bool, optional + Whether the layer is a residual layer. """ def __init__( @@ -139,10 +154,14 @@ def __init__( w: Optional[np.ndarray] = None, b: Optional[np.ndarray] = None, idt: Optional[np.ndarray] = None, + activation_function: Optional[str] = None, + resnet: bool = False, ) -> None: self.w = w self.b = b self.idt = idt + self.activation_function = activation_function + self.resnet = resnet def serialize(self) -> dict: """Serialize the layer to a dict. @@ -158,7 +177,11 @@ def serialize(self) -> dict: } if self.idt is not None: data["idt"] = self.idt - return data + return { + "activation_function": self.activation_function, + "resnet": self.resnet, + "@variables": data, + } @classmethod def deserialize(cls, data: dict) -> "NativeLayer": @@ -169,7 +192,13 @@ def deserialize(cls, data: dict) -> "NativeLayer": data : dict The dict to deserialize from. """ - return cls(data["w"], data["b"], data.get("idt", None)) + return cls( + w=data["@variables"]["w"], + b=data["@variables"]["b"], + idt=data.get("idt", None), + activation_function=data["activation_function"], + resnet=data.get("resnet", False), + ) def __setitem__(self, key, value): if key in ("w", "matrix"): @@ -178,6 +207,10 @@ def __setitem__(self, key, value): self.b = value elif key == "idt": self.idt = value + elif key == "activation_function": + self.activation_function = value + elif key == "resnet": + self.resnet = value else: raise KeyError(key) @@ -188,11 +221,47 @@ def __getitem__(self, key): return self.b elif key == "idt": return self.idt + elif key == "activation_function": + return self.activation_function + elif key == "resnet": + return self.resnet else: raise KeyError(key) + def call(self, x: np.ndarray) -> np.ndarray: + """Forward pass. + + Parameters + ---------- + x : np.ndarray + The input. + + Returns + ------- + np.ndarray + The output. + """ + if self.w is None or self.b is None or self.activation_function is None: + raise ValueError("w, b, and activation_function must be set") + if self.activation_function == "tanh": + fn = np.tanh + elif self.activation_function.lower() == "none": + + def fn(x): + return x + else: + raise NotImplementedError(self.activation_function) + y = fn(np.matmul(x, self.w) + self.b) + if self.idt is not None: + y *= self.idt + if self.resnet and self.w.shape[1] == self.w.shape[0]: + y += x + elif self.resnet and self.w.shape[1] == 2 * self.w.shape[0]: + y += np.concatenate([x, x], axis=1) + return y + -class NativeNet: +class NativeNet(NativeOP): """Native representation of a neural network. Parameters @@ -238,3 +307,20 @@ def __setitem__(self, key, value): if len(self.layers) <= key: self.layers.extend([NativeLayer()] * (key - len(self.layers) + 1)) self.layers[key] = value + + def call(self, x: np.ndarray) -> np.ndarray: + """Forward pass. + + Parameters + ---------- + x : np.ndarray + The input. + + Returns + ------- + np.ndarray + The output. + """ + for layer in self.layers: + x = layer.call(x) + return x diff --git a/source/tests/test_model_format_utils.py b/source/tests/test_model_format_utils.py index b959ace3f6..3b2aa5d8d4 100644 --- a/source/tests/test_model_format_utils.py +++ b/source/tests/test_model_format_utils.py @@ -25,25 +25,45 @@ def test_serialize(self): network[1]["b"] = self.b network[0]["w"] = self.w network[0]["b"] = self.b + network[1]["activation_function"] = "tanh" + network[0]["activation_function"] = "tanh" + network[1]["resnet"] = True + network[0]["resnet"] = True jdata = network.serialize() - np.testing.assert_array_equal(jdata["layers"][0]["w"], self.w) - np.testing.assert_array_equal(jdata["layers"][0]["b"], self.b) - np.testing.assert_array_equal(jdata["layers"][1]["w"], self.w) - np.testing.assert_array_equal(jdata["layers"][1]["b"], self.b) + np.testing.assert_array_equal(jdata["layers"][0]["@variables"]["w"], self.w) + np.testing.assert_array_equal(jdata["layers"][0]["@variables"]["b"], self.b) + np.testing.assert_array_equal(jdata["layers"][1]["@variables"]["w"], self.w) + np.testing.assert_array_equal(jdata["layers"][1]["@variables"]["b"], self.b) + np.testing.assert_array_equal(jdata["layers"][0]["activation_function"], "tanh") + np.testing.assert_array_equal(jdata["layers"][1]["activation_function"], "tanh") + np.testing.assert_array_equal(jdata["layers"][0]["resnet"], True) + np.testing.assert_array_equal(jdata["layers"][1]["resnet"], True) def test_deserialize(self): network = NativeNet.deserialize( { "layers": [ - {"w": self.w, "b": self.b}, - {"w": self.w, "b": self.b}, - ] + { + "activation_function": "tanh", + "resnet": True, + "@variables": {"w": self.w, "b": self.b}, + }, + { + "activation_function": "tanh", + "resnet": True, + "@variables": {"w": self.w, "b": self.b}, + }, + ], } ) np.testing.assert_array_equal(network[0]["w"], self.w) np.testing.assert_array_equal(network[0]["b"], self.b) np.testing.assert_array_equal(network[1]["w"], self.w) np.testing.assert_array_equal(network[1]["b"], self.b) + np.testing.assert_array_equal(network[0]["activation_function"], "tanh") + np.testing.assert_array_equal(network[1]["activation_function"], "tanh") + np.testing.assert_array_equal(network[0]["resnet"], True) + np.testing.assert_array_equal(network[1]["resnet"], True) class TestDPModel(unittest.TestCase): @@ -52,12 +72,18 @@ def setUp(self) -> None: self.b = np.full((3,), 4.0) self.model_dict = { "type": "some_type", - "@variables": { - "layers": [ - {"w": self.w, "b": self.b}, - {"w": self.w, "b": self.b}, - ] - }, + "layers": [ + { + "activation_function": "tanh", + "resnet": True, + "@variables": {"w": self.w, "b": self.b}, + }, + { + "activation_function": "tanh", + "resnet": True, + "@variables": {"w": self.w, "b": self.b}, + }, + ], } self.filename = "test_dp_model_format.dp" From c4b7baae636c1d0bf263403126f8dd58fbdadd61 Mon Sep 17 00:00:00 2001 From: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> Date: Fri, 5 Jan 2024 16:52:01 +0800 Subject: [PATCH 64/97] NativeLayer: support None bias. (#3111) - fix bugs. - add UT for the `NativeLayer` --------- Co-authored-by: Han Wang Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- deepmd_utils/model_format.py | 13 +++++++++---- source/tests/test_model_format_utils.py | 21 ++++++++++++++++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/deepmd_utils/model_format.py b/deepmd_utils/model_format.py index 0b67131c4d..83e6ac11fc 100644 --- a/deepmd_utils/model_format.py +++ b/deepmd_utils/model_format.py @@ -194,8 +194,8 @@ def deserialize(cls, data: dict) -> "NativeLayer": """ return cls( w=data["@variables"]["w"], - b=data["@variables"]["b"], - idt=data.get("idt", None), + b=data["@variables"].get("b", None), + idt=data["@variables"].get("idt", None), activation_function=data["activation_function"], resnet=data.get("resnet", False), ) @@ -241,7 +241,7 @@ def call(self, x: np.ndarray) -> np.ndarray: np.ndarray The output. """ - if self.w is None or self.b is None or self.activation_function is None: + if self.w is None or self.activation_function is None: raise ValueError("w, b, and activation_function must be set") if self.activation_function == "tanh": fn = np.tanh @@ -251,7 +251,12 @@ def fn(x): return x else: raise NotImplementedError(self.activation_function) - y = fn(np.matmul(x, self.w) + self.b) + y = ( + np.matmul(x, self.w) + self.b + if self.b is not None + else np.matmul(x, self.w) + ) + y = fn(y) if self.idt is not None: y *= self.idt if self.resnet and self.w.shape[1] == self.w.shape[0]: diff --git a/source/tests/test_model_format_utils.py b/source/tests/test_model_format_utils.py index 3b2aa5d8d4..2fef4e1922 100644 --- a/source/tests/test_model_format_utils.py +++ b/source/tests/test_model_format_utils.py @@ -1,4 +1,5 @@ # SPDX-License-Identifier: LGPL-3.0-or-later +import itertools import os import unittest from copy import ( @@ -8,16 +9,34 @@ import numpy as np from deepmd_utils.model_format import ( + NativeLayer, NativeNet, load_dp_model, save_dp_model, ) +class TestNativeLayer(unittest.TestCase): + def setUp(self) -> None: + self.w = np.full((2, 3), 3.0) + self.b = np.full((3,), 4.0) + self.idt = np.full((3,), 5.0) + + def test_serialize_deserize(self): + for ww, bb, idt, activation_function, resnet in itertools.product( + [self.w], [self.b, None], [self.idt, None], ["tanh", "none"], [True, False] + ): + nl0 = NativeLayer(ww, bb, idt, activation_function, resnet) + nl1 = NativeLayer.deserialize(nl0.serialize()) + inp = np.arange(self.w.shape[0]) + np.testing.assert_allclose(nl0.call(inp), nl1.call(inp)) + + class TestNativeNet(unittest.TestCase): def setUp(self) -> None: - self.w = np.full((3, 2), 3.0) + self.w = np.full((2, 3), 3.0) self.b = np.full((3,), 4.0) + self.idt = np.full((3,), 5.0) def test_serialize(self): network = NativeNet() From 7b3c3c01af32391f673947bf94af831acff03c49 Mon Sep 17 00:00:00 2001 From: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> Date: Sat, 6 Jan 2024 07:46:43 +0800 Subject: [PATCH 65/97] fix native layer concat bug. (#3112) add UT testing all input and output shapes --------- Co-authored-by: Han Wang Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- deepmd_utils/model_format.py | 2 +- source/tests/test_model_format_utils.py | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/deepmd_utils/model_format.py b/deepmd_utils/model_format.py index 83e6ac11fc..131be93121 100644 --- a/deepmd_utils/model_format.py +++ b/deepmd_utils/model_format.py @@ -262,7 +262,7 @@ def fn(x): if self.resnet and self.w.shape[1] == self.w.shape[0]: y += x elif self.resnet and self.w.shape[1] == 2 * self.w.shape[0]: - y += np.concatenate([x, x], axis=1) + y += np.concatenate([x, x], axis=-1) return y diff --git a/source/tests/test_model_format_utils.py b/source/tests/test_model_format_utils.py index 2fef4e1922..af8c4361c8 100644 --- a/source/tests/test_model_format_utils.py +++ b/source/tests/test_model_format_utils.py @@ -17,18 +17,24 @@ class TestNativeLayer(unittest.TestCase): - def setUp(self) -> None: - self.w = np.full((2, 3), 3.0) - self.b = np.full((3,), 4.0) - self.idt = np.full((3,), 5.0) - def test_serialize_deserize(self): - for ww, bb, idt, activation_function, resnet in itertools.product( - [self.w], [self.b, None], [self.idt, None], ["tanh", "none"], [True, False] + for (ni, no), bias, ut, activation_function, resnet, ashp in itertools.product( + [(5, 5), (5, 10), (5, 9), (9, 5)], + [True, False], + [True, False], + ["tanh", "none"], + [True, False], + [None, [4], [3, 2]], ): + ww = np.full((ni, no), 3.0) + bb = np.full((no,), 4.0) if bias else None + idt = np.full((no,), 5.0) if ut else None nl0 = NativeLayer(ww, bb, idt, activation_function, resnet) nl1 = NativeLayer.deserialize(nl0.serialize()) - inp = np.arange(self.w.shape[0]) + inp_shap = [ww.shape[0]] + if ashp is not None: + inp_shap = ashp + inp_shap + inp = np.arange(np.prod(inp_shap)).reshape(inp_shap) np.testing.assert_allclose(nl0.call(inp), nl1.call(inp)) From f181a3084a04f8e797f5474e14015d46e597e98a Mon Sep 17 00:00:00 2001 From: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:45:39 +0800 Subject: [PATCH 66/97] model format for the embedding net (#3113) - refact the dir structure for the model_format - change the input of `NativeNet` from `List[NativeLayer]` to the `List[dict]` --------- Signed-off-by: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> Co-authored-by: Han Wang Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Jinzhe Zeng --- deepmd_utils/model_format/__init__.py | 18 +++++ .../network.py} | 66 ++++++++++++++++++- source/tests/test_model_format_utils.py | 12 ++++ 3 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 deepmd_utils/model_format/__init__.py rename deepmd_utils/{model_format.py => model_format/network.py} (81%) diff --git a/deepmd_utils/model_format/__init__.py b/deepmd_utils/model_format/__init__.py new file mode 100644 index 0000000000..4b33aa0151 --- /dev/null +++ b/deepmd_utils/model_format/__init__.py @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +from .network import ( + EmbeddingNet, + NativeLayer, + NativeNet, + load_dp_model, + save_dp_model, + traverse_model_dict, +) + +__all__ = [ + "EmbeddingNet", + "NativeLayer", + "NativeNet", + "load_dp_model", + "save_dp_model", + "traverse_model_dict", +] diff --git a/deepmd_utils/model_format.py b/deepmd_utils/model_format/network.py similarity index 81% rename from deepmd_utils/model_format.py rename to deepmd_utils/model_format/network.py index 131be93121..04aaa75534 100644 --- a/deepmd_utils/model_format.py +++ b/deepmd_utils/model_format/network.py @@ -275,10 +275,10 @@ class NativeNet(NativeOP): The layers of the network. """ - def __init__(self, layers: Optional[List[NativeLayer]] = None) -> None: + def __init__(self, layers: Optional[List[dict]] = None) -> None: if layers is None: layers = [] - self.layers = layers + self.layers = [NativeLayer.deserialize(layer) for layer in layers] def serialize(self) -> dict: """Serialize the network to a dict. @@ -299,7 +299,7 @@ def deserialize(cls, data: dict) -> "NativeNet": data : dict The dict to deserialize from. """ - return cls([NativeLayer.deserialize(layer) for layer in data["layers"]]) + return cls(data["layers"]) def __getitem__(self, key): assert isinstance(key, int) @@ -329,3 +329,63 @@ def call(self, x: np.ndarray) -> np.ndarray: for layer in self.layers: x = layer.call(x) return x + + +class EmbeddingNet(NativeNet): + def __init__( + self, + in_dim, + neuron: List[int] = [24, 48, 96], + activation_function: str = "tanh", + resnet_dt: bool = False, + ): + layers = [] + i_in = in_dim + rng = np.random.default_rng() + for idx, ii in enumerate(neuron): + i_ot = ii + layers.append( + NativeLayer( + rng.normal(size=(i_in, i_ot)), + b=rng.normal(size=(ii)), + idt=rng.normal(size=(ii)) if resnet_dt else None, + activation_function=activation_function, + resnet=True, + ).serialize() + ) + i_in = i_ot + super().__init__(layers) + self.in_dim = in_dim + self.neuron = neuron + self.activation_function = activation_function + self.resnet_dt = resnet_dt + + def serialize(self) -> dict: + """Serialize the network to a dict. + + Returns + ------- + dict + The serialized network. + """ + return { + "in_dim": self.in_dim, + "neuron": self.neuron.copy(), + "activation_function": self.activation_function, + "resnet_dt": self.resnet_dt, + "layers": [layer.serialize() for layer in self.layers], + } + + @classmethod + def deserialize(cls, data: dict) -> "EmbeddingNet": + """Deserialize the network from a dict. + + Parameters + ---------- + data : dict + The dict to deserialize from. + """ + layers = data.pop("layers") + obj = cls(**data) + super(EmbeddingNet, obj).__init__(layers) + return obj diff --git a/source/tests/test_model_format_utils.py b/source/tests/test_model_format_utils.py index af8c4361c8..f26ebbaa8d 100644 --- a/source/tests/test_model_format_utils.py +++ b/source/tests/test_model_format_utils.py @@ -9,6 +9,7 @@ import numpy as np from deepmd_utils.model_format import ( + EmbeddingNet, NativeLayer, NativeNet, load_dp_model, @@ -90,6 +91,17 @@ def test_deserialize(self): np.testing.assert_array_equal(network[0]["resnet"], True) np.testing.assert_array_equal(network[1]["resnet"], True) + def test_embedding_net(self): + for ni, idt, act in itertools.product( + [1, 10], + [True, False], + ["tanh", "none"], + ): + en0 = EmbeddingNet(ni) + en1 = EmbeddingNet.deserialize(en0.serialize()) + inp = np.ones([ni]) + np.testing.assert_allclose(en0.call(inp), en1.call(inp)) + class TestDPModel(unittest.TestCase): def setUp(self) -> None: From d1c00749f1a392466a5468ab36e23cd6b2c4588f Mon Sep 17 00:00:00 2001 From: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> Date: Tue, 9 Jan 2024 08:40:17 +0800 Subject: [PATCH 67/97] support numerical precision and env_mat (#3114) - change of numerical precision is supported - environment matrix is supported. --------- Co-authored-by: Han Wang Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- deepmd_utils/model_format/__init__.py | 8 ++ deepmd_utils/model_format/common.py | 24 +++++ deepmd_utils/model_format/env_mat.py | 129 ++++++++++++++++++++++++ deepmd_utils/model_format/network.py | 48 ++++++--- source/tests/test_model_format_utils.py | 53 +++++++++- 5 files changed, 246 insertions(+), 16 deletions(-) create mode 100644 deepmd_utils/model_format/common.py create mode 100644 deepmd_utils/model_format/env_mat.py diff --git a/deepmd_utils/model_format/__init__.py b/deepmd_utils/model_format/__init__.py index 4b33aa0151..533dd9ffff 100644 --- a/deepmd_utils/model_format/__init__.py +++ b/deepmd_utils/model_format/__init__.py @@ -1,4 +1,10 @@ # SPDX-License-Identifier: LGPL-3.0-or-later +from .common import ( + PRECISION_DICT, +) +from .env_mat import ( + EnvMat, +) from .network import ( EmbeddingNet, NativeLayer, @@ -9,10 +15,12 @@ ) __all__ = [ + "EnvMat", "EmbeddingNet", "NativeLayer", "NativeNet", "load_dp_model", "save_dp_model", "traverse_model_dict", + "PRECISION_DICT", ] diff --git a/deepmd_utils/model_format/common.py b/deepmd_utils/model_format/common.py new file mode 100644 index 0000000000..82beb969c2 --- /dev/null +++ b/deepmd_utils/model_format/common.py @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +from abc import ( + ABC, +) + +import numpy as np + +PRECISION_DICT = { + "float16": np.float16, + "float32": np.float32, + "float64": np.float64, + "half": np.float16, + "single": np.float32, + "double": np.float64, +} +DEFAULT_PRECISION = "float64" + + +class NativeOP(ABC): + """The unit operation of a native model.""" + + def call(self, *args, **kwargs): + """Forward pass in NumPy implementation.""" + raise NotImplementedError diff --git a/deepmd_utils/model_format/env_mat.py b/deepmd_utils/model_format/env_mat.py new file mode 100644 index 0000000000..84771135a6 --- /dev/null +++ b/deepmd_utils/model_format/env_mat.py @@ -0,0 +1,129 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +from typing import ( + Optional, + Union, +) + +import numpy as np + +from .common import ( + NativeOP, +) + + +def compute_smooth_weight( + distance: np.ndarray, + rmin: float, + rmax: float, +): + """Compute smooth weight for descriptor elements.""" + min_mask = distance <= rmin + max_mask = distance >= rmax + mid_mask = np.logical_not(np.logical_or(min_mask, max_mask)) + uu = (distance - rmin) / (rmax - rmin) + vv = uu * uu * uu * (-6.0 * uu * uu + 15.0 * uu - 10.0) + 1.0 + return vv * mid_mask + min_mask + + +def _make_env_mat( + nlist, + coord, + rcut: float, + ruct_smth: float, +): + """Make smooth environment matrix.""" + nf, nloc, nnei = nlist.shape + # nf x nall x 3 + coord = coord.reshape(nf, -1, 3) + mask = nlist >= 0 + nlist = nlist * mask + # nf x (nloc x nnei) x 3 + index = np.tile(nlist.reshape(nf, -1, 1), (1, 1, 3)) + coord_r = np.take_along_axis(coord, index, 1) + # nf x nloc x nnei x 3 + coord_r = coord_r.reshape(nf, nloc, nnei, 3) + # nf x nloc x 1 x 3 + coord_l = coord[:, :nloc].reshape(nf, -1, 1, 3) + # nf x nloc x nnei x 3 + diff = coord_r - coord_l + # nf x nloc x nnei + length = np.linalg.norm(diff, axis=-1, keepdims=True) + # for index 0 nloc atom + length = length + ~np.expand_dims(mask, -1) + t0 = 1 / length + t1 = diff / length**2 + weight = compute_smooth_weight(length, ruct_smth, rcut) + env_mat_se_a = np.concatenate([t0, t1], axis=-1) * weight * np.expand_dims(mask, -1) + return env_mat_se_a, diff * np.expand_dims(mask, -1), weight + + +class EnvMat(NativeOP): + def __init__( + self, + rcut, + rcut_smth, + ): + self.rcut = rcut + self.rcut_smth = rcut_smth + + def call( + self, + nlist: np.ndarray, + coord_ext: np.ndarray, + atype_ext: np.ndarray, + davg: Optional[np.ndarray] = None, + dstd: Optional[np.ndarray] = None, + ) -> Union[np.ndarray, np.ndarray]: + """Compute the environment matrix. + + Parameters + ---------- + nlist + The neighbor list. shape: nf x nloc x nnei + coord_ext + The extended coordinates of atoms. shape: nf x (nallx3) + atype_ext + The extended aotm types. shape: nf x nall + davg + The data avg. shape: nt x nnei x 4 + dstd + The inverse of data std. shape: nt x nnei x 4 + + Returns + ------- + env_mat + The environment matrix. shape: nf x nloc x nnei x 4 + switch + The value of switch function. shape: nf x nloc x nnei + """ + em, sw = self._call(nlist, coord_ext) + nf, nloc, nnei = nlist.shape + atype = atype_ext[:, :nloc] + if davg is not None: + em -= davg[atype] + if dstd is not None: + em /= dstd[atype] + return em, sw + + def _call( + self, + nlist, + coord_ext, + ): + em, diff, ww = _make_env_mat(nlist, coord_ext, self.rcut, self.rcut_smth) + return em, ww + + def serialize( + self, + ) -> dict: + return { + "rcut": self.rcut, + "rcut_smth": self.rcut_smth, + } + + @classmethod + def deserialize( + cls, + data: dict, + ) -> "EnvMat": + return cls(**data) diff --git a/deepmd_utils/model_format/network.py b/deepmd_utils/model_format/network.py index 04aaa75534..98c35636fa 100644 --- a/deepmd_utils/model_format/network.py +++ b/deepmd_utils/model_format/network.py @@ -4,9 +4,6 @@ See issue #2982 for more information. """ import json -from abc import ( - ABC, -) from typing import ( List, Optional, @@ -20,6 +17,12 @@ except ImportError: __version__ = "unknown" +from .common import ( + DEFAULT_PRECISION, + PRECISION_DICT, + NativeOP, +) + def traverse_model_dict(model_obj, callback: callable, is_variable: bool = False): """Traverse a model dict and call callback on each variable. @@ -124,14 +127,6 @@ def load_dp_model(filename: str) -> dict: return model_dict -class NativeOP(ABC): - """The unit operation of a native model.""" - - def call(self, *args, **kwargs): - """Forward pass in NumPy implementation.""" - raise NotImplementedError - - class NativeLayer(NativeOP): """Native representation of a layer. @@ -156,12 +151,16 @@ def __init__( idt: Optional[np.ndarray] = None, activation_function: Optional[str] = None, resnet: bool = False, + precision: str = DEFAULT_PRECISION, ) -> None: - self.w = w - self.b = b - self.idt = idt + prec = PRECISION_DICT[precision.lower()] + self.precision = precision + self.w = w.astype(prec) if w is not None else None + self.b = b.astype(prec) if b is not None else None + self.idt = idt.astype(prec) if idt is not None else None self.activation_function = activation_function self.resnet = resnet + self.check_type_consistency() def serialize(self) -> dict: """Serialize the layer to a dict. @@ -180,6 +179,7 @@ def serialize(self) -> dict: return { "activation_function": self.activation_function, "resnet": self.resnet, + "precision": self.precision, "@variables": data, } @@ -192,14 +192,28 @@ def deserialize(cls, data: dict) -> "NativeLayer": data : dict The dict to deserialize from. """ + precision = data.get("precision", DEFAULT_PRECISION) return cls( w=data["@variables"]["w"], b=data["@variables"].get("b", None), idt=data["@variables"].get("idt", None), activation_function=data["activation_function"], resnet=data.get("resnet", False), + precision=precision, ) + def check_type_consistency(self): + precision = self.precision + + def check_var(var): + if var is not None: + # assertion "float64" == "double" would fail + assert PRECISION_DICT[var.dtype.name] is PRECISION_DICT[precision] + + check_var(self.w) + check_var(self.b) + check_var(self.idt) + def __setitem__(self, key, value): if key in ("w", "matrix"): self.w = value @@ -211,6 +225,8 @@ def __setitem__(self, key, value): self.activation_function = value elif key == "resnet": self.resnet = value + elif key == "precision": + self.precision = value else: raise KeyError(key) @@ -225,6 +241,8 @@ def __getitem__(self, key): return self.activation_function elif key == "resnet": return self.resnet + elif key == "precision": + return self.precision else: raise KeyError(key) @@ -338,6 +356,7 @@ def __init__( neuron: List[int] = [24, 48, 96], activation_function: str = "tanh", resnet_dt: bool = False, + precision: str = DEFAULT_PRECISION, ): layers = [] i_in = in_dim @@ -351,6 +370,7 @@ def __init__( idt=rng.normal(size=(ii)) if resnet_dt else None, activation_function=activation_function, resnet=True, + precision=precision, ).serialize() ) i_in = i_ot diff --git a/source/tests/test_model_format_utils.py b/source/tests/test_model_format_utils.py index f26ebbaa8d..aeb717060d 100644 --- a/source/tests/test_model_format_utils.py +++ b/source/tests/test_model_format_utils.py @@ -10,6 +10,7 @@ from deepmd_utils.model_format import ( EmbeddingNet, + EnvMat, NativeLayer, NativeNet, load_dp_model, @@ -19,18 +20,22 @@ class TestNativeLayer(unittest.TestCase): def test_serialize_deserize(self): - for (ni, no), bias, ut, activation_function, resnet, ashp in itertools.product( + for ( + ni, + no, + ), bias, ut, activation_function, resnet, ashp, prec in itertools.product( [(5, 5), (5, 10), (5, 9), (9, 5)], [True, False], [True, False], ["tanh", "none"], [True, False], [None, [4], [3, 2]], + ["float32", "float64", "single", "double"], ): ww = np.full((ni, no), 3.0) bb = np.full((no,), 4.0) if bias else None idt = np.full((no,), 5.0) if ut else None - nl0 = NativeLayer(ww, bb, idt, activation_function, resnet) + nl0 = NativeLayer(ww, bb, idt, activation_function, resnet, prec) nl1 = NativeLayer.deserialize(nl0.serialize()) inp_shap = [ww.shape[0]] if ashp is not None: @@ -134,3 +139,47 @@ def test_save_load_model(self): def tearDown(self) -> None: if os.path.exists(self.filename): os.remove(self.filename) + + +class TestEnvMat(unittest.TestCase): + def setUp(self): + # nloc == 3, nall == 4 + self.nloc = 3 + self.nall = 4 + self.nf, self.nt = 1, 2 + self.coord_ext = np.array( + [ + [0, 0, 0], + [0, 1, 0], + [0, 0, 1], + [0, -2, 0], + ], + dtype=np.float64, + ).reshape([1, self.nall * 3]) + self.atype_ext = np.array([0, 0, 1, 0], dtype=int).reshape([1, self.nall]) + # sel = [5, 2] + self.nlist = np.array( + [ + [1, 3, -1, -1, -1, 2, -1], + [0, -1, -1, -1, -1, 2, -1], + [0, 1, -1, -1, -1, 0, -1], + ], + dtype=int, + ).reshape([1, self.nloc, 7]) + self.rcut = 0.4 + self.rcut_smth = 2.2 + + def test_self_consistency( + self, + ): + rng = np.random.default_rng() + nf, nloc, nnei = self.nlist.shape + davg = rng.normal(size=(self.nt, nnei, 4)) + dstd = rng.normal(size=(self.nt, nnei, 4)) + dstd = 0.1 + np.abs(dstd) + em0 = EnvMat(self.rcut, self.rcut_smth) + em1 = EnvMat.deserialize(em0.serialize()) + mm0, ww0 = em0.call(self.nlist, self.coord_ext, self.atype_ext, davg, dstd) + mm1, ww1 = em1.call(self.nlist, self.coord_ext, self.atype_ext, davg, dstd) + np.testing.assert_allclose(mm0, mm1) + np.testing.assert_allclose(ww0, ww1) From 25cdd1981a76aef357a0c219d5b5dc2db60d91eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 13:16:16 +0800 Subject: [PATCH 68/97] Bump docker/metadata-action from 5.4.0 to 5.5.0 (#3115) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 5.4.0 to 5.5.0.
Release notes

Sourced from docker/metadata-action's releases.

v5.5.0

Full Changelog: https://github.com/docker/metadata-action/compare/v5.4.0...v5.5.0

Commits
  • dbef880 Merge pull request #374 from docker/dependabot/npm_and_yarn/moment-timezone-0...
  • b73e7a7 chore: update generated content
  • b9fba69 chore(deps): Bump moment-timezone from 0.5.43 to 0.5.44
  • ac82374 Merge pull request #373 from docker/dependabot/npm_and_yarn/moment-2.30.1
  • c92519a chore: update generated content
  • 3b4179d chore(deps): Bump moment from 2.29.4 to 2.30.1
  • 0784993 Merge pull request #371 from docker/dependabot/npm_and_yarn/docker/actions-to...
  • 52c3e9e chore: update generated content
  • 82a5e67 chore(deps): Bump @​docker/actions-toolkit from 0.16.0 to 0.16.1
  • 41e1fe3 Merge pull request #370 from crazy-max/bake-cwd
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/metadata-action&package-manager=github_actions&previous-version=5.4.0&new-version=5.5.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_wheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index e47f14b1f4..23076e9bf5 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -144,7 +144,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@9dc751fe249ad99385a2583ee0d084c400eee04e + uses: docker/metadata-action@dbef88086f6cef02e264edb7dbf63250c17cef6c with: images: ghcr.io/deepmodeling/deepmd-kit From a971d928b0fe266913565dd51003fd876efc88a9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 13:17:25 +0800 Subject: [PATCH 69/97] [pre-commit.ci] pre-commit autoupdate (#3116) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.1.9 → v0.1.11](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.9...v0.1.11) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index efa2bc1675..5b6beb1dba 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,7 +30,7 @@ repos: exclude: ^source/3rdparty - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.9 + rev: v0.1.11 hooks: - id: ruff args: ["--fix"] From 438bc78fdb48004729fc5e76e5b1515600604d3d Mon Sep 17 00:00:00 2001 From: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> Date: Wed, 10 Jan 2024 10:00:47 +0800 Subject: [PATCH 70/97] Add dp model format sea (#3123) - add precision test for embedding net Limitations - only support `type_one_side` - does not support type embedding and `stripped_type_embedding` - does not support `exclude_types` - does not support spin --------- Co-authored-by: Han Wang --- deepmd_utils/model_format/__init__.py | 6 + deepmd_utils/model_format/network.py | 2 + deepmd_utils/model_format/se_e2_a.py | 195 ++++++++++++++++++++++++ source/tests/test_model_format_utils.py | 45 +++++- 4 files changed, 243 insertions(+), 5 deletions(-) create mode 100644 deepmd_utils/model_format/se_e2_a.py diff --git a/deepmd_utils/model_format/__init__.py b/deepmd_utils/model_format/__init__.py index 533dd9ffff..40769f187d 100644 --- a/deepmd_utils/model_format/__init__.py +++ b/deepmd_utils/model_format/__init__.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: LGPL-3.0-or-later from .common import ( + DEFAULT_PRECISION, PRECISION_DICT, ) from .env_mat import ( @@ -13,8 +14,12 @@ save_dp_model, traverse_model_dict, ) +from .se_e2_a import ( + DescrptSeA, +) __all__ = [ + "DescrptSeA", "EnvMat", "EmbeddingNet", "NativeLayer", @@ -23,4 +28,5 @@ "save_dp_model", "traverse_model_dict", "PRECISION_DICT", + "DEFAULT_PRECISION", ] diff --git a/deepmd_utils/model_format/network.py b/deepmd_utils/model_format/network.py index 98c35636fa..682a349476 100644 --- a/deepmd_utils/model_format/network.py +++ b/deepmd_utils/model_format/network.py @@ -379,6 +379,7 @@ def __init__( self.neuron = neuron self.activation_function = activation_function self.resnet_dt = resnet_dt + self.precision = precision def serialize(self) -> dict: """Serialize the network to a dict. @@ -393,6 +394,7 @@ def serialize(self) -> dict: "neuron": self.neuron.copy(), "activation_function": self.activation_function, "resnet_dt": self.resnet_dt, + "precision": self.precision, "layers": [layer.serialize() for layer in self.layers], } diff --git a/deepmd_utils/model_format/se_e2_a.py b/deepmd_utils/model_format/se_e2_a.py new file mode 100644 index 0000000000..114f9df915 --- /dev/null +++ b/deepmd_utils/model_format/se_e2_a.py @@ -0,0 +1,195 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later +import numpy as np + +try: + from deepmd_utils._version import version as __version__ +except ImportError: + __version__ = "unknown" + +from typing import ( + Any, + List, + Optional, +) + +from .common import ( + DEFAULT_PRECISION, + NativeOP, +) +from .env_mat import ( + EnvMat, +) +from .network import ( + EmbeddingNet, +) + + +class DescrptSeA(NativeOP): + def __init__( + self, + rcut: float, + rcut_smth: float, + sel: List[str], + neuron: List[int] = [24, 48, 96], + axis_neuron: int = 8, + resnet_dt: bool = False, + trainable: bool = True, + type_one_side: bool = True, + exclude_types: List[List[int]] = [], + set_davg_zero: bool = False, + activation_function: str = "tanh", + precision: str = DEFAULT_PRECISION, + spin: Optional[Any] = None, + stripped_type_embedding: bool = False, + ) -> None: + ## seed, uniform_seed, multi_task, not included. + if not type_one_side: + raise NotImplementedError("type_one_side == False not implemented") + if stripped_type_embedding: + raise NotImplementedError("stripped_type_embedding is not implemented") + if exclude_types != []: + raise NotImplementedError("exclude_types is not implemented") + if spin is not None: + raise NotImplementedError("spin is not implemented") + + self.rcut = rcut + self.rcut_smth = rcut_smth + self.sel = sel + self.ntypes = len(self.sel) + self.neuron = neuron + self.axis_neuron = axis_neuron + self.resnet_dt = resnet_dt + self.trainable = trainable + self.type_one_side = type_one_side + self.exclude_types = exclude_types + self.set_davg_zero = set_davg_zero + self.activation_function = activation_function + self.precision = precision + self.spin = spin + self.stripped_type_embedding = stripped_type_embedding + + in_dim = 1 # not considiering type embedding + self.embeddings = [] + for ii in range(self.ntypes): + self.embeddings.append( + EmbeddingNet( + in_dim, + self.neuron, + self.activation_function, + self.resnet_dt, + self.precision, + ) + ) + self.env_mat = EnvMat(self.rcut, self.rcut_smth) + self.nnei = np.sum(self.sel) + self.nneix4 = self.nnei * 4 + self.davg = np.zeros([self.ntypes, self.nneix4]) + self.dstd = np.ones([self.ntypes, self.nneix4]) + self.orig_sel = self.sel + + def __setitem__(self, key, value): + if key in ("avg", "data_avg", "davg"): + self.davg = value + elif key in ("std", "data_std", "dstd"): + self.dstd = value + else: + raise KeyError(key) + + def __getitem__(self, key): + if key in ("avg", "data_avg", "davg"): + return self.davg + elif key in ("std", "data_std", "dstd"): + return self.dstd + else: + raise KeyError(key) + + def cal_g( + self, + ss, + ll, + ): + nf, nloc, nnei = ss.shape[0:3] + ss = ss.reshape(nf, nloc, nnei, 1) + # nf x nloc x nnei x ng + gg = self.embeddings[ll].call(ss) + return gg + + def call( + self, + coord_ext, + atype_ext, + nlist, + ): + """Compute the environment matrix. + + Parameters + ---------- + coord_ext + The extended coordinates of atoms. shape: nf x (nallx3) + atype_ext + The extended aotm types. shape: nf x nall + nlist + The neighbor list. shape: nf x nloc x nnei + + Returns + ------- + descriptor + The descriptor. shape: nf x nloc x ng x axis_neuron + """ + # nf x nloc x nnei x 4 + rr, ww = self.env_mat.call(nlist, coord_ext, atype_ext, self.davg, self.dstd) + nf, nloc, nnei, _ = rr.shape + sec = np.append([0], np.cumsum(self.sel)) + + ng = self.neuron[-1] + gr = np.zeros([nf, nloc, ng, 4]) + for tt in range(self.ntypes): + tr = rr[:, :, sec[tt] : sec[tt + 1], :] + ss = tr[..., 0:1] + gg = self.cal_g(ss, tt) + # nf x nloc x ng x 4 + gr += np.einsum("flni,flnj->flij", gg, tr) + gr /= self.nnei + gr1 = gr[:, :, : self.axis_neuron, :] + # nf x nloc x ng x ng1 + grrg = np.einsum("flid,fljd->flij", gr, gr1) + # nf x nloc x (ng x ng1) + grrg = grrg.reshape(nf, nloc, ng * self.axis_neuron) + return grrg + + def serialize(self) -> dict: + return { + "rcut": self.rcut, + "rcut_smth": self.rcut_smth, + "sel": self.sel, + "neuron": self.neuron, + "axis_neuron": self.axis_neuron, + "resnet_dt": self.resnet_dt, + "trainable": self.trainable, + "type_one_side": self.type_one_side, + "exclude_types": self.exclude_types, + "set_davg_zero": self.set_davg_zero, + "activation_function": self.activation_function, + "precision": self.precision, + "spin": self.spin, + "stripped_type_embedding": self.stripped_type_embedding, + "env_mat": self.env_mat.serialize(), + "embeddings": [ii.serialize() for ii in self.embeddings], + "@variables": { + "davg": self.davg, + "dstd": self.dstd, + }, + } + + @classmethod + def deserialize(cls, data: dict) -> "DescrptSeA": + variables = data.pop("@variables") + embeddings = data.pop("embeddings") + env_mat = data.pop("env_mat") + obj = cls(**data) + + obj["davg"] = variables["davg"] + obj["dstd"] = variables["dstd"] + obj.embeddings = [EmbeddingNet.deserialize(dd) for dd in embeddings] + obj.env_mat = EnvMat.deserialize(env_mat) + return obj diff --git a/source/tests/test_model_format_utils.py b/source/tests/test_model_format_utils.py index aeb717060d..7fd93c1366 100644 --- a/source/tests/test_model_format_utils.py +++ b/source/tests/test_model_format_utils.py @@ -9,6 +9,7 @@ import numpy as np from deepmd_utils.model_format import ( + DescrptSeA, EmbeddingNet, EnvMat, NativeLayer, @@ -97,12 +98,18 @@ def test_deserialize(self): np.testing.assert_array_equal(network[1]["resnet"], True) def test_embedding_net(self): - for ni, idt, act in itertools.product( + for ni, act, idt, prec in itertools.product( [1, 10], - [True, False], ["tanh", "none"], + [True, False], + ["double", "single"], ): - en0 = EmbeddingNet(ni) + en0 = EmbeddingNet( + ni, + activation_function=act, + precision=prec, + resnet_dt=idt, + ) en1 = EmbeddingNet.deserialize(en0.serialize()) inp = np.ones([ni]) np.testing.assert_allclose(en0.call(inp), en1.call(inp)) @@ -141,7 +148,7 @@ def tearDown(self) -> None: os.remove(self.filename) -class TestEnvMat(unittest.TestCase): +class TestCaseSingleFrameWithNlist: def setUp(self): # nloc == 3, nall == 4 self.nloc = 3 @@ -158,6 +165,7 @@ def setUp(self): ).reshape([1, self.nall * 3]) self.atype_ext = np.array([0, 0, 1, 0], dtype=int).reshape([1, self.nall]) # sel = [5, 2] + self.sel = [5, 2] self.nlist = np.array( [ [1, 3, -1, -1, -1, 2, -1], @@ -165,10 +173,15 @@ def setUp(self): [0, 1, -1, -1, -1, 0, -1], ], dtype=int, - ).reshape([1, self.nloc, 7]) + ).reshape([1, self.nloc, sum(self.sel)]) self.rcut = 0.4 self.rcut_smth = 2.2 + +class TestEnvMat(unittest.TestCase, TestCaseSingleFrameWithNlist): + def setUp(self): + TestCaseSingleFrameWithNlist.setUp(self) + def test_self_consistency( self, ): @@ -183,3 +196,25 @@ def test_self_consistency( mm1, ww1 = em1.call(self.nlist, self.coord_ext, self.atype_ext, davg, dstd) np.testing.assert_allclose(mm0, mm1) np.testing.assert_allclose(ww0, ww1) + + +class TestDescrptSeA(unittest.TestCase, TestCaseSingleFrameWithNlist): + def setUp(self): + TestCaseSingleFrameWithNlist.setUp(self) + + def test_self_consistency( + self, + ): + rng = np.random.default_rng() + nf, nloc, nnei = self.nlist.shape + davg = rng.normal(size=(self.nt, nnei, 4)) + dstd = rng.normal(size=(self.nt, nnei, 4)) + dstd = 0.1 + np.abs(dstd) + + em0 = DescrptSeA(self.rcut, self.rcut_smth, self.sel) + em0.davg = davg + em0.dstd = dstd + em1 = DescrptSeA.deserialize(em0.serialize()) + mm0 = em0.call(self.coord_ext, self.atype_ext, self.nlist) + mm1 = em1.call(self.coord_ext, self.atype_ext, self.nlist) + np.testing.assert_allclose(mm0, mm1) From dac64cf9987d079db789e034ed0e75bddda0c6a5 Mon Sep 17 00:00:00 2001 From: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> Date: Wed, 10 Jan 2024 11:27:49 +0800 Subject: [PATCH 71/97] input order of env_mat changed to be consistent with descriptor (#3125) Co-authored-by: Han Wang --- deepmd_utils/model_format/env_mat.py | 2 +- deepmd_utils/model_format/se_e2_a.py | 2 +- source/tests/test_model_format_utils.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deepmd_utils/model_format/env_mat.py b/deepmd_utils/model_format/env_mat.py index 84771135a6..7822bd7d0c 100644 --- a/deepmd_utils/model_format/env_mat.py +++ b/deepmd_utils/model_format/env_mat.py @@ -68,9 +68,9 @@ def __init__( def call( self, - nlist: np.ndarray, coord_ext: np.ndarray, atype_ext: np.ndarray, + nlist: np.ndarray, davg: Optional[np.ndarray] = None, dstd: Optional[np.ndarray] = None, ) -> Union[np.ndarray, np.ndarray]: diff --git a/deepmd_utils/model_format/se_e2_a.py b/deepmd_utils/model_format/se_e2_a.py index 114f9df915..5a4fe15a2d 100644 --- a/deepmd_utils/model_format/se_e2_a.py +++ b/deepmd_utils/model_format/se_e2_a.py @@ -137,7 +137,7 @@ def call( The descriptor. shape: nf x nloc x ng x axis_neuron """ # nf x nloc x nnei x 4 - rr, ww = self.env_mat.call(nlist, coord_ext, atype_ext, self.davg, self.dstd) + rr, ww = self.env_mat.call(coord_ext, atype_ext, nlist, self.davg, self.dstd) nf, nloc, nnei, _ = rr.shape sec = np.append([0], np.cumsum(self.sel)) diff --git a/source/tests/test_model_format_utils.py b/source/tests/test_model_format_utils.py index 7fd93c1366..ac37120e83 100644 --- a/source/tests/test_model_format_utils.py +++ b/source/tests/test_model_format_utils.py @@ -192,8 +192,8 @@ def test_self_consistency( dstd = 0.1 + np.abs(dstd) em0 = EnvMat(self.rcut, self.rcut_smth) em1 = EnvMat.deserialize(em0.serialize()) - mm0, ww0 = em0.call(self.nlist, self.coord_ext, self.atype_ext, davg, dstd) - mm1, ww1 = em1.call(self.nlist, self.coord_ext, self.atype_ext, davg, dstd) + mm0, ww0 = em0.call(self.coord_ext, self.atype_ext, self.nlist, davg, dstd) + mm1, ww1 = em1.call(self.coord_ext, self.atype_ext, self.nlist, davg, dstd) np.testing.assert_allclose(mm0, mm1) np.testing.assert_allclose(ww0, ww1) From 398f037834e8f3b082edd8916218d16b9a5f8cec Mon Sep 17 00:00:00 2001 From: Han Wang <92130845+wanghan-iapcm@users.noreply.github.com> Date: Wed, 10 Jan 2024 11:28:19 +0800 Subject: [PATCH 72/97] doc string for dp model format descriptor se_e2_a (#3124) Co-authored-by: Han Wang --- deepmd_utils/model_format/se_e2_a.py | 96 ++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 6 deletions(-) diff --git a/deepmd_utils/model_format/se_e2_a.py b/deepmd_utils/model_format/se_e2_a.py index 5a4fe15a2d..624f30c122 100644 --- a/deepmd_utils/model_format/se_e2_a.py +++ b/deepmd_utils/model_format/se_e2_a.py @@ -25,6 +25,95 @@ class DescrptSeA(NativeOP): + r"""DeepPot-SE constructed from all information (both angular and radial) of + atomic configurations. The embedding takes the distance between atoms as input. + + The descriptor :math:`\mathcal{D}^i \in \mathcal{R}^{M_1 \times M_2}` is given by [1]_ + + .. math:: + \mathcal{D}^i = (\mathcal{G}^i)^T \mathcal{R}^i (\mathcal{R}^i)^T \mathcal{G}^i_< + + where :math:`\mathcal{R}^i \in \mathbb{R}^{N \times 4}` is the coordinate + matrix, and each row of :math:`\mathcal{R}^i` can be constructed as follows + + .. math:: + (\mathcal{R}^i)_j = [ + \begin{array}{c} + s(r_{ji}) & \frac{s(r_{ji})x_{ji}}{r_{ji}} & \frac{s(r_{ji})y_{ji}}{r_{ji}} & \frac{s(r_{ji})z_{ji}}{r_{ji}} + \end{array} + ] + + where :math:`\mathbf{R}_{ji}=\mathbf{R}_j-\mathbf{R}_i = (x_{ji}, y_{ji}, z_{ji})` is + the relative coordinate and :math:`r_{ji}=\lVert \mathbf{R}_{ji} \lVert` is its norm. + The switching function :math:`s(r)` is defined as: + + .. math:: + s(r)= + \begin{cases} + \frac{1}{r}, & r