第 7 周:Scaffold Split 和 GNN 入门

记录 random split 与 scaffold split 的差异,以及从 Morgan Fingerprint 过渡到分子图和简单 GCN baseline 的过程。

2026/6/3
0 分钟阅读

前情提要

正在做一个AI制药平台项目,前端使用vue3、后端采用双后端(主后端Java、SpringBoot做业务,次后端Python、FastAPI做AI服务)

Vue3 前端
  |
  | REST API
  v
SpringBoot 主后端
  |
  | 任务管理 / 数据管理
  v
PostgreSQL + Redis
  |
  | 调用
  v
Python AI Service
  |
  | RDKit / PyTorch / PyG / scikit-learn
  v
模型推理与分子计算

会把自己认为比较重要的部分,单独写成文章以便记录。写这个项目的主要目的是以赛代练,因为不想从头到尾啃生物信息学、生物化学原理这些AI制药理论。通过项目能快速理解核心概念,剩下零零散散的后续慢慢补。

此篇就是第 7 周的记录。

第 7 周:Scaffold Split 和 GNN 入门

第 7 周主要解决两个问题。

第一,前面几周用的 random split 可能太乐观。结构相似的分子可能同时出现在训练集和测试集里,模型看起来泛化得不错,但实际只是记住了相近化学骨架。

第二,Morgan Fingerprint 虽然稳定,但它已经把分子结构压成固定长度 bit vector。进入 GNN 之前,需要把分子重新看成图:原子是节点,化学键是边。

这一周的路线是:

random split vs scaffold split
-> Bemis-Murcko scaffold
-> mol_to_graph
-> simple GCN baseline

random split 的问题

random split 按样本随机划分 train / validation / test。它适合很多机器学习任务,但在分子任务里有一个明显风险:结构非常相似的分子可能被分到不同 split。

这会让测试集变得“不够陌生”。模型在训练集中见过相近骨架后,测试集表现可能很好,但这种表现不一定代表它能泛化到新的化学系列。

在药物研发里,更关心的问题往往不是“同一批相似分子里还能不能预测准”,而是“遇到新骨架时还剩多少预测能力”。这就是 scaffold split 的价值。

scaffold split 更严格

Scaffold split 基于 Bemis-Murcko scaffold 分组。简单说,它按分子的核心骨架划分,而不是按单个分子随机划分。

同一个 scaffold 下的分子会被放到同一个 split 里,避免相似骨架同时出现在训练集和测试集。

这会让测试更难,但也更接近真实泛化。模型如果在 scaffold split 下仍然表现稳定,才更有说服力。

这一周的对比脚本是:

ml-experiments/scaffold_split.py

它输出:

ml-experiments/outputs/scaffold_split_metrics.json
ml-experiments/outputs/scaffold_split_assignments.csv
ml-experiments/outputs/figures/split_comparison_r2.png
ml-experiments/reports/split_comparison.md
models/esol_rf_random_split.pkl
models/esol_rf_scaffold_split.pkl

这组文件的作用是把“为什么 random split 可能过于乐观”从一句判断变成可复现实验。

从 fingerprint 到 molecular graph

Morgan Fingerprint 和 GNN 的差异,本质上是分子表示方式不同。

表示特点
RDKit descriptors低维、人工定义、含义清楚
Morgan Fingerprint固定长度 bit vector,稳定、高效
分子图保留原子和键的连接关系

Fingerprint 已经把结构编码成固定长度向量。GNN 则直接在图上做消息传递,让原子节点从邻居节点和边关系中更新表示。

这一周实现的最小版本 mol_to_graph 主要包含:

  • 原子作为节点
  • 化学键作为边
  • 节点特征
  • 边索引
  • 图级标签

这一步的价值不是立刻拿到高分,而是把输入从表格特征切换成图数据。

simple GCN baseline

GNN 部分先跑一个简单 GCN baseline:

ml-experiments/simple_gnn_baseline.py

输出文件包括:

models/esol_simple_gcn.pt
ml-experiments/outputs/simple_gnn_metrics.json
ml-experiments/outputs/simple_gnn_predictions.csv
ml-experiments/outputs/simple_gnn_training_log.csv
ml-experiments/outputs/figures/simple_gnn_loss_curve.png
ml-experiments/outputs/figures/simple_gnn_pred_vs_actual.png
ml-experiments/reports/simple_gnn_report.md

这版 GCN 只负责跑通图模型训练、评估、保存和报告流程。它不承担“超过所有 baseline”的压力。对项目来说,先把分子图数据结构、PyTorch Geometric 数据流、图级回归流程接起来,比追求一个漂亮分数更重要。

这一周改变了评估视角

第 4 周和第 5 周更多是在比较模型:RandomForest、MLP、不同特征。第 7 周开始,评估方式本身也变成了实验对象。

如果 random split 分数高,而 scaffold split 分数明显下降,这不是坏事。它说明模型在新骨架上的泛化能力有限,也说明之前的 random split 可能给了过于乐观的判断。

这类结论比单纯展示一个模型更接近 AI 制药工程里真实的问题:数据划分、化学空间、泛化边界,都会影响模型是否可信。

第 7 周结束后,项目里已经有三类输入表示:

RDKit descriptors
Morgan Fingerprint
molecular graph

也有两类评估划分:

random split
scaffold split

后续无论接 DTI、ADMET 扩展,还是把模型封装成推理 API,都可以基于这套更严肃的评估框架继续推进。