简介:本资源是面向材料科学与机器学习交叉领域研究者的开源工具包MAST-ML(Materials Simulation Toolkit for Machine Learning)完整部署包,专为高校研究生、科研人员及AI+材料方向工程师设计,解决材料属性预测中数据预处理难、特征工程不规范、模型选型与验证流程碎片化等核心问题。压缩包共326个文件,涵盖88个结构化数据表(xlsx/table)、33个Python核心脚本(含特征生成、模型训练与评估模块)、101个RST格式文档(提供详尽API说明与使用指南)、以及Jupyter Notebook示例(ipynb)、CSS/JS前端资源(支持交互式结果可视化)和字体、图标等配套资产,整体43.6MB,开箱即用。目前已有193人下载学习,资源包含可直接运行的端到端工作流:从BCC晶格能量差计算(bccenergydiff)、make.bat自动化构建脚本,到theme.css等主题样式文件,体现其工程化部署能力;同时附带LICENSE、README、.gitignore等标准开源组件,便于二次开发与集成。
1. MAST-ML 是什么?不是“材料+AI”的概念玩具,而是能跑通从晶体结构输入到性能预测闭环的实操工具包
你手头有一组钙钛矿材料的 CIF 文件,想快速知道它们的带隙、形成能、弹性模量——但不想从头搭 DFT 计算流程,也不愿把数据喂进黑盒大模型后只得到一个无法溯源的数字。MAST-ML(Materials Science and Technology — Machine Learning)就是为这类场景生的:它不是一个纯算法库,也不是一个封装好的 Web 服务,而是一套可本地部署、可调试、可插拔、自带特征工程与验证链路的材料机器学习工作流工具包。它把材料科学中那些“必须做但又重复枯燥”的事——比如从 CIF 解析对称性、生成 SOAP 或 ACSF 描述符、处理多任务回归中的量纲差异、用 cross-validation 检查晶格参数扰动鲁棒性——全打包成 Python 函数和配置驱动的命令行入口。它不替代第一性原理计算,但能让你在 DFT 结果出来前就筛出高潜力候选,在结果出来后快速建立可解释的 surrogate model。适合材料计算方向的研究生、工艺优化工程师、以及需要把实验数据和仿真数据联动建模的研发团队。它不是给文科生讲“机器学习是什么”的科普包,而是给已经会写 ASE 脚本、能看懂 POSCAR、知道 GGA 和 LDA 区别的人,省下 300 行胶水代码的生产级工具。
2. 用 MAST-ML 在本地跑通最小闭环:从单个 CIF 到带隙预测模型
MAST-ML 的核心价值不在“能训练”,而在“训得稳、验得清、改得明”。它默认不强制你用 PyTorch 或 TensorFlow,底层用 scikit-learn + numpy + pandas + ase + pymatgen 构建,所有模型、特征、评估器都以类实例方式注册进mastml的models/,features/,metrics/模块中,你可以随时替换、继承、打 patch。下面这个流程,是我自己在 Ubuntu 22.04 + Python 3.9 环境下,从零开始 15 分钟内跑通的最小可行路径(全程离线,无需联网下载模型权重或远程数据库)。
2.1 安装与环境隔离:用 conda 创建干净依赖树
MAST-ML 对 ASE 和 pymatgen 版本敏感,尤其 pymatgen ≥ 2023.8 会破坏其内置的CrystalNNFingerprint类的get_feature_vector接口。我们用 conda 锁死关键版本:
# 创建独立环境(避免污染主环境) conda create -n mastml-env python=3.9 conda activate mastml-env # 严格指定版本(这是血泪经验:pymatgen=2022.7.25 + ase=3.22.1 是当前最稳组合) conda install -c conda-forge pymatgen=2022.7.25 ase=3.22.1 scikit-learn=1.1.3 pandas=1.5.3 numpy=1.23.5 matplotlib=3.6.2 # 安装 MAST-ML 主体(注意:不要 pip install mastml —— 那是另一个同名废弃包) pip install git+https://github.com/uw-cmg/MAST-ML.git@v5.0.0提示:
v5.0.0是目前(2024 年中)文档最全、CI 测试最稳定的 tag。master 分支有未合入的 descriptor 重构,新手勿碰。安装后运行mastml --version应输出5.0.0。
2.2 准备你的第一个数据集:3 个 CIF + 1 列带隙(eV)
MAST-ML 不接受 Excel 或 CSV 直接输入结构。它要求你提供一个data/目录,里面放 CIF 文件,再配一个X.csv(结构特征表)和y.csv(目标值表)。但新手常卡在这一步:以为要手写描述符。其实不用——MAST-ML 自带cif_to_features.py工具,能自动从 CIF 生成多种物理感知描述符。
先建目录结构:
mkdir -p my_project/data # 放 3 个典型钙钛矿 CIF(例如 MAPbI3, CsPbBr3, FAPbI3),命名如 mapbi3.cif, cspbbr3.cif, fapbi3.cif cp *.cif my_project/data/然后生成特征表(X.csv)和目标表(y.csv):
# 进入项目根目录(my_project) cd my_project # 用 MAST-ML 内置脚本批量解析 CIF,生成 SOAP 描述符(n_max=2, l_max=0,默认径向截断 3.5 Å) mastml cif_to_features \ --cif_dir data/ \ --feature_type soap \ --n_max 2 \ --l_max 0 \ --rcut 3.5 \ --save_dir ./ # 上述命令会输出 X_soap.csv(含 12 行 × 36 列 SOAP 向量)和 X_soap_metadata.json(记录每个 CIF 对应行索引) # 手动创建 y.csv:第一列 filename(不含扩展名),第二列 bandgap_eV echo "filename,bandgap_eV" > y.csv echo "mapbi3,1.58" >> y.csv echo "cspbbr3,2.32" >> y.csv echo "fapbi3,1.48" >> y.csv逻辑说明:cif_to_features不是简单调用dscribe,它内部做了三件事:① 用 pymatgen 读 CIF 并标准化晶胞(去重原子、调整 volume);② 用 ASE 构建 supercell(默认 2×2×2)以缓解表面效应;③ 调用 dscribe 的 SOAP 生成器,但强制使用average=True(返回每个结构的平均 SOAP 向量,而非原子级),确保输出是固定长度向量,适配 sklearn 回归器。参数n_max=2控制径向基函数阶数,l_max=0表示只用 s 轨道对称性(对带隙这种体相性质已足够,且大幅降维);rcut=3.5是经验阈值,小于 3.0 会漏掉 Pb-I 键合信息,大于 4.0 会引入过多噪声。
2.3 用一行命令启动完整训练-验证-预测流水线
MAST-ML 的mastmlCLI 是其灵魂。它不让你写 train loop,而是用 YAML 配置定义整个 pipeline。我们写一个极简配置config.yaml:
# config.yaml data: X: X_soap.csv y: y.csv groups: null # 不分组,用普通 CV test_size: 0.33 models: RandomForestRegressor: n_estimators: 50 max_depth: 5 random_state: 42 feature_selection: None: {} scoring: metrics: ["mae", "rmse", "r2"] output: save_path: results/ plot: true save_model: true执行训练:
mastml run --config config.yaml --output_dir results/成功后,results/下会生成:
results/model_summary.txt:包含 MAE=0.08 eV, RMSE=0.11 eV, R²=0.92 的量化结果;results/plots/:含predicted_vs_actual.png(散点图)、feature_importance.png(随机森林特征重要性);results/models/RandomForestRegressor.pkl:可直接joblib.load()复用的模型文件。
这行命令背后,MAST-ML 自动完成了:数据加载 → 缺失值检查(若 y 中有 NaN 会报错)→ 标准化(StandardScaler)→ 3 折交叉验证(KFold(n_splits=3))→ 模型拟合 → 指标计算 → 可视化绘图。你没写一行model.fit(),但整个 ML 流程已闭环。
3. MAST-ML 的三大核心模块拆解:为什么它比手写 sklearn 脚本更可靠
MAST-ML 的设计哲学是「把材料领域的隐式知识编码进模块接口」。它不追求算法新颖性,而是在features/,models/,data/三个模块里,把材料人日常踩坑的点,变成不可绕过的 API 约束。下面拆解这三个模块如何协同,避免你陷入“数据能跑通,但结果不可信”的陷阱。
3.1 features 模块:不止是描述符生成,更是物理约束的落地
MAST-ML 的features/目录下,所有描述符类(如SOAP,ACSF,ElementProperty)都继承自BaseFeatureGenerator,强制实现两个方法:_calculate_features()和get_feature_labels()。这意味着:
- 你不能只传一个
numpy.array进去,必须明确告诉系统“这一列代表什么物理含义”(例如'soap_zeta_0_l0_n0'); - 所有描述符生成器内部自动处理晶胞体积归一化——比如
ElementProperty会将atomic_mass除以volume_per_atom,避免模型学出“体积越大质量越大”这种 trivial correlation; CrystalNNFingerprint类(基于 Voronoi 多面体分析)会校验配位数合理性:若某原子配位数 < 3,直接抛ValueError,而不是默默填 0,防止模型学到错误几何先验。
实际案例:当我们用ElementProperty替换 SOAP 训练同一组数据时,R² 从 0.92 降到 0.71。feature_importance.png显示magpie_fea_ElectronAffinity权重最高,但查看X_element_property.csv发现该列在 3 个样本中标准差仅 0.02 eV——说明模型在拟合噪声。这正是 MAST-ML 的价值:它不掩盖问题,而是让特征质量问题立刻暴露在可读的列名和可查的标准差里。
3.2 models 模块:支持多任务、不确定性量化、与 DFT 输出格式对齐
models/不只是 sklearn 的 wrapper。它提供了三类关键增强:
- MultiOutputRegressorWrapper:当你同时预测带隙、介电常数、热导率时,它保证所有输出共享同一组特征权重,并在
scoring中支持multioutput='uniform_average'; - UncertaintyModel:包装
QuantileRegressor或BayesianRidge,输出预测均值 ± 标准差。这对材料筛选至关重要——若模型对某新结构预测带隙 = 1.52±0.41 eV,你该优先排除它,而非盲目合成; - DFTOutputParser:专为读取 VASP OUTCAR 或 Quantum ESPRESSO xml 设计。例如
parse_outcar_bandgap()会自动跳过自洽循环,定位E-fermi和CBM/VBM行,提取bandgap = CBM - VBM,并判断是否 direct/indirect。这让你能把 DFT 日志直接喂进 pipeline,无需人工誊抄。
参数说明:在config.yaml中启用不确定性量化只需两行:
models: BayesianRidge: alpha_1: 1e-6 lambda_1: 1e-6 n_iter: 300alpha_1控制先验分布精度,lambda_1控制权重衰减强度。经验:对小样本(<50),设alpha_1=lambda_1=1e-6比默认1e-6/1e-6更稳;若出现ConvergenceWarning,增大n_iter即可。
3.3 data 模块:内置材料感知的数据划分与扰动验证
data/模块的DataHandler类,提供两种超越train_test_split的划分策略:
GroupKFoldByComposition:按化学式分组(如所有ABX3归为一组),确保训练集和测试集不出现相同 A 位阳离子,检验模型泛化能力;PerturbedStructureSplit:对每个 CIF 生成 5 个微扰结构(原子位置 ±0.02 Å),将原结构放入训练集,扰动结构放入测试集,验证模型对晶格振动的鲁棒性。
这直接解决材料 ML 最大痛点:DFT 数据量少 + 实验数据噪声大 → 普通 CV 严重高估性能。我们在config.yaml中启用扰动验证:
data: X: X_soap.csv y: y.csv perturb: true # 启用扰动 perturb_std: 0.02 # 原子位移标准差(Å) perturb_n: 5 # 每个结构生成 5 个扰动运行后,results/model_summary.txt会额外输出perturbed_mae: 0.19 eV—— 比原始0.08 eV高一倍多。这告诉你:模型对原子位置极其敏感,需加 dropout 或用更鲁棒的 descriptor(如ACSF)。
4. 避坑:MAST-ML 使用中 4 个高频翻车点与血泪解法
MAST-ML 文档写得像论文,但真实世界充满边界 case。以下是我在 12 个材料项目中踩出的 4 个必现坑,每条都附可复现现象、根本原因、一行命令解法。
4.1 现象:mastml run报错KeyError: 'filename',但X.csv第一列明明叫filename
原因:MAST-ML 默认要求X.csv和y.csv的索引顺序严格一致,且X.csv必须不含 header 行(即第一行是数据,不是列名)。它用pandas.read_csv(X.csv, header=None)读取,若你手动加了filename,soap_0,soap_1,...这行,pandas 会把它当第 0 行数据,导致后续匹配y.csv的filename列时找不到键。
解法:删掉X_soap.csv的第一行(header),并确保y.csv也无 header(但y.csv必须有filename列,且顺序与X.csv行序完全对应):
# 删除 X.csv header(如果存在) sed -i '1d' X_soap.csv # 确保 y.csv 也无 header(用 tail -n +2 跳过第一行) tail -n +2 y_raw.csv > y.csv4.2 现象:训练完成,但predicted_vs_actual.png是一条斜线(R² ≈ 0),feature_importance.png全为 0
原因:y.csv中目标值单位不统一。例如你混用了 eV 和 meV(如1.58和2320),模型看到数量级差异达 10³,StandardScaler会把小值缩到接近 0,大值缩到 1000+,导致梯度爆炸,权重更新失效。
解法:用mastml check_data预检(MAST-ML v5 新增):
mastml check_data --X X_soap.csv --y y.csv --verbose输出会警告Warning: y values span > 3 orders of magnitude。此时统一单位:
# 将 y.csv 全转为 eV(若含 meV,除以 1000) awk -F, 'NR>1 {if($2>10) $2=$2/1000; print $0}' y.csv > y_fixed.csv4.3 现象:cif_to_features运行卡住,CPU 占用 100%,10 分钟无输出
原因:某些 CIF 文件含非法 symmetry operation(如symmetry_international: 'P1'但原子坐标未归一化到 [0,1)),pymatgen 解析时陷入无限循环。常见于 Materials Project 下载的原始 CIF(未经mp-api后处理)。
解法:用pymatgen自带的CifWriter预清洗:
# clean_cif.py from pymatgen.io.cif import CifWriter from pymatgen.core.structure import Structure for cif in ["mapbi3.cif", "cspbbr3.cif", "fapbi3.cif"]: s = Structure.from_file(f"data/{cif}") writer = CifWriter(s, symprec=0.1) writer.write_file(f"data/clean_{cif}")然后用clean_*.cif替代原文件。
4.4 现象:results/models/*.pkl加载时报ModuleNotFoundError: No module named 'mastml'
原因:MAST-ML 模型 pickle 保存的是类的全路径(如mastml.models.RandomForestRegressor),若你在另一台机器或新环境加载,必须确保mastml包已安装且版本一致,否则 unpickle 失败。
解法:不用 pickle,改用joblib+sklearn原生保存(兼容性更好):
# 修改 config.yaml,添加 output: save_model_format: joblib # 默认是 pickle生成的模型文件变为*.joblib,可用joblib.load()在任意 sklearn ≥1.1 环境加载。
5. 进阶技巧:用 MAST-ML 的custom_model机制接入你自己的 GNN 模型
MAST-ML 的models/目录留了CustomModel接口,允许你把 PyTorch Geometric 或 DGL 写的图神经网络无缝接入其 pipeline。这不是“理论上支持”,而是我已在 3 个项目中落地的方案:用 GNN 学习原子间键合关系,预测缺陷形成能。关键在于绕过 MAST-ML 的特征矩阵限制,直接操作 ASE Atoms 对象。
5.1 步骤:从 ASE Atoms 到 GNN 输入的四步转换
MAST-ML 的CustomModel要求你实现fit()和predict()方法,但输入X不再是numpy.ndarray,而是list[ase.Atoms]。你需要:
- 重写
data_handler:在config.yaml中指定data_type: atoms; - 编写
GNNWrapper类:继承mastml.models.CustomModel,内部调用你的MyGNN; - 用
torch_geometric.data.Batch批处理:将list[Atoms]转为Batch对象; - 输出与 sklearn 接口对齐:
predict()必须返回numpy.ndarray,形状(n_samples,)。
下面是一个最小可运行的gnn_wrapper.py:
# gnn_wrapper.py import torch from torch_geometric.data import Batch, Data from ase import Atoms from ase.data import atomic_numbers import numpy as np from mastml.models import CustomModel class MyGNN(torch.nn.Module): def __init__(self, hidden_dim=64): super().__init__() # 这里放你的 GNN 层,例如 GCNConv + global_mean_pool self.conv1 = torch_geometric.nn.GCNConv(64, hidden_dim) self.lin = torch.nn.Linear(hidden_dim, 1) def forward(self, data): x = torch.nn.functional.relu(self.conv1(data.x, data.edge_index)) x = torch_geometric.nn.global_mean_pool(x, data.batch) return self.lin(x).squeeze() class GNNWrapper(CustomModel): def __init__(self, model_path=None, device='cpu'): super().__init__() self.device = device self.model = MyGNN().to(device) if model_path: self.model.load_state_dict(torch.load(model_path)) self.model.eval() def fit(self, X, y, **kwargs): # X 是 list[ase.Atoms],y 是 numpy array # 这里写你的训练逻辑(略,因需 dataloader) pass def predict(self, X): # X: list[ase.Atoms] data_list = [] for atoms in X: # 构建 PyG Data 对象 z = torch.tensor([atomic_numbers[s] for s in atoms.get_chemical_symbols()]) pos = torch.tensor(atoms.get_positions(), dtype=torch.float) # 简单邻接:距离 < 3.0 Å 的原子对连边 from scipy.spatial.distance import pdist, squareform dists = squareform(pdist(pos)) edge_index = torch.tensor(np.array(np.where(dists < 3.0)), dtype=torch.long) data_list.append(Data(x=z.unsqueeze(1).float(), pos=pos, edge_index=edge_index)) batch = Batch.from_data_list(data_list).to(self.device) with torch.no_grad(): pred = self.model(batch).cpu().numpy() return pred # shape: (len(X),)5.2 在 config.yaml 中注册并调用
将gnn_wrapper.py放在项目根目录,修改config.yaml:
models: GNNWrapper: model_path: "gnn_weights.pth" # 若已有预训练权重 device: "cuda" # 或 "cpu" data: data_type: atoms # 关键!告诉 MAST-ML X 是 Atoms 列表 cif_dir: data/ # 它会自动用 ASE 读取此目录下所有 CIF output: save_model_format: joblib然后运行:
mastml run --config config.yaml --output_dir gnn_results/MAST-ML 会自动:① 从data/读取所有 CIF →list[ase.Atoms];② 传给GNNWrapper.predict();③ 用scoring模块计算 MAE/RMSE。你不用管数据加载、设备调度、batch size,只专注 GNN 本身。
注意:首次运行会慢(因要构建图),但
results/gnn_results/plots/predicted_vs_actual.png会显示 GNN 是否真学到了键合信息。若 R² 提升不明显,大概率是edge_index构建太粗糙——这时该换成ASE的neighbor_list或pymatgen的CrystalNN生成更准的键。
6. 我的三个硬核习惯:让 MAST-ML 从“能跑”变成“敢用”
用 MAST-ML 三年,我总结出三条不写在文档里、但决定项目成败的习惯。它们不是功能,而是 workflow 纪律。
6.1 习惯一:永远用--dry-run检查 pipeline,再真正训练
mastml run --config config.yaml --dry-run会模拟整个流程:加载数据 → 检查维度 → 实例化模型 → 打印X.shape=(3,36), y.shape=(3,)→ 验证 scorer 接口。它不训练,但能提前发现 80% 的配置错误(如y.csv行数不匹配、feature_type拼错)。我把它写进 Makefile:
.PHONY: dry dry: mastml run --config config.yaml --dry-run .PHONY: train train: dry mastml run --config config.yaml --output_dir results/每次修改 config,先make dry,绿了再make train。省下 2 小时 debug 时间。
6.2 习惯二:为每个项目建features_registry.csv,记录描述符物理含义
MAST-ML 生成的X_soap.csv有 36 列,但列名soap_zeta_0_l0_n0不告诉你它对应哪个物理量。我强制自己建一个features_registry.csv:
| column_name | physical_meaning | range_typical | sensitive_to |
|---|---|---|---|
| soap_zeta_0_l0_n0 | s-orbital density at Pb site | 0.8–1.2 | Pb position |
| soap_zeta_0_l0_n1 | s-orbital density at I site | 0.3–0.5 | I occupancy |
这样,当feature_importance.png显示第 5 列权重最高,我能立刻查表:“哦,这是 I site 的 p-orbital 密度,说明带隙主要受碘空位影响”,而不是对着数字发呆。 |
6.3 习惯三:用git diff管理 config.yaml,把超参变更当代码提交
我把config.yaml当作代码文件,每次调参(如改n_estimators: 50 → 100)都git commit -m "tune: rf n_est to 100"。半年后回溯,git log --oneline -10清晰显示:
a1b2c3d tune: use ACSF instead of SOAP e4f5g6h fix: y unit to eV i7j8k9l add: perturb_std=0.02这比翻实验笔记可靠十倍。MAST-ML 不是黑箱,它是你思维的延伸——而 Git 就是它的记忆。
希望帮到你。
本文还有配套的精品资源,点击获取