使用 PyTorch Geometric (PyG) 和 Material Project API (MP API),结合深度学习技术预测材料的性能。选择预测材料的带隙(band gap) 作为任务,带隙是材料的一个关键性能,影响其导电性和光学性质。通过这个案例,可以将掌握从数据获取到模型预测的完整流程,并理解深度学习在材料科学中的作用。
1. 案例背景
-
Material Project API (MP API): Materials Project 是一个开放的材料数据库,提供了丰富的晶体结构和性能数据。通过其 API,我们可以轻松获取这些数据,用于训练和测试模型。
-
PyTorch Geometric (PyG): PyG 是一个基于 PyTorch 的图神经网络(GNN)库,特别适合处理图结构数据。在材料科学中,晶体结构可以表示为图(原子为节点,化学键为边),PyG 是实现性能预测的理想工具。
-
任务: 使用 MP API 获取材料数据,结合 PyG 构建 GNN 模型,预测材料的带隙。
2. 环境准备
在开始之前,请确保安装以下 Python 库:
bash
pip install mp_api pymatgen torch torch-geometric
-
mp_api: 用于访问 Materials Project 数据库。
-
pymatgen: 用于处理晶体结构数据。
-
torch: PyTorch 深度学习框架。
-
torch-geometric: PyTorch Geometric,处理图神经网络。
此外,你需要从 Materials Project 官网 注册并获取一个 API 密钥,将其保存以供后续使用。
3. 数据获取
我们将使用 MP API 获取一组材料的晶体结构和带隙数据。这里以 10 种材料为例。
python
from mp_api.client import MPRester# 替换为你的 API 密钥
API_KEY = "your_api_key"# 使用 MPRester 获取数据
with MPRester(API_KEY) as mpr:# 查询 10 种材料的结构和带隙materials = mpr.materials.summary.search(fields=["material_id", "structure", "band_gap"],num_elements=(1, 5), # 限制元素数量以简化limit=10 # 获取 10 种材料)# 提取材料 ID、结构和带隙
material_ids = [mat.material_id for mat in materials]
structures = [mat.structure for mat in materials]
band_gaps = [mat.band_gap for mat in materials]# 输出验证
for mid, bg in zip(material_ids, band_gaps):print(f"Material ID: {mid}, Band Gap: {bg} eV")
说明:
-
MPRester 是 MP API 的客户端工具,用于查询数据。
-
search 方法指定了返回字段(material_id、structure、band_gap),并限制了元素数量和返回数量。
-
我们获取了每种材料的 ID、晶体结构和带隙值。
4. 数据预处理:将晶体结构转换为图数据
晶体结构可以表示为图,原子作为节点,化学键作为边。我们需要将晶体结构转换为 PyG 可用的图数据格式。
python
from pymatgen.core import Structure
from torch_geometric.data import Data
import torchdef structure_to_graph(structure: Structure, cutoff: float = 4.0):"""将晶体结构转换为图数据。参数:structure: pymatgen 的 Structure 对象cutoff: 边距离阈值(Å)返回:Data: PyG 的图数据对象"""# 节点特征:原子序数atomic_numbers = [site.specie.number for site in structure.sites]x = torch.tensor(atomic_numbers, dtype=torch.float).view(-1, 1)# 获取所有原子对的距离(考虑周期性边界)all_neighbors = structure.get_all_neighbors(cutoff, include_index=True)edge_index = []edge_attr = []for i, neighbors in enumerate(all_neighbors):for neighbor in neighbors:j = neighbor[2] # 邻居原子的索引dist = neighbor[1] # 距离edge_index.append([i, j])edge_attr.append(dist)# 转换为 tensoredge_index = torch.tensor(edge_index, dtype=torch.long).t().contiguous()edge_attr = torch.tensor(edge_attr, dtype=torch.float).view(-1, 1)return Data(x=x, edge_index=edge_index, edge_attr=edge_attr)# 将所有结构转换为图数据
graph_data_list = [structure_to_graph(struct) for struct in structures]# 为每个图数据添加带隙标签
for data, bg in zip(graph_data_list, band_gaps):data.y = torch.tensor([bg], dtype=torch.float)
说明:
-
structure_to_graph 函数将晶体结构转换为图:
-
节点特征 (x): 使用原子的原子序数作为特征。
-
边索引 (edge_index): 表示原子之间的连接。
-
边特征 (edge_attr): 使用原子间距离作为特征。
-
-
get_all_neighbors 获取指定距离(cutoff)内的邻居原子,考虑周期性边界。
-
每个图数据对象 Data 包含节点特征、边索引、边特征和带隙标签 y。
5. 构建图神经网络(GNN)模型
我们使用 PyG 构建一个简单的 GNN 模型来预测带隙。
python
import torch.nn as nn
from torch_geometric.nn import GCNConv, global_mean_poolclass BandGapPredictor(nn.Module):def __init__(self, num_features: int, hidden_channels: int):super().__init__()self.conv1 = GCNConv(num_features, hidden_channels)self.conv2 = GCNConv(hidden_channels, hidden_channels)self.lin = nn.Linear(hidden_channels, 1)def forward(self, data):x, edge_index, batch = data.x, data.edge_index, data.batchx = self.conv1(x, edge_index).relu()x = self.conv2(x, edge_index).relu()x = global_mean_pool(x, batch) # 全局平均池化return self.lin(x)
说明:
-
GCNConv: 图卷积层,用于学习节点间的特征交互。
-
global_mean_pool: 将所有节点的嵌入聚合为图级嵌入。
-
模型包含两层图卷积和一个线性层,最终输出带隙预测值。
6. 数据集划分和训练准备
将数据划分为训练集和测试集,并创建数据加载器。
python
from torch_geometric.data import DataLoader# 划分训练集和测试集(80% 训练,20% 测试)
train_data = graph_data_list[:8]
test_data = graph_data_list[8:]# 创建数据加载器
train_loader = DataLoader(train_data, batch_size=2, shuffle=True)
test_loader = DataLoader(test_data, batch_size=2, shuffle=False)
说明:
-
DataLoader 用于批量加载图数据。
-
batch_size=2 表示每个批次包含 2 个图。
7. 模型训练
训练模型以最小化预测带隙和实际带隙之间的均方误差。
python
# 初始化模型、优化器和损失函数
model = BandGapPredictor(num_features=1, hidden_channels=32)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
criterion = nn.MSELoss()# 训练函数
def train():model.train()total_loss = 0for data in train_loader:optimizer.zero_grad()out = model(data)loss = criterion(out, data.y.view(-1, 1))loss.backward()optimizer.step()total_loss += loss.item()return total_loss / len(train_loader)# 训练模型
for epoch in range(50):loss = train()if (epoch + 1) % 10 == 0:print(f"Epoch {epoch+1}, Loss: {loss:.4f}")
说明:
-
使用 Adam 优化器和均方误差(MSE)损失函数。
-
训练 50 个周期,每 10 个周期输出一次损失。
8. 模型评估
在测试集上评估模型的性能。
python
def test(loader):model.eval()total_error = 0with torch.no_grad():for data in loader:out = model(data)error = torch.abs(out - data.y.view(-1, 1)).sum().item()total_error += errorreturn total_error / len(loader.dataset)# 测试模型
test_error = test(test_loader)
print(f"Test MAE: {test_error:.4f} eV")
说明:
-
test 函数计算平均绝对误差(MAE)。
-
model.eval() 切换到评估模式,torch.no_grad() 关闭梯度计算。
9. 预测新材料的带隙
使用训练好的模型预测一个新材料的带隙。
python
# 获取一个新材料(例如 mp-150)
with MPRester(API_KEY) as mpr:new_material = mpr.materials.summary.search(material_ids=["mp-150"], fields=["structure"])
new_structure = new_material[0].structure# 转换为图数据
new_data = structure_to_graph(new_structure)# 预测
model.eval()
with torch.no_grad():prediction = model(new_data)
print(f"Predicted band gap for mp-150: {prediction.item():.4f} eV")
说明:
-
获取新材料的晶体结构并转换为图数据。
-
使用训练好的模型预测带隙并输出结果。
10. 总结与深度学习的意义
通过这个案例,我们完成了从数据获取到模型预测的完整流程:
-
使用 MP API 获取材料数据。
-
将晶体结构转换为图数据。
-
构建并训练 GNN 模型。
-
评估模型并预测新材料的带隙。
深度学习在材料性能预测中的作用:
-
自动化特征提取: GNN 可以从晶体结构中自动提取特征,避免手动设计复杂的描述符。
-
高效预测: 训练好的模型可以快速预测新材料的性能,加速材料筛选和设计。
-
广泛适用性: 该方法可扩展到其他性能预测任务(如弹性模量、热导率等),适用于大规模数据集。