
大家好我是专注于分享机器学习与科学计算实战经验的博主。在材料科学、化学和物理模拟领域基于深度学习的势函数Deep Potential DP模型正成为替代传统经验势函数的有力工具。很多朋友在成功使用 DP-GEN 生成数据集并用 DeePMD-kit 训练出 DP 模型后往往会卡在最后一步如何科学、全面地评估这个训练好的模型模型在训练集上表现良好但在未知结构上是否依然可靠其预测的力、能量、应力是否准确本文将围绕DP 模型的测试与验证这一核心主题系统性地拆解从加载模型、执行预测到结果分析与可视化评估的全流程。无论你是刚入门 DeePMD-kit 的新手还是希望将 DP 模型应用于实际科研项目的开发者都能从本文中找到一套可直接复用的闭环测试方案。1. 背景与核心概念为什么需要测试 DP 模型在深入操作之前我们首先要理解模型测试的必要性。一个典型的 DP 模型工作流包含数据准备、主动学习DP-GEN、模型训练DeePMD-kit和模型测试四个阶段。测试是验证模型泛化能力、确保其可用于实际模拟的关键环节。DP 模型是什么Deep Potential 模型是一种基于深度神经网络的原子间势函数。它通过学习第一性原理计算如 DFT产生的原子坐标、能量、力和应力数据构建一个能够以接近 DFT 精度、但计算成本低数个数量级的代理模型。其核心输入是原子系统的描述符如经过平滑处理的原子间距离和角度输出是系统的总能量、每个原子所受的力以及系统的维里应力。为什么训练后必须测试防止过拟合模型可能在训练集上表现完美低损失但对训练数据分布之外的新结构预测误差很大。测试用于评估这种泛化能力。量化误差我们需要具体的数值指标如能量 RMSE、力 RMSE来客观衡量模型的精度判断其是否达到研究要求。验证物理一致性模型的预测需要满足基本的物理规律例如能量应对平移和旋转不变力应为能量的负梯度等。测试可以部分验证这些性质。指导模型迭代测试结果是指引我们是否需要回退到 DP-GEN 进行更多数据探索或调整训练参数如网络大小、描述符参数的重要依据。核心测试场景静态性质测试对一组独立的测试集结构未参与训练进行单点能量、力和应力计算与 DFT 参考值比较。分子动力学MD模拟测试使用训练好的 DP 模型驱动 MD 模拟观察体系是否稳定并计算与 MD 相关的性质如径向分布函数、扩散系数与 DFT-MD 或实验结果对比。迁移性测试将模型应用于与训练数据截然不同的新相或新化学成分观察其表现。本文将重点讲解最基础也最必要的静态性质测试全流程。2. 环境准备与版本说明在进行测试之前请确保你的计算环境已就绪。本文的示例基于 Linux 系统但核心命令在配置好的环境下是通用的。操作系统 Ubuntu 20.04 LTS 或更高版本 / CentOS 7 或更高版本。Windows 用户可通过 WSL2 获得类似体验。Python 环境 推荐使用 Conda 管理环境避免依赖冲突。核心软件版本DeePMD-kit2.2.x或2.3.x版本。这是执行模型预测的核心库。本文命令以2.2.6为例。DP-GEN0.10.x或更高版本。它主要用于数据生成和主动学习循环在测试阶段我们主要使用其产出的数据和模型。LAMMPS或i-PI 如果你需要进行分子动力学测试则需要安装集成了 DeePMD-kit 的 LAMMPS 或 i-PI。本文静态测试暂不涉及。可视化与分析工具matplotlib,numpy,pandas,ase(Atomic Simulation Environment)。用于结果分析和绘图。环境搭建快速回顾 如果你已经完成了训练环境应该已经配置好。如果尚未安装可以参考以下最小化安装步骤以 Conda 为例# 1. 创建并激活 conda 环境 conda create -n dp-test python3.10 -y conda activate dp-test # 2. 安装 TensorFlow 和 DeePMD-kit # 注意DeePMD-kit 版本需与训练时使用的版本一致以避免模型兼容性问题。 pip install tensorflow2.11.0 pip install deepmd-kit2.2.6 lammps # 3. 安装分析工具 pip install matplotlib numpy pandas ase项目结构假设 假设你通过 DP-GEN 流程后得到了如下目录结构我们将在此基础上进行测试your_project/ ├── 00.train/ # 训练相关目录 │ ├── 000/ # 第一次训练迭代 │ │ ├── frozen_model.pb # 训练好的模型文件关键 │ │ ├── lcurve.out # 学习曲线 │ │ └── ... │ └── ... ├── 01.model_devi/ # 模型偏差计算目录 ├── 02.fp/ # 第一性原理计算数据 │ └── data/ # 最终的训练和测试数据集 │ ├── set.000/ # 数据集 0 │ │ ├── box.npy # 晶胞矢量 │ │ ├── coord.npy # 原子坐标 │ │ ├── energy.npy # 系统能量 │ │ ├── force.npy # 原子受力 │ │ └── virial.npy # 维里应力 │ └── ... └── ... # 其他 DP-GEN 目录关键文件说明frozen_model.pb: 冻结的模型文件是训练产出的最终模型用于部署和预测。data/目录下的.npy文件 由 DP-GEN 收集并经过第一性原理计算验证的数据集。我们将从中划分一部分作为测试集。3. 核心原理与测试流程拆解DP 模型的测试本质上是前向传播Inference过程。我们将测试集的原子坐标 (coord.npy) 和晶胞信息 (box.npy) 输入到训练好的frozen_model.pb中模型会输出预测的能量、力和应力。我们将这些预测值与第一性原理计算的参考值 (energy.npy,force.npy,virial.npy) 进行比较计算误差指标。标准测试流程准备测试数据从总数据集中分离出一部分从未参与训练的数据作为测试集。DP-GEN 的02.fp/data中通常已经混合了所有数据我们需要手动或按规则划分。转换数据格式DeePMD-kit 的测试工具通常需要特定的输入格式如deepmd/npy格式目录或deepmd/raw格式。我们需要将测试集数据转换成这种格式。执行模型测试使用 DeePMD-kit 提供的dp命令行工具加载模型并对测试集进行预测同时计算误差。结果分析与可视化解析测试工具输出的结果文件计算均方根误差 (RMSE)、平均绝对误差 (MAE) 等统计量并绘制散点图、误差分布图等直观评估模型性能。误差指标解读能量 RMSE (eV/atom) 每个原子的能量均方根误差。这是衡量模型精度的核心指标之一。对于金属和半导体通常需要达到1-10 meV/atom(0.001-0.01 eV/atom) 量级。力 RMSE (eV/Å) 每个原子每个分量上的力均方根误差。力的精度要求通常更高对于 MD 模拟 0.1 eV/Å是一个常见的目标 0.05 eV/Å则非常优秀。应力 RMSE (GPa 或 eV/Å^3) 维里应力的误差。对于涉及体积变化的模拟如相变、弹性性质计算很重要。4. 完整实战案例从模型文件到测试报告下面我们以一个具体的例子一步步演示如何测试一个训练好的水H₂O体系的 DP 模型。4.1 准备独立的测试集首先我们需要从总数据中分离出测试集。假设我们的所有数据都在02.fp/data目录下包含 1000 个结构。# 进入项目目录 cd your_project # 创建测试集目录 mkdir -p test_data cd test_data # 我们随机选取最后100个结构作为测试集假设前900个用于训练 # 注意这是一种简单划分。更严谨的做法是在DP-GEN阶段就通过设置fp_style等参数预留测试集。 for i in {900..999}; do # 复制数据文件 cp ../02.fp/data/set.$(printf “%03d“ $i)/* . # 为了区分我们可以重命名或移动到子目录这里我们简单复制 # 实际建议将每个set的文件复制到 test_data/set.$(printf “%03d“ $((i-900))) 中 done # 更规范的做法使用Python脚本按比例随机划分 # 这里提供一个简单的Python脚本示例 split_test_set.pysplit_test_set.py脚本内容import numpy as np import os, shutil, random data_dir “../02.fp/data“ test_ratio 0.1 # 10% 作为测试集 test_dir “./test_data_deepmd“ os.makedirs(test_dir, exist_okTrue) # 获取所有set目录 all_sets sorted([d for d in os.listdir(data_dir) if d.startswith(‘set.‘)]) total_sets len(all_sets) indices list(range(total_sets)) random.seed(42) # 固定随机种子确保可重复性 random.shuffle(indices) num_test int(total_sets * test_ratio) test_indices indices[:num_test] print(f“Total sets: {total_sets}, Test sets: {num_test}“) # 复制测试集数据并转换为连续的set编号 for new_idx, old_idx in enumerate(test_indices): old_set_name all_sets[old_idx] new_set_name f“set.{new_idx:03d}“ src_path os.path.join(data_dir, old_set_name) dst_path os.path.join(test_dir, new_set_name) shutil.copytree(src_path, dst_path) print(f“Copied {old_set_name} - {new_set_name}“) print(f“Test data prepared in {test_dir}“)运行脚本python split_test_set.py执行后你会在test_data_deepmd目录下得到类似set.000,set.001, ... 的测试数据集。4.2 转换数据为 DeePMD-kit 格式DeePMD-kit 的测试和训练需要数据是deepmd/npy格式。我们的数据已经是这种格式每个set.xxx目录下有box.npy,coord.npy等。但为了测试我们需要确保所有测试集数据被正确识别。通常直接使用set.xxx目录的父目录即可。检查test_data_deepmd目录结构test_data_deepmd/ ├── set.000/ │ ├── box.npy │ ├── coord.npy │ ├── energy.npy │ ├── force.npy │ └── virial.npy ├── set.001/ └── ...这个结构本身就是deepmd/npy格式。4.3 使用dp命令进行模型测试DeePMD-kit 的dp工具提供了test子命令专门用于评估模型在给定数据集上的性能。# 假设你的训练好的模型路径为00.train/000/frozen_model.pb # 测试数据路径为./test_data_deepmd dp test -m 00.train/000/frozen_model.pb -s ./test_data_deepmd -n 1000 -d results命令参数解释-m, --model: 指定训练好的冻结模型文件 (frozen_model.pb) 的路径。-s, --system: 指定测试数据集的路径。该路径下应包含多个set.xxx目录。-n, --number: 指定从数据集中抽取多少帧结构进行测试。如果数据量很大可以设置一个较小的数以加快测试速度。使用-1表示测试所有帧。-d, --output: 指定输出目录。测试结果将保存在该目录下。其他有用参数--atomic: 输出每个原子的能量如果模型支持。--shuffle: 在抽取测试帧时打乱顺序。执行命令后程序会逐帧读取测试数据用模型进行预测并与参考值比较。屏幕上会滚动显示进度和初步统计信息。4.4 理解测试输出结果测试完成后在results目录下会生成几个关键文件ls results/ # 可能输出energy.out force.out virial.out checkpoint model_devi.out (如果指定了--atomic等)energy.out: 能量测试结果。head -20 results/energy.out输出示例# number of test data : 100 # Energy RMSE : 0.002345 eV # Energy RMSE/Natoms : 0.000123 eV/atom # Energy MAE : 0.001234 eV # Energy MAE/Natoms : 0.000065 eV/atom # max Energy error : 0.005678 eV # min Energy error : 0.000012 eV # data idx, energy (eV), energy_p (eV), diff (eV) 0 -123.456789 -123.458123 0.001334 1 -122.987654 -122.985432 -0.002222 ...前几行是整体统计信息测试数据量、RMSE、平均绝对误差 (MAE) 等。后续行是每一帧数据的详细对比idx是帧索引energy是 DFT 参考能量energy_p是模型预测能量diff是差值 (energy_p - energy)。force.out: 力测试结果。格式类似但统计量是针对所有原子所有力分量的。# number of test data : 100 # number of atoms : 300 # Force RMSE : 0.045678 eV/A # Force MAE : 0.032156 eV/A # max Force error : 0.123456 eV/A # min Force error : 0.000001 eV/A # data idx, atom idx, fx, fy, fz, fx_p, fy_p, fz_p, diff ...virial.out: 应力测试结果如果数据中包含维里应力。关键指标解读 对于我们的水模型示例假设我们得到Energy RMSE/Natoms : 0.0008 eV/atom(0.8 meV/atom)Force RMSE : 0.038 eV/Å这个结果对于水体系而言是相当不错的表明模型在能量和力上都达到了较高的精度可以用于后续的分子动力学模拟。4.5 结果可视化与分析数字指标很重要但可视化能更直观地揭示问题。我们可以用 Python 脚本绘制预测值与参考值的散点图、误差分布直方图等。创建一个plot_results.py脚本import numpy as np import matplotlib.pyplot as plt import os # 1. 读取能量测试结果 energy_data np.loadtxt(‘results/energy.out‘, skiprows7) # 跳过前7行注释 idx energy_data[:, 0] e_dft energy_data[:, 1] # DFT能量 e_dp energy_data[:, 2] # DP预测能量 e_diff energy_data[:, 3] # 差值 # 计算每原子能量 (假设每个结构有24个原子这里需要根据你的体系调整) natoms_per_frame 24 e_dft_per_atom e_dft / natoms_per_frame e_dp_per_atom e_dp / natoms_per_frame e_diff_per_atom e_diff / natoms_per_frame # 2. 绘制能量散点图 plt.figure(figsize(12, 4)) plt.subplot(1, 3, 1) plt.scatter(e_dft_per_atom, e_dp_per_atom, alpha0.6, s10) min_val min(e_dft_per_atom.min(), e_dp_per_atom.min()) max_val max(e_dft_per_atom.max(), e_dp_per_atom.max()) plt.plot([min_val, max_val], [min_val, max_val], ‘r--‘, lw1, label‘yx‘) plt.xlabel(‘DFT Energy per atom (eV)‘) plt.ylabel(‘DP Predicted Energy per atom (eV)‘) plt.title(‘Energy Scatter Plot‘) plt.legend() plt.grid(True, linestyle‘--‘, alpha0.5) # 3. 绘制能量误差分布直方图 plt.subplot(1, 3, 2) plt.hist(e_diff_per_atom, bins30, edgecolor‘black‘, alpha0.7) plt.xlabel(‘Energy Error per atom (eV)‘) plt.ylabel(‘Frequency‘) plt.title(‘Energy Error Distribution‘) plt.axvline(xe_diff_per_atom.mean(), color‘r‘, linestyle‘--‘, labelf‘Mean: {e_diff_per_atom.mean():.6f}‘) plt.axvline(xe_diff_per_atom.std(), color‘g‘, linestyle‘:‘, labelf‘Std: {e_diff_per_atom.std():.6f}‘) plt.legend() plt.grid(True, linestyle‘--‘, alpha0.5) # 4. 绘制误差随结构索引的变化检查系统性偏差 plt.subplot(1, 3, 3) plt.plot(idx, e_diff_per_atom, ‘o-‘, markersize3, alpha0.7) plt.xlabel(‘Frame Index‘) plt.ylabel(‘Energy Error per atom (eV)‘) plt.title(‘Error vs. Frame Index‘) plt.axhline(y0, color‘k‘, linestyle‘-‘, linewidth0.5) plt.grid(True, linestyle‘--‘, alpha0.5) plt.tight_layout() plt.savefig(‘energy_test_analysis.png‘, dpi300) plt.show() # 5. 类似地可以读取和分析 force.out # force_data np.loadtxt(‘results/force.out‘, skiprows7) # ... 绘制力的误差分析图 print(“能量分析图已保存为 ‘energy_test_analysis.png‘“)运行脚本python plot_results.py生成的图像将帮助你判断散点图 理想情况下所有点应落在红色对角线上。点的离散程度反映了模型的随机误差。误差分布 理想情况下应近似正态分布均值为零。如果分布有偏说明模型存在系统性偏差。误差 vs 索引 如果误差随索引呈现某种趋势如逐渐变大可能意味着测试集中的结构存在某种顺序如按温度或压强排列而模型对某一区间的数据拟合较差。5. 常见问题与排查思路在测试 DP 模型时你可能会遇到以下典型问题问题现象可能原因排查思路与解决方案dp test命令报错ValueError: cannot reshape array...1. 测试数据格式与模型期望的输入维度不匹配。2.type_map原子类型映射不一致。1.检查数据维度确认coord.npy的形状是[n_frames, n_atoms*3]box.npy是[n_frames, 9]。使用np.load(‘coord.npy‘).shape查看。2.检查type_map模型训练时定义了原子类型顺序如[“O“, “H“]。测试数据中type.raw文件如果有或原子类型的实际顺序必须与此一致。确保测试数据来自与训练数据相同的源或使用dp -m model.pb --print-type-map查看模型的类型映射。能量误差 (RMSE) 非常大 ( 0.1 eV/atom)1. 测试集与训练集分布完全不同模型未见过此类结构。2. 模型训练不收敛或过拟合。3. 数据单位不一致。1.检查数据来源确保测试集是训练数据分布的合理子集。可视化测试集和训练集的结构如用 ASE 查看键长、键角。2.检查训练日志查看lcurve.out确认训练损失和验证损失是否都已收敛到较低平台且没有明显过拟合验证损失不上升。3.检查单位DeePMD-kit 默认使用 eV能量、Å长度。确保你的第一性原理数据输出单位与此一致。力误差 (RMSE) 很大但能量误差尚可1. 训练数据中力的噪声较大或精度不足。2. 模型描述符如sel、rcut设置不合理无法捕捉敏感的局部环境信息。3. 网络容量不足。1.检查 DFT 计算设置确保第一性原理计算力的收敛标准足够严格如EDIFFG -0.01in VASP。2.审查训练参数检查input.json中的descriptor参数特别是rcut截断半径是否足够大以包含重要的原子相互作用sel各类型原子最大邻居数是否足够。3.尝试更大网络增加fitting_net中神经网络的层数和节点数。测试时部分结构的力/能量出现极端异常值1. 该结构存在非常异常的原子构型如原子距离过近。2. 模型在该区域的泛化能力极差。1.检查异常结构使用脚本找出误差最大的几帧用 ASE 或 VMD 可视化这些结构看是否存在物理上不合理的构型。2.将这些结构加入训练如果这些结构是物理上可能存在的说明训练集覆盖不足。可以将这些结构作为新的初始数据重新启动 DP-GEN 的主动学习循环。dp test输出结果文件中没有应力 (virial.out)1. 测试数据中没有提供维里应力 (virial.npy)。2. 训练模型时没有启用应力训练。1.检查数据确认test_data_deepmd/set.000/等目录下存在virial.npy文件。2.检查训练配置查看训练用的input.jsonloss部分是否配置了virial的权重 (pref_virial)。如果为0或未设置模型不会学习预测应力。6. 最佳实践与工程建议为了确保 DP 模型测试的有效性和结果的可靠性遵循以下最佳实践至关重要测试集与训练集严格独立时间上独立在 DP-GEN 的主动学习流程开始前就应预留一部分“种子”数据作为测试集并且在整个循环中绝不使用它们进行训练。分布上覆盖测试集应尽可能覆盖你期望模型应用的整个构型空间如不同的温度、压强、成分范围。如果测试集只来自一个狭窄区域好的测试结果不代表模型全局好用。采用多种测试手段静态测试本文重点提供基础精度指标。分子动力学测试使用 LAMMPS 或 i-PI 运行一段 NVT 或 NPT 模拟。检查体系是否稳定原子是否飞散。计算径向分布函数 (RDF)、扩散系数等与参考的 DFT-MD 或实验数据对比。这是更严格的测试。性质预测测试使用 DP 模型计算晶格常数、弹性常数、声子谱等与 DFT 计算结果比较。建立模型测试报告模板每次训练出新模型都运行一套固定的测试脚本自动生成包含以下内容的报告模型基本信息训练迭代步数、最终损失值。静态测试误差表能量、力、应力 RMSE/MAE。关键误差分布图、散点图。如果进行了 MD 测试附上 RDF 对比图、能量漂移图。测试结论与建议通过/不通过是否需要重新训练。版本控制与记录将训练模型的input.json、最终frozen_model.pb以及对应的测试结果和报告一并归档。记录训练数据的来源、DFT 计算参数、测试集划分方式。这保证了工作的可重复性。理解误差的物理意义0.01 eV/atom的能量误差对于凝聚态体系通常是可以接受的。力的误差直接影响 MD 模拟的稳定性。通常0.1 eV/Å是 MD 模拟可用的门槛0.05 eV/Å以下则质量较高。对于需要精确计算声子或弹性性质的工作对力的精度要求更高。生产环境部署前的最后验证在将模型用于大规模生产模拟如数千原子的长时 MD之前务必先用一个小体系如 100 原子进行长时间的测试模拟如 100 ps密切监控总能、温度、压力的波动是否在物理合理范围内。通过本文详细的步骤讲解、代码示例和问题排查指南你应该已经掌握了系统测试 DeePMD-kit 训练出的 DP 模型的方法。从准备数据、运行测试命令到深入分析结果每一步都是确保模型可靠性的关键。记住一个未经充分测试的模型就像未经测试的代码将其用于科学计算可能会产生误导性的结果。建议你将文中的脚本整合到你的工作流中形成自动化的测试流水线。如果在测试中发现了模型精度不足的问题那就是反馈给 DP-GEN 进行新一轮数据探索和模型训练的信号这正是主动学习闭环的核心价值所在。