3步搞定PyG QM9数据集加载:下载报错、依赖降级、目标索引踩坑排查手册
2026/9/6 17:59:55 网站建设 项目流程

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.sdfgdb9.sdf.csvuncharacterized.txt(实现见 torch_geometric/datasets/qm9.py)。父类 InMemoryDataset(一种把处理产物缓存为磁盘二进制文件、加载时整体读入内存的数据集形态)会逐个核对raw_file_names,缺任何一个就重新触发下载。网络中断、代理超时、目录被手动挪动,都会让文件只落下一部分。

解法

  1. 根目录固定用相对路径,如root = 'data/QM9',目录会自动创建;
  2. 网络不稳时,手动下载原始压缩包解压到raw/再运行;
  3. 怀疑缓存损坏时,加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=Trueprocessed/产物会重建
同套方法能用到别的分子数据集吗?可以,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.pyatomrefs字典最快的方式。

【免费下载链接】pytorch_geometricGraph Neural Network Library for PyTorch项目地址: https://gitcode.com/GitHub_Trending/py/pytorch_geometric

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询