Deep Potential Generator (DP-GEN) 是一个将神经网络势能(machine learning potential)和主动学习(active learing)结合起来的工作流。该包主要由张林峰(普林斯顿大学),王涵(北京应用物理与计算数学研究所)开发。如有问题,可以向他们询问。
考虑到 DP-GEN 在集群运行可能存在一定的性能问题,推荐尝试 ai 2 -kit 运行势函数训练的 Close Loop Learning (CLL) 任务。
以下为参考信息:
Warning
此页面仅限提供贡献者对于该软件的理解,如有任何问题请联系贡献者。建议在阅读此篇前先对DeePMD-kit有一定了解。
指路:
DeePMD-kit
DP-GEN的工作流是由以下三步组成的循环:
为了使dpgen运行起来,我们需要准备如下的文件:
param.json
三步计算中所用的参数,具体指神经网络训练的参数,lammps中MD的参数和DFTMD计算单点能的参数。
machine.json
制定上述三个步骤分别在哪个服务器计算。
在 Zeus 集群上配置
machine.json
`,请参阅
GPU使用说明
放在提交dpgen所在的服务器上,用于训练势函数,参照 DeePMD-kit 中方法生成。
放在提交dpgen所在的服务器上,必须使用vasp5.x的POSCAR,把.xyz文件转化为POSCAR的脚本可见 文末 。
在提交dpgen的文件夹下会出现以下输出文件,用于指示任务运行的状况:
dpgen.log
包括了运行轮数,单个任务提交的情况,采样准确度等详细的信息。
record.dpgen
由多行
x y
组成,记录任务进程。其中
x
为运行的轮数(iteration),从0开始;
y
取0-8,其中0-2指代训练,3-5指代采样和筛选,6-8指代标记。
dpgen通过读取这个文件来决定从哪里重启计算,所以我们可以通过手动修改这个文件来决定重启的点。例如,在第
x
轮中我们发现采样的准确度过低,需要增加初始结构的数量重新跑MD,我们就可以把
record.dpgen
文件在
x 2
之后的内容删除,重新提交dpgen任务。
nohup.out
这个并不是必要输出,但是建议使用
nohup命令
把dpgen挂在后台运行。这个文件中输出的信息和
dpgen.log
的基本一致。
接下来,把铂水界面势函数训练所用的
param.json
分解成几个部分进行解释,在实际使用中需要把几段放在一起。
comment
文件中的注释用_comment标注。
params.json
¶
{
"type_map": [
"O",
"H",
"mass_map": [
15.999,
1.0079,
195.08
"_comment": " atoms in your systems ",
"init_data_prefix": "/data/kmr/edl/pzc/hydroxide/ml_potential/pt-oh",
"init_data_sys": [
"init/system-000","init/system-001"
"_comment": " path of training set ",
"init_batch_size": [
1,1
"sys_configs": [
["/data/kmr/edl/pzc/hydroxide/ml_potential/pt-oh/init/configs/POSCAR_0[0-9]"],
["/data/kmr/edl/pzc/hydroxide/ml_potential/pt-oh/init/configs/POSCAR_1[0-9]"]
"_comment": " path of initial structure for sampling ",
"sys_batch_size": [
1,1
......
势函数训练(DPMD)
param.json {
......
"numb_models": 4,
"_comment": " number of NNP for model deviation ",
"train_param": "input.json",
"_comment": " name of automatically generated input file for DPMD ",
"default_training_param": {
"model": {
"descriptor": {
"type": "se_a",
"_comment": "could be bigger than the number of atoms of the very element",
"sel": [68, 136, 64],
"rcut_smth": 0.50,
"rcut": 5.00,
"neuron": [25, 50, 100],
"resnet_dt": false,
"axis_neuron": 16,
"seed": 1
"fitting_net": {
"n_neuron": [240, 240, 240],
"resnet_dt": true,
"seed": 1
"learning_rate": {
"type": "exp",
"start_lr": 0.005,
"decay_steps": 2000,
"_comment": "last 20000 or 400000",
"decay_rate": 0.95
"loss": {
"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
"training": {
"systems": [ ],
"set_prefix": "set",
"stop_batch": 400000,
"batch_size": 1,
"seed": 1,
"disp_file": "lcurve.out",
"disp_freq": 100,
"numb_test": 4,
"save_freq": 1000,
"save_ckpt": "model.ckpt",
"load_ckpt": "model.ckpt",
"disp_training": true,
"time_training": true,
"profiling": false,
"profiling_file": "timeline.json"
"_comment": "modify according your systems!",
......
采样和筛选(Lammps)
param.json{
"model_devi_dt": 0.0005,
"_comment": "model_devi_dt: Timesteps for MD. Consistent with DFTMD!",
"model_devi_skip": 0,
"_comment": "model_devi_skip: the first x frames of the recorded frames",
"model_devi_f_trust_lo": 0.075,
"model_devi_f_trust_hi": 0.10,
"_comment": "modify according to the error distribution of system",
"model_devi_e_trust_lo": 1e10,
"model_devi_e_trust_hi": 1e10,
"model_devi_clean_traj": false,
"model_devi_jobs": [
{"temps": [300,400],"sys_idx": [0,1],"trj_freq": 10,"nsteps": 2000,"ensemble": "nvt","_idx": 0},
{"temps": [300,400],"sys_idx": [0,1],"trj_freq": 10,"nsteps": 2000,"ensemble": "nvt","_idx": 1}
"_comment": "sys_idx should correspond to sys_configs in the beginning",
"_comment": "add the _idx step by step",
"_comment": "modify nsteps and sys_idx based on model deviation accuracy",
......
标记(计算单点能,此处以CP2K为例,VASP的设置可在官方文档中查看)
param.json{
......
"fp_style": "cp2k",
"shuffle_poscar": false,
"fp_task_max": 200,
"_comment": "the maximum number of stcs to calc.",
"fp_task_min": 5,
"fp_pp_path": ".",
"fp_pp_files": [],
"_comment":"the maximum number of stcs to calc.",
"_comment": "fp_params: modify according your systems!",
"fp_params": {
"FORCE_EVAL":{
"DFT":{
"BASIS_SET_FILE_NAME": "/data/kmr/BASIC_SET/BASIS_MOLOPT",
"POTENTIAL_FILE_NAME": "/data/kmr/BASIC_SET/GTH_POTENTIALS",
"MGRID":{
"CUTOFF": 400
"QS":{
"EPS_DEFAULT": 1.0E-13
"SCF":{
"SCF_GUESS": "ATOMIC",
"EPS_SCF": 1.0E-6,
"MAX_SCF": 500,
"ADDED_MOS": 500,
"CHOLESKY": "INVERSE",
"SMEAR":{"ON"
"METHOD": "FERMI_DIRAC",
"ELECTRONIC_TEMPERATURE": 300
"DIAGONALIZATION":{
"ALGORITHM": "STANDARD"
"MIXING":{
"METHOD": "BROYDEN_MIXING",
"ALPHA": 0.3,
"BETA": 1.5,
"NBROYDEN": 14
"XC":{
"XC_FUNCTIONAL":{"_": "PBE"},
"XC_GRID":{
"XC_SMOOTH_RHO": "NN50",
"XC_DERIV": "NN50_SMOOTH"
"vdW_POTENTIAL":{
"DISPERSION_FUNCTIONAL": "PAIR_POTENTIAL",
"PAIR_POTENTIAL":{
"TYPE": "DFTD3",
"PARAMETER_FILE_NAME": "/data/kmr/BASIC_SET/dftd3.dat",
"REFERENCE_FUNCTIONAL": "PBE"
"SUBSYS":{
"KIND":{
"_": ["O", "H","Pt"],
"POTENTIAL": ["GTH-PBE-q6", "GTH-PBE-q1","GTH-PBE-q10"],
"BASIS_SET": ["DZVP-MOLOPT-SR-GTH", "DZVP-MOLOPT-SR-GTH","DZVP-A5-Q10-323-MOL-T1-DERIVED_SET-1"]
CP2K的input中部分参数有默认设置写入,具体可参照cp2k.py。
指路:cp2k.py
金属体系OT section需要手动关闭,具体见上方的设置。
任务提交设置: machine.json
¶
从 DP-GEN 0.10.0 版本开始,官方引入了对 DPDispatcher 的支持,并计划将 machine.json
迁移到 DPDispatcher 上。
DPDispatcher 相比原本 DP-GEN 自带的 Dispatcher,在接口和语法上有较大变化,需要额外指定 api_version
大于或等于 1.0。
关于 DPDispatcher 项目的说明,请参阅这里。
DPDispatcher 相比旧版,基于配置字典而非文件Flag来管理所提交的任务,稳定性更优,且对作业管理系统的支持更加灵活多样,内置接口可支持多任务并行提交。
但新版在操作习惯上有较大改变,需要适应和调整。
以 LSF 为例,对 machine.json
的写法举例如下,请留意以下的注意事项。
train
部分和model_devi
部分使用了对新版 LSF 提供支持的写法,即同时指定 gpu_usage
和 gpu_new_syntax
为 True
,从而可在提交脚本中使用新版 LSF 的语法。
para_deg
表示在同一张卡上同时运行的任务数,通常可不写出,此时默认值为1。这里给出的例子表示在同一张卡上同时运行两个Lammps任务。
fp
部分使用的是针对CPU计算使用的语法。
注意在fp
部分,mpiexec.hydra
需要明确写出以确保任务是并行执行的,可参考以下例子中的写法:mpiexec.hydra -genvall vasp_gam
。若你不知道这部分该如何书写,请参考集群上的提交脚本说明(/data/share/base/scripts
)。
若在191上向191上提交任务,可以考虑使用LocalContext
,可以减少文件压缩传输的额外IO开销。
machine.json{
"api_version": "1.0",
"train": [
"command": "dp",
"machine": {
"batch_type": "Slurm",
"context_type": "LocalContext",
"local_root": "./",
"remote_root": "/data/tom/dprun/train",
"resources": {
"number_node": 1,
"cpu_per_node": 1,
"gpu_per_node": 1,
"queue_name": "gpu3",
"group_size": 1,
"module_list": [
"deepmd/2.0"
"model_devi":[
"command": "lmp_mpi",
"machine":{
"batch_type": "Slurm",
"context_type": "SSHContext",
"local_root": "./",
"remote_root": "/data/jerry/dprun/md",
"remote_profile": {
"hostname": "198.76.54.32",
"username": "jerry",
"port": 6666
"resources": {
"number_node": 1,
"cpu_per_node": 1,
"gpu_per_node": 1,
"queue_name": "gpu2",
"group_size": 5,
"kwargs": {
"custom_gpu_line": [
"#SBATCH --gres=gpu:1g.10gb:1"
"strategy": {"if_cuda_multi_devices": false},
"para_deg": 2,
"module_list": [
"deepmd/2.1"
"source_list": []
"fp":[
"command": "mpiexec.hydra -genvall cp2k.popt input.inp",
"machine":{
"batch_type": "Slurm",
"context_type": "SSHContext",
"local_root": "./",
"remote_root": "/data/jerry/dprun/fp",
"remote_profile": {
"hostname": "198.76.54.32",
"username": "jerry",
"port": 6666
"resources": {
"number_node": 2,
"cpu_per_node": 32,
"gpu_per_node": 0,
"queue_name": "c53-medium",
"group_size": 10,
"module_list": [
"intel/17.5.239",
"mpi/intel/2017.5.239",
"gcc/5.5.0"
"cp2k/7.1"
相关参数含义,详情请参阅官方文档
machine 和
resources 部分的说明。
以下是部分参数含义:
custom_gpu_line
自定义GPU提交命令,可根据语法自定义。根据作业管理系统不同,以 #BSUB
(LSF) 或 #SBATCH
(Slurm) 开头。文中的例子即在gpu2
上使用MIG实例(1g.10gb)。
custom_flags
其他需要使用的Flag,例如Walltime、作业名等设置。
queue_name
任务提交的队列名。
group_size
每个作业绑定的任务个数。
if_cuda_multi_devices
是否允许任务运行在多卡上,默认为 True
。在Zeus上建议写成 False
。
para_deg
同一卡上同时运行的任务数。默认为1。
module_list
需要load的module。可不写。
module_unload_list
需要unload的module。可不写。
source_list
需要source的脚本路径。可不写。
需要引入的环境变量。可不写。
Slurm获取状态异常问题的解决
若遇到以下报错,很大可能是因为Slurm暂时无法获取任务状态。由于旧版本DPDispatcher对这类波动导致的报错没有充分考虑,会直接退出:
RuntimeError: status command squeue fails to execute.job_id:13544
error message:squeue: error: Invalid user for SlurmUser slurm, ignored
squeue: fatal: Unable to process configuration file
新版这一部分已经做了调整,但由于之前的版本空文件夹复制过程存在严重bug,请务必保证DPDispatcher版本在0.5.6以上。
pip install --upgrade --user dpdispatcher
目前DP-GEN 0.11以上版本已经移除了旧版 dispatcher
的支持,推荐迁移到 DPDispatcher 上。为防止兼容性问题,这里仍保留了旧版的输入,请注意甄别。
machine_old.json{
"train": [
"machine": {
"machine_type": "slurm",
"hostname": "123.45.67.89",
"port": 22,
"username": "kmr",
"work_path": "/home/kmr/pt-oh/train"
"resources": {
"node_gpu": 1,
"numb_node": 1,
"task_per_node": 1,
"partition": "large",
"exclude_list": [],
"source_list": [],
"module_list": [
"deepmd/2.1"
"time_limit": "23:0:0"
"python_path": "/share/apps/deepmd/2.1/bin/python"
"model_devi": [
"machine": {
"machine_type": "slurm",
"hostname": "123.45.67.89",
"port": 22,
"username": "kmr",
"work_path": "/home/kmr/pt-oh/dpmd"
"resources": {
"node_gpu": 1,
"numb_node": 1,
"task_per_node": 1,
"partition": "large",
"exclude_list": [],
"source_list": [],
"module_list": [
"deepmd/2.1"
"time_limit": "23:0:0"
"command": "lmp_mpi",
"group_size": 80
"fp": [
"machine": {
"machine_type": "slurm",
"hostname": "123.45.67.90",
"port": 6666,
"username": "kmr",
"work_path": "/data/kmr/edl/pzc/hydroxide/ml_potential/pt-oh/labelling"
"resources": {
"cvasp": false,
"task_per_node": 28,
"numb_node": 1,
"node_cpu": 28,
"exclude_list": [],
"with_mpi": true,
"source_list": [
"module_list": [
"intel/17.5.239",
"mpi/intel/17.5.239",
"cp2k/6.1"
"time_limit": "12:00:00",
"partition": "medium",
"_comment": "that's Bel"
"command": "cp2k.popt input.inp",
"group_size": 50
训练集收集¶
DP-GEN代码迭代生成的训练集是分散储存的。可以用DP-GEN自带的collect函数进行数据收集。
首先可以使用dpgen collect -h
查看使用说明
常用用法是
dpgen collect JOB_DIR OUTPUT_DIR -p param.json
JOB_DIR就是DP-GEN的输出目录,包含有iter.0000*
一系列的目录。OUTPUT_DIR就是收集的数据准备放到哪。param.json就是运行DP-GEN跑的param文件。
dpgen collect ./ ./collect -p param-ruo2.json
以上命令会把当前文件夹的DP-GEN数据收集好放入collect目录里。
init.000 init.001 sys.000 sys.001
init.*
是初始训练集,sys.*
是后来DP-GEN生成的训练集,按照param的sys分类。
Bonus!¶
常见报错问题(欢迎补充&修正)¶
... expecting value ...
可能是数组或者字典末尾多写了逗号
ERROR: lost atoms ...
可能是Lammps算model_devi的时候因为势函数太差导致有原子重合而报错。可以手动在对应的单条轨迹的input.lammps中加入
thermo_modify lost ignore flush yes
然后在上一级文件夹下面手动提交任务
bsub<*.sub
- AssertionError
某个单点能计算中断后重新开始,导致cp2k的output中有重叠。可以在02.fp文件夹下用以下脚本进行检查:
import dpdata
import glob
l = glob.glob("task.002*")
l.sort()
stc = dpdata.LabeledSystem(l[0]+'/output',fmt='cp2k/output')
for i in l[1:]:
print(i)
stc += dpdata.LabeledSystem(i+'/output',fmt='cp2k/output')
其中task.002.*
代表遍历002system中的被标记的结构。如果不同系统的原子数相同,也可以直接用task.00*
一次性检查所有的结构。
如果你发现进行 model deviation 从一开始就非常大,并且测试集的结构被打乱,有可能是在 param 文件中设置了"shuffle_poscar": true
。该选项会随机打乱测试集原始 POSCAR
中的行,并用打乱后的结构进行 model deviation 测试。该选项主要用于打乱合金体系的结构,然而对于界面或者共价键连接的体系(如半导体),随机打乱原子的将会使界面结构或者半导体结构变成混乱的一锅粥,没有任何化学含义,因此我们不用进行shuffle(也不可以)。请在 param 文件中设置:
"shuffle_poscar": false
script from xyz to POSCAR¶
from ase.io import iread, write
import ase.build
for j in range(2):
i=0
for atoms in iread('./traj_'+str(j)+'.xyz', format='xyz'):
atoms.set_cell([11.246, 11.246, 35.94,90,90,90])
i=i+1
if i%20==0:
atoms=ase.build.sort(atoms)
ase.io.write('POSCAR_'+str(j)+'_'+str(int(i/20)-1), atoms, format='vasp',vasp5=True)
或者调用ase.io.vasp
里的write
:
def write_vasp(filename, atoms, label=None, direct=False, sort=None,
symbol_count=None, long_format=True, vasp5=False,
ignore_constraints=False):