3步搞定PyG QM9数据集加载:下载报错、依赖降级、目标索引踩坑排查手册
【免费下载链接】pytorch_geometricGraph Neural Network Library for PyTorch项目地址: https://gitcode.com/GitHub_Trending/py/pytorch_geometric
本文解决 PyTorch Geometric(PyG)加载 QM9 时最常见的三类故障:FileNotFoundError下载缺文件、RDKit 缺失导致的静默降级、以及 DimeNet 预训练场景下的目标属性索引错位。全文按"现象→原因→解法→验证"分诊,文末附一段可直接复制运行的完整训练脚本。
先判断你踩的是哪个坑:30秒自检
| 你看到的报错 / 现象 | 大概率属于哪个环节 |
|---|---|
FileNotFoundError: .../QM9/raw/gdb9.sdf | 下载环节 |
stderr 出现Using a pre-processed version of the dataset | 处理环节 |
| 目标索引越界、loss 明显异常 | 训练环节 |
| GPU 利用率低、dataloader 等待时间长 | 加载环节 |
QM9 收录约 13 万个有机小分子的 19 种量子化学性质,是分子属性回归的标准测试集。PyG 将其封装为QM9类,完整链路分四步:下载 → 处理 → 训练 → 提速。对照上表定位环节后再动手,能少走一半弯路。
环节一:QM9下载目录里找不到 gdb9.sdf 怎么修
现象
FileNotFoundError: [Errno 2] No such file or directory: 'data/QM9/raw/gdb9.sdf'原因
当环境里能 import 到 rdkit 时,QM9 的下载依赖三个文件:gdb9.sdf、gdb9.sdf.csv、uncharacterized.txt(实现见 torch_geometric/datasets/qm9.py)。父类 InMemoryDataset(一种把处理产物缓存为磁盘二进制文件、加载时整体读入内存的数据集形态)会逐个核对raw_file_names,缺任何一个就重新触发下载。网络中断、代理超时、目录被手动挪动,都会让文件只落下一部分。
解法
- 根目录固定用相对路径,如
root = 'data/QM9',目录会自动创建; - 网络不稳时,手动下载原始压缩包解压到
raw/再运行; - 怀疑缓存损坏时,加
force_reload=True强制重走处理流程。
验证:processed/下生成data_v3.pt,且len(dataset)输出 130831。
⚠️ 注意一个容易混淆的细节:没装 RDKit 时检查的文件是qm9_v3.pt而不是gdb9.sdf。所以报gdb9.sdf缺失,说明当时环境里 rdkit 是可导入的。
环节二:RDKit 装不上怎么办,数据会"静默降级"
现象
Using a pre-processed version of the dataset. Please install 'rdkit' ...原因
RDKit 是化学信息学工具包,负责把 SDF 格式的分子文件解析成图结构(节点特征x、边edge_index、3D 坐标pos等)。缺少它时,PyG 自动改下预处理的qm9_v3.zip:功能上仍能训练,但没有 SMILES 等字段,也无法自行复核分子结构。这条分支是"静默降级"——只在 stderr 打一行提示,不仔细看根本发现不了。
解法
pip install rdkit # 或 conda install -c conda-forge rdkit装完后删掉raw/与processed/两个目录(或传force_reload=True),让它重新走原始 SDF 的处理路径。
验证:print(dataset[0].smiles)能打印出 SMILES 字符串即恢复完整版本。
环节三:QM9 目标属性索引错位的处理办法
现象:用 DimeNet 预训练模型评测时,报 target 越界(形如Expected target 7 to be in [0, 11], got 12),或 loss 与论文数值明显对不上。
原因:DimeNet 的预训练权重针对 U0、U、H、G 四个"原子化能"训练。QM9 属性表里它们位于索引 7、8、9、10,而 DimeNet 内部把属性顺序重排成[0,1,2,3,4,5,6,12,13,14,15,11],把热容c_v挪到了末尾。直接用原始编号当目标,取到的就是另一列。
解法
- 推荐走类方法
from_qm9_pretrained,重排和训练/验证/测试划分都在内部完成,参考 examples/qm9_pretrained_dimenet.py、examples/qm9_pretrained_schnet.py; - 手动重排则只需一行索引置换:
import torch idx = torch.tensor([0, 1, 2, 3, 4, 5, 6, 12, 13, 14, 15, 11]) dataset.data.y = dataset.data.y[:, idx]验证:重排后dataset.data.y.shape为 (130831, 12),且第 7 列对应 U0^ATOM。
环节四:13万个分子如何加载得快、训得动
处理完成后 QM9 会一次性整体载入内存(InMemoryDataset 的设计),第二次起加载是秒级。提速重点在 DataLoader 侧:
- 多进程预取:
DataLoader(..., num_workers=4),让数据预处理与 GPU 计算并行; - 按节点数动态分批:分子图大小不均,以"每批总节点数"为预算能让各 step 耗时更均匀,实现见 torch_geometric/loader/dynamic_batch_sampler.py:
from torch_geometric.loader import DataLoader from torch_geometric.loader.dynamic_batch_sampler import DynamicBatchSampler sampler = DynamicBatchSampler(dataset, max_num_nodes=1024, shuffle=True) loader = DataLoader(dataset, batch_sampler=sampler, num_workers=4)- 多路 CPU 服务器:可把 worker 绑定到单路 socket,官方对比实验见 docs/source/advanced/cpu_affinity.rst。
上图是官方在不同 worker 数与亲和性配置下的训练耗时对比:加大 worker 并配置亲和性后,端到端训练时间可缩短约 1.5~1.85 倍。
最小可运行示例
复制即跑,首次运行会自动下载并处理数据:
import os import torch import torch.nn.functional as F from torch_geometric.datasets import QM9 from torch_geometric.loader import DataLoader from torch_geometric.nn import SchNet root = 'data/QM9' dataset = QM9(root) # 自动下载 + 处理,断点可续 print(len(dataset)) # 130831 # 打乱后切分:10w 训练 / 1w 验证 / 2w 测试 dataset = dataset.shuffle() train_ds = dataset[:100000] val_ds = dataset[100000:110000] test_ds = dataset[110000:] loader = DataLoader(train_ds, batch_size=64, shuffle=True, num_workers=4) device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = SchNet(hidden_channels=128, num_filters=128, num_interactions=6, num_gaussians=50).to(device) optimizer = torch.optim.Adam(model.parameters(), lr=1e-3) target = 0 # 预测偶极矩 for epoch in range(1, 5): model.train() for data in loader: data = data.to(device) optimizer.zero_grad() out = model(data.z, data.pos, data.batch) loss = F.mse_loss(out.view(-1), data.y[:, target]) loss.backward() optimizer.step() print(f'epoch {epoch}, loss {loss.item():.4f}')高频问题速查
| 问题 | 答案 |
|---|---|
dataset.atomref(target)是干什么的? | 对原子化能目标(索引 7~10)返回各原子参考能量,用于性质归一化;其他目标返回 None |
| 某性质均值/标准差怎么取? | 直接用dataset.mean(i)/dataset.std(i),源码在 torch_geometric/datasets/qm9.py |
| transform 与 pre_transform 区别? | 前者每次取数据时实时作用;后者只在处理时执行一次并写入磁盘 |
| 想彻底重处理一次? | 传force_reload=True,processed/产物会重建 |
| 同套方法能用到别的分子数据集吗? | 可以,PCQM4M 与 ZINC 逻辑相同:torch_geometric/datasets/pcqm4m.py、torch_geometric/datasets/zinc.py |
进阶方向
- NNConv 分子属性回归示例:examples/qm9_nn_conv.py
- 大分子数据集多卡训练:examples/multi_gpu/pcqm4m_ogb.py
- 模块级文档入口:docs/source/modules
下一步行动建议:跑通上面的最小示例后,把target改成 7,并用dataset.atomref(7)对目标做参考能量校正再训练,对比一下两种设置下 loss 的收敛曲线——这是 QM9 评测前的标准操作,也是读懂qm9.py里atomrefs字典最快的方式。
【免费下载链接】pytorch_geometricGraph Neural Network Library for PyTorch项目地址: https://gitcode.com/GitHub_Trending/py/pytorch_geometric
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考