Repository: https://github.com/snap-stanford/pretrain-gnns Stars: 1067 | Forks: 174 | Language: Python | License: MIT 論文: Hu, Liu, Gomes, Zitnik, Liang, Pande, Leskovec. Strategies for Pre-training Graph Neural Networks. ICLR 2020. arXiv:1905.12265 | OpenReview


1. 專案概覽 (Project Overview)

1.1 背景與團隊

pretrain-gnns 是史丹佛大學 SNAP(Stanford Network Analysis Project)實驗室在 2020 年 ICLR 發表的代表作之一,作者群包含 Jure Leskovec(圖神經網路領域重量級學者,也是 GraphSAGE、OGB(Open Graph Benchmark) 的主要推動者)與 Marinka Zitnik(生醫圖學習專家)。這篇論文回答的核心問題是:

圖神經網路 (Graph Neural Network; GNN) 能不能像 BERT 在 NLP、ImageNet 預訓練在 CV 一樣,透過「預訓練 + 微調 (pre-training + fine-tuning)」的範式獲益?

在 2019 年之前,圖學習領域普遍認為 GNN 難以受益於預訓練,甚至有實驗顯示「naive 的預訓練策略」會導致負遷移 (negative transfer; 負向遷移)——即預訓練後在下游任務上表現反而變差。這篇論文系統性地拆解了失敗原因,並提出一套組合式的預訓練策略,首次在分子性質預測與蛋白質功能預測任務上證明了 GNN 預訓練的普遍有效性。

1.2 解決的問題

GNN 在真實世界應用(藥物發現、材料科學、生物網路分析)中最大的痛點是標註資料稀缺:一個下游任務(例如「這個分子是否有毒性」)往往只有幾百到幾千筆標註樣本,而 GNN 動輒有數十萬參數,極易過擬合 (overfitting; 過度配適)。

論文的核心洞察是:只做「節點層級」或只做「圖層級」的預訓練都不夠——

  • 只做節點層級 (node-level) 自監督:模型學會了局部結構模式(例如「碳原子旁邊常接氫」),但沒有學到「整個圖代表什麼」的全域語義,遷移到圖分類任務時效果有限,甚至因為學到的表徵在圖層級空間中分佈與下游任務不匹配而發生負遷移
  • 只做圖層級 (graph-level) 監督式預訓練(直接用大量弱標註做多任務分類):模型學到的是「與預訓練標籤相關」的捷徑特徵,泛化到全新的下游標籤集合時效果同樣有限。

因此論文提出:先做節點層級的自監督預訓練,再疊加圖層級的監督式預訓練,兩者順序組合才能穩定帶來正遷移。

1.3 為什麼重要

  1. 首次系統性驗證 GNN 預訓練有效性:在 2020 年之前,“GNN + pretraining” 幾乎是空白領域;本文的 8 個下游分子任務 + 40+ 蛋白質功能預測任務的大規模實驗,讓後續整個「圖基礎模型 (graph foundation model)」研究方向有了可信的起點。
  2. 提出可組合的自監督任務集合:Context Prediction、Attribute Masking、Edge Prediction、(Supervised) 四種策略可以任意組合疊加,成為後續大量圖預訓練論文(GraphCL、GPT-GNN、MGSSL 等)的 baseline 與設計參考。
  3. 開源完整的 pre-trained checkpointmodel_gin/model_architecture/ 目錄下釋出了 GIN/GCN/GAT/GraphSAGE 四種骨幹網路 × 多種預訓練策略組合的權重,讓後續研究者可以「直接載入權重做微調」而不必重新跑昂貴的大規模預訓練(化學資料集 2.5GB、生物資料集 2GB)。

1.4 在 snap-stanford 生態系中的定位

pretrain-gnns 與 SNAP 實驗室其他知名專案密切相關:

  • PyTorch Geometric (PyG):本專案直接建構在 torch_geometric 之上(MessagePassing 基類、global_add_pool 等),是 PyG 生態系中「預訓練範式」的早期範例應用。
  • Open Graph Benchmark (OGB):OGB 的分子性質預測任務(ogbg-molhiv 等)大量沿用本專案的資料處理管線(loader.pymol_to_graph_data_obj_simple)與圖表徵設計(num_atom_type = 120)。
  • GraphSAGE / node2vec 系列:本專案的其中一種預訓練策略(Context Prediction)在概念上呼應 SNAP 早期 node2vec / GraphSAGE 對「鄰域上下文」的建模思路,只是從 embedding 表格轉移到端到端 GNN 訓練。

2. 核心架構 (Core Architecture)

2.1 系統架構圖


flowchart TB
    subgraph sg1["資料層 Data Layer"]
        A1["分子資料集 chem/loader.py
SMILES → RDKit Mol → Graph"] A2["蛋白質資料集 bio/loader.py
PPI 網路 → Subgraph"] end subgraph sg2["GNN 骨幹層 Backbone Layer"] B1["GNN 基類 (model.py)"] B2["GINConv"] B3["GCNConv"] B4["GATConv"] B5["GraphSAGEConv"] B1 --> B2 B1 --> B3 B1 --> B4 B1 --> B5 end subgraph sg3["節點層級自監督 Node-level SSL"] C1["Attribute Masking
pretrain_masking.py"] C2["Context Prediction
pretrain_contextpred.py"] C3["Edge Prediction
pretrain_edgepred.py"] C4["Deep Graph Infomax
pretrain_deepgraphinfomax.py"] end subgraph sg4["圖層級監督式預訓練 Graph-level Supervised"] D1["Multi-task 分類
pretrain_supervised.py"] end subgraph sg5["下游微調 Downstream Fine-tuning"] E1["GNN_graphpred
finetune.py"] E2["下游任務:Tox21 / HIV / BBBP
/ BACE / PPI 功能預測 等"] end A1 --> B1 A2 --> B1 B1 --> C1 B1 --> C2 B1 --> C3 B1 --> C4 C1 --> D1 C2 --> D1 C3 --> D1 C4 --> D1 D1 -->|"儲存權重 OUTPUT_MODEL_FILE"| E1 C1 -->|"或直接載入"| E1 E1 --> E2

2.2 關鍵模組說明

模組檔案角色
GNNchem/model.py / bio/model.py骨幹網路基類,內部堆疊 num_layer 層訊息傳遞 (message passing),支援 4 種 GNN 變體
GINConvmodel.pyGraph Isomorphism Network 卷積層,理論上表達力等同 Weisfeiler-Lehman 測試,本專案的預設骨幹
GCNConv / GATConv / GraphSAGEConvmodel.py另外三種可替換骨幹,用於消融實驗 (ablation study; 消融研究) 比較不同 GNN 架構對預訓練效果的敏感度
GNN_graphpredmodel.pyGNN 之上加一層 pooling(sum/mean/max/attention/set2set)+ 線性分類頭,用於下游微調
MoleculeDatasetchem/loader.py繼承 PyG InMemoryDataset,把 SMILES 字串轉換成圖物件(節點=原子、邊=化學鍵)
BioDatasetbio/loader.py把蛋白質-蛋白質交互作用 (PPI) 網路轉換成以「自我網路 (ego-network)」為單位的圖物件
ExtractSubstructureContextPair / MaskAtom / NegativeEdgeutil.py三種自監督任務的資料變換 (data transform),在 DataLoader 階段動態產生訓練標籤
scaffold_splitsplitters.py化學分子專用的資料切分方法,依據 Bemis-Murcko scaffold(分子骨架)切分,避免結構相似分子同時出現在訓練/測試集造成資訊洩漏

2.3 資料流


flowchart LR
    A["原始資料
SMILES 字串 / PPI 邊列表"] --> B["Graph 物件建構
x=[num_nodes,2] 節點特徵
edge_index=[2,num_edges]
edge_attr=[num_edges,2]"] B --> C["自監督 Transform
(訓練時動態套用)"] C --> D["MoleculeDataset / BioDataset
(PyG InMemoryDataset)"] D --> E["DataLoader 批次組裝
batch.x / batch.edge_index
/ batch.batch"] E --> F["GNN 前向傳播
node_rep = model(x, edge_index, edge_attr)"] F --> G1["節點層級 loss
(masking/context/edge)"] F --> G2["Pooling → 圖層級表徵
graph_rep"] G2 --> H["監督式 loss
(多任務分類/回歸)"]

2.4 設計哲學與技術選擇分析

  1. 為何選 GIN 作為主力骨幹? GIN(Graph Isomorphism Network)在理論上被證明擁有與 Weisfeiler-Lehman 圖同構測試相同的判別能力上限,是目前已知表達力最強的訊息傳遞 GNN 之一,因此作者將其作為主實驗骨幹,其餘三種(GCN/GAT/GraphSAGE)作為消融比較。
  2. 邊特徵嵌入的一致設計:所有卷積層(GIN/GCN/GAT/GraphSAGE)在 forward() 中都有一段幾乎相同的程式碼:加自環 (self-loop) → 補上自環對應的邊特徵 (self_loop_attr[:,0]=4) → 邊嵌入相加。這是刻意的一致性設計:確保四種骨幹在「如何處理化學鍵資訊」這件事上完全公平比較,差異只來自訊息聚合方式本身。
  3. forward(*argv) 的彈性介面GNN.forward 同時支援 forward(x, edge_index, edge_attr)forward(data) 兩種呼叫方式,這是典型的 Pythonic 相容性設計,方便在不同的呼叫情境(單獨呼叫 vs. PyG DataLoader 自動組裝的 batch 物件)下重用同一個模型。
  4. 自監督任務以「資料變換」而非「額外模型」實作ExtractSubstructureContextPairMaskAtomNegativeEdge 都是作用在單一 Data 物件上的 transform function,套用在 dataset.transform 參數上。這種設計把「如何生成自監督標籤」的邏輯與「如何訓練模型」解耦,符合 PyG 的慣例,也讓後續要新增第五種自監督任務時,只需要新寫一個 transform class,不需要碰核心訓練迴圈。

3. 安裝與設定 (Installation & Setup)

3.1 環境需求

原始 README 標註的官方測試環境(注意:這是 2019 年的版本組合,年代久遠,建議搭配下方「現代化替代方案」):

 1Python                    3.7
 2pytorch                   1.0.1
 3torch-geometric           1.0.3
 4torch-cluster             1.2.4
 5torch-scatter             1.1.2
 6torch-sparse              0.2.4
 7torch-spline-conv         1.0.6
 8rdkit                     2019.03.1.0
 9tqdm                      4.31.1
10tensorboardx              1.6

GPU 非必要但強烈建議——化學資料集規模達 200 萬+分子圖,CPU 訓練預訓練階段可能需要數天。

3.2 完整安裝步驟(依循全域規範:Python 用 uv,禁止把 pip 當主要安裝方式)

⚠️ 版本相容性提醒torch_geometric==1.0.3 是 2019 年的極舊版本,新版 PyG(2.x)API 已大幅變動(例如 MessagePassing.propagate 的呼叫簽名)。若要在現代環境重跑,建議兩條路線二選一:

路線 A:完整還原原始環境(適合精確重現論文數值)

 1# 用 uv 建立獨立虛擬環境,鎖定舊版 Python
 2uv venv --python 3.7 .venv-pretrain-gnns
 3source .venv-pretrain-gnns/bin/activate
 4
 5# rdkit 建議透過 conda-forge 取得(pip 版 rdkit 對舊版 Python 支援不穩定)
 6# 若環境許可,退而求其次:
 7uv pip install torch==1.0.1
 8uv pip install torch-geometric==1.0.3 torch-scatter==1.1.2 torch-sparse==0.2.4 \
 9               torch-cluster==1.2.4 torch-spline-conv==1.0.6
10uv pip install tqdm==4.31.1 tensorboardx==1.6 scikit-learn pandas

路線 B:移植到現代 PyG(適合實際拿來做新研究,推薦)

1uv venv --python 3.11 .venv-pretrain-gnns-modern
2source .venv-pretrain-gnns-modern/bin/activate
3
4uv pip install torch --index-url https://download.pytorch.org/whl/cpu   # 或對應 CUDA 版本
5uv pip install torch_geometric
6uv pip install rdkit tqdm scikit-learn pandas tensorboardX

使用路線 B 時,model.py 中的 self.propagate(self.aggr, edge_index, x=x, edge_attr=edge_embeddings) 需要改寫為現代 PyG 語法 self.propagate(edge_index, x=x, edge_attr=edge_embeddings)aggr 改在 __init__super().__init__(aggr=aggr) 設定),這是最主要的 API 差異點。

3.3 資料集下載與準備

1# 化學資料集(分子性質預測,2.5GB)
2wget https://snap.stanford.edu/gnn-pretrain/data/chem_dataset.zip
3unzip chem_dataset.zip -d chem/
4
5# 生物資料集(蛋白質功能預測,2GB)
6wget https://snap.stanford.edu/gnn-pretrain/data/bio_dataset.zip
7unzip bio_dataset.zip -d bio/

解壓後目錄結構大致如下:

1chem/
2  dataset/
3    tox21/
4      raw/
5      processed/
6    hiv/
7    bace/
8    bbbp/
9    ...(8 個下游任務資料集 + 預訓練用的 zinc_standard_agent)

3.4 常見問題排解

症狀原因解法
ImportError: cannot import name 'scatter_' from torch_scatter新版 torch_scatter 移除了舊 API改用 scatter_add/scatter_mean 等新函式名,或鎖定 torch_scatter==1.1.2
RDKit 找不到分子 / SMILES 解析失敗資料集中含有 RDKit 無法解析的邊界化合物loader.py 已內建過濾機制,若自訂資料集需自行加 Chem.MolFromSmiles(smiles) is not None 檢查
GPU OOM (顯存不足)batch_size 太大或分子圖節點數過多(大分子如蛋白質配體)降低 --batch_size(預設常見為 32~256),或改用梯度累積
微調結果與論文差異大scaffold_split 對隨機種子敏感用官方腳本 finetune_tune.sh SEED DEVICE 跑 0~9 十個種子取平均,這是論文報告數值的方式
tensorboardX 版本衝突舊版 API 與新版 PyTorch 內建 torch.utils.tensorboard 有命名空間重疊若不需要視覺化,可直接註解掉 SummaryWriter 相關程式碼

4. 核心概念詳解 (Key Concepts)

4.1 為什麼「只做一種」預訓練會失敗?

用一個類比理解:假設你要訓練一個新進醫生。

  • 只教「局部觀察」(節點層級自監督):你讓他反覆練習「看到某個症狀該聯想到哪個器官」,他會變成很會做局部推理的專家,但從沒被訓練過「綜合病人所有症狀,判斷整體診斷」的能力——這對應論文中「只用節點層級 SSL,圖層級表徵沒有被有效組織」的問題。
  • 只教「死記診斷結果」(圖層級監督式預訓練,用大量弱標籤):你讓他背誦「這些症狀組合 = 這個病名」,但只背了幾種常見病,遇到訓練時沒出現過的新病種(新的下游任務標籤),他完全無法舉一反三——這對應論文中「純監督式預訓練會過擬合預訓練標籤本身、缺乏可遷移的表徵結構」的問題。
  • 本文方案:先學局部觀察,再疊加綜合診斷訓練:先讓醫生扎實掌握局部症狀-器官的關聯(節點層級 SSL 打好底層表徵基礎),再在此基礎上做多種疾病的綜合診斷訓練(圖層級監督式預訓練,此時圖層級表徵是建立在已經良好組織的節點表徵之上),兩階段疊加才能讓他面對全新病例時依然可靠——這正是論文的核心結論:Node-level SSL 打底 + Graph-level supervised 疊加,才能穩定帶來正遷移

flowchart TB
    X["隨機初始化 GNN"] -->|"Stage 1: 節點層級自監督"| Y["表徵已具備
局部結構語義"] Y -->|"Stage 2: 圖層級監督式(可選)"| Z["表徵同時具備
局部 + 全域語義"] Z -->|"Stage 3: 下游微調"| W["下游任務
(強遷移、抗過擬合)"] X -.->|"❌ 跳過 Stage 1
直接圖層級監督"| Z2["表徵過擬合
預訓練標籤本身"] Z2 -.->|"下游微調"| W2["❌ 負遷移風險高"]

4.2 四種節點層級自監督任務

任務直覺類比實作核心
Attribute Masking (屬性遮罩)類似 BERT 的 masked language modeling:把句子中某些字挖空讓模型猜隨機遮住部分原子/化學鍵的屬性,讓 GNN 根據鄰居結構預測被遮住的原子種類或鍵種類(MaskAtom in util.py
Context Prediction (上下文預測)類似 word2vec 的 skip-gram:用「這個詞的上下文」判斷這個詞是否合理對每個節點抽取「以它為中心的 k-hop 子結構」與「更外圍的上下文子結構」,訓練模型判斷兩者是否來自同一個節點(ExtractSubstructureContextPair
Edge Prediction (邊預測)類似連結預測 (link prediction):給兩個節點,判斷它們之間該不該有邊隨機採樣「負邊」(原圖中不存在的節點對),訓練模型分辨真實邊與負採樣邊(NegativeEdge
Deep Graph Infomax (深度圖互資訊)類似對比學習:讓「整張圖的摘要向量」與「屬於這張圖的節點」互資訊最大化,與「不屬於這張圖的節點」互資訊最小化對比局部節點表徵與全域圖表徵,是一種圖層級的自監督對比學習 (contrastive learning)

4.3 分子圖的表示方式

分子 (SMILES 字串) 被轉換成標準的 PyG Data 物件:

  • 節點特徵 xshape=[num_atoms, 2],兩個維度分別是「原子類型」(num_atom_type=120,涵蓋所有常見元素 + mask token) 與「手性標籤」(num_chirality_tag=3)。
  • 邊索引 edge_indexshape=[2, num_bonds*2](無向圖以雙向邊儲存)。
  • 邊特徵 edge_attrshape=[num_bonds*2, 2],兩維分別是「化學鍵類型」(num_bond_type=6,含芳香鍵、自環、mask token) 與「鍵方向」(num_bond_direction=3)。

flowchart LR
    subgraph mol["分子 CCO (乙醇)"]
        C1["C 原子
node_id=0"] -- "單鍵" --> C2["C 原子
node_id=1"] C2 -- "單鍵" --> O1["O 原子
node_id=2"] end mol --> G["Graph 物件
x=[3,2], edge_index=[2,4]
(雙向), edge_attr=[4,2]"]

4.4 Scaffold Split:為什麼不能隨機切分資料集?

化學分子的隨機切分會造成「資訊洩漏」:結構高度相似的分子(例如同一藥物家族的衍生物)可能同時分散在訓練集與測試集,模型只需要記住「這個骨架的分子通常有毒/無毒」就能在測試集上取得虛高的準確率,卻無法真正泛化到全新骨架的分子。scaffold_split(在 splitters.py)依照 Bemis-Murcko 骨架分組後再切分,確保訓練集與測試集的分子骨架互不重疊,這是分子性質預測領域公認更嚴謹、更貼近真實藥物發現場景的評估方式。


5. 使用方式與程式碼範例 (Usage & Code Examples)

5.1 基礎用法:自監督預訓練(Attribute Masking)

 1cd chem/
 2python pretrain_masking.py \
 3    --output_model_file ./saved_model/masking_pretrained \
 4    --num_layer 5 \
 5    --emb_dim 300 \
 6    --dropout_ratio 0.5 \
 7    --mask_rate 0.15 \
 8    --mask_edge 1 \
 9    --gnn_type gin \
10    --batch_size 256 \
11    --epochs 100 \
12    --device 0

底層對應的訓練邏輯(節錄自 pretrain_masking.py,已簡化並加上中文註解):

 1def train(args, model_list, loader, optimizer_list, device):
 2    model, linear_pred_atoms, linear_pred_bonds = model_list
 3    optimizer_model, optimizer_linear_pred_atoms, optimizer_linear_pred_bonds = optimizer_list
 4
 5    model.train()
 6    for step, batch in enumerate(tqdm(loader, desc="Iteration")):
 7        batch = batch.to(device)
 8        # 前向傳播:拿到每個節點(含被遮罩的節點)的表徵
 9        node_rep = model(batch.x, batch.edge_index, batch.edge_attr)
10
11        # 只在「被遮罩的節點」位置計算分類 loss,預測被遮住的原子種類
12        pred_node = linear_pred_atoms(node_rep[batch.masked_atom_indices])
13        loss = criterion(pred_node.double(), batch.mask_node_label[:, 0])
14
15        if args.mask_edge:
16            # 邊層級遮罩:同時預測被遮住的化學鍵種類
17            masked_edge_index = batch.edge_index[:, batch.connected_edge_indices]
18            edge_rep = node_rep[masked_edge_index[0]] + node_rep[masked_edge_index[1]]
19            pred_edge = linear_pred_bonds(edge_rep)
20            loss += criterion(pred_edge.double(), batch.mask_edge_label[:, 0])
21
22        optimizer_model.zero_grad()
23        loss.backward()
24        optimizer_model.step()

5.2 進階用法:疊加圖層級監督式預訓練

1# Stage 1 的輸出接續做 Stage 2 監督式預訓練
2python pretrain_supervised.py \
3    --input_model_file ./saved_model/masking_pretrained.pth \
4    --output_model_file ./saved_model/masking_supervised_pretrained \
5    --num_layer 5 --emb_dim 300 --gnn_type gin --device 0

5.3 下游微調與評估

1python finetune.py \
2    --model_file ./saved_model/masking_supervised_pretrained.pth \
3    --dataset bbbp \
4    --filename result_bbbp.txt \
5    --num_layer 5 --emb_dim 300 --gnn_type gin \
6    --lr 0.001 --batch_size 32 --epochs 100 \
7    --split scaffold --device 0

微調階段的模型定義使用 GNN_graphpred(節錄自 model.py,加上中文說明):

 1class GNN_graphpred(torch.nn.Module):
 2    """
 3    在 GNN 骨幹之上加一個 pooling 層 + 線性分類頭,
 4    用於圖層級的下游任務(分子性質分類/回歸)。
 5    """
 6    def __init__(self, num_layer, emb_dim, num_tasks, JK="last",
 7                 drop_ratio=0, graph_pooling="mean", gnn_type="gin"):
 8        super(GNN_graphpred, self).__init__()
 9        self.gnn = GNN(num_layer, emb_dim, JK, drop_ratio, gnn_type=gnn_type)
10
11        if graph_pooling == "sum":
12            self.pool = global_add_pool
13        elif graph_pooling == "mean":
14            self.pool = global_mean_pool
15        elif graph_pooling == "max":
16            self.pool = global_max_pool
17        # ... 亦支援 attention / set2set pooling
18
19        self.graph_pred_linear = torch.nn.Linear(emb_dim, num_tasks)
20
21    def from_pretrained(self, model_file):
22        # 這是本專案最關鍵的「遷移」入口:載入預訓練好的骨幹權重
23        self.gnn.load_state_dict(torch.load(model_file))
24
25    def forward(self, x, edge_index, edge_attr, batch):
26        node_representation = self.gnn(x, edge_index, edge_attr)
27        graph_representation = self.pool(node_representation, batch)
28        return self.graph_pred_linear(graph_representation)

完整可執行的微調範例(濃縮自 finetune.py,展示端到端流程):

 1import torch
 2from torch_geometric.data import DataLoader
 3from loader import MoleculeDataset
 4from model import GNN_graphpred
 5from splitters import scaffold_split
 6import pandas as pd
 7
 8# 1. 讀取資料集並依骨架切分
 9dataset = MoleculeDataset("dataset/bbbp", dataset="bbbp")
10smiles_list = pd.read_csv("dataset/bbbp/processed/smiles.csv", header=None)[0].tolist()
11train_dataset, valid_dataset, test_dataset = scaffold_split(
12    dataset, smiles_list, null_value=0, frac_train=0.8, frac_valid=0.1, frac_test=0.1
13)
14
15train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
16
17# 2. 建立模型並載入預訓練權重
18model = GNN_graphpred(num_layer=5, emb_dim=300, num_tasks=1,
19                       JK="last", drop_ratio=0.5, graph_pooling="mean", gnn_type="gin")
20model.from_pretrained("./saved_model/masking_supervised_pretrained.pth")
21model = model.to("cuda:0")
22
23# 3. 標準的分類微調迴圈
24optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=0)
25criterion = torch.nn.BCEWithLogitsLoss(reduction="none")
26
27for epoch in range(100):
28    model.train()
29    for batch in train_loader:
30        batch = batch.to("cuda:0")
31        pred = model(batch.x, batch.edge_index, batch.edge_attr, batch.batch)
32        y = batch.y.view(pred.shape).to(torch.float64)
33        is_valid = y ** 2 > 0
34        loss_mat = criterion(pred.double(), (y + 1) / 2)
35        loss_mat = torch.where(is_valid, loss_mat, torch.zeros_like(loss_mat))
36        loss = torch.sum(loss_mat) / torch.sum(is_valid)
37
38        optimizer.zero_grad()
39        loss.backward()
40        optimizer.step()

6. 進階應用場景 (Advanced Use Cases)

6.1 真實世界應用案例

  1. 藥物發現前期篩選 (drug discovery virtual screening)chem/ 下的 8 個下游任務(Tox21、ToxCast、SIDER、ClinTox、MUV、HIV、BACE、BBBP)都是真實的藥物性質預測基準,涵蓋毒性、副作用、血腦屏障穿透性等;藥廠或生技團隊可以直接借用預訓練權重做「新化合物庫」的快速虛擬篩選前處理。
  2. 蛋白質功能預測 (protein function prediction)bio/ 資料集基於 PPI 網路,預訓練後的骨幹可微調用於預測基因本體論 (Gene Ontology; GO) 功能標籤,是蛋白質組學研究中「少樣本學習」情境的實用工具。
  3. 材料科學性質預測:雖然本專案聚焦分子/蛋白質,但其「圖預訓練」範式已被後續工作(如 MatBERT、CGCNN 系列)借鏡,套用到晶體材料的性質預測。

6.2 與其他 snap-stanford 工具的整合


flowchart LR
    A["pretrain-gnns
預訓練骨幹權重"] --> B["Open Graph Benchmark (OGB)
標準化評測榜單"] A --> C["PyTorch Geometric
底層框架"] D["node2vec / GraphSAGE
(SNAP 早期表徵學習)"] -.->|"概念延伸"| A A --> E["下游 GNN 研究
(GraphCL/GPT-GNN 等後續工作)"]
  • 可以把 model_gin/contextpred.pth 等預訓練權重直接餵給任何基於 PyG 撰寫的下游 GNN 專案,只要骨幹超參數(num_layer, emb_dim, gnn_type)一致即可 load_state_dict
  • OGB 的 ogbg-molhivogbg-molpcba 等任務可直接沿用本專案的 MoleculeDataset 資料處理邏輯做前處理對齊。

6.3 效能調校與最佳實踐

  • num_layer 建議 3-5 層:論文消融實驗顯示 GNN 層數過深(>5 層)會有 over-smoothing(過度平滑)問題,反而傷害下游表現。
  • JK(Jumping Knowledge)策略選擇concat 通常比單純 last 更穩健,因為它保留了不同深度層的中間表徵,緩解過度平滑。
  • 多種子平均是必要的finetune_tune.sh SEED DEVICE 跑 0~9 共 10 個隨機種子取平均 ROC-AUC,單一種子的結果波動可能達到 ±2-3%,不能只看單次結果下結論。
  • 先做 Attribute Masking 再疊加 Supervised:論文報告的最佳組合通常是 maskingcontextpred 疊加 supervised,單獨用 supervised 預訓練在多數任務上不如組合策略穩定。

7. 與 AIKT 的關聯分析 (AIKT Integration Analysis)

7.1 此專案能否作為 AIKT 的資料來源或分析工具?

pretrain-gnns 本身不是一個「知識管理」工具,而是一個領域研究資產(domain research asset)。它與 AIKT 的關係不是「被 AIKT 呼叫執行」,而是「被 AIKT 妥善收錄、精讀、轉化為可檢索知識」。具體切入點:

  • 作為知識擷取對象(L1-3)gh-save(L2)已經是本次教學文件的產生路徑本身——透過 gh: 前綴把此 repo 的 README、程式碼結構、關鍵檔案摘要收錄進 inbox/
  • 作為教學生成對象(L12)gh-tutorial-qd(本文件所屬 Layer)把倉庫轉換成結構化教學,正是目前這份文件的產出管線。
  • 作為藥物開發計畫的技術基礎(L19):若使用者要生成涉及分子性質預測、GNN-based 虛擬篩選的 tu-plan-generator 藥物開發計畫,pretrain-gnns 的方法論(scaffold split、預訓練策略選擇)可作為技術方案章節的引用依據。
  • 作為論文精讀教學對象(L15 paper-tutorial):原始 ICLR 2020 論文本身適合用 paper-tutorial: 生成精讀教學,搭配這份程式碼導向教學形成「理論+實作」雙軌知識資產。

7.2 AIKT 哪些 Layer 可以包裝或編排此專案


flowchart TB
    subgraph aikt["AIKT 28-Layer 系統"]
        L2["L2 gh-save
已收錄本 repo metadata"] L9["L9 paper-search
可搜尋 ICLR 2020 論文
+ 後續引用文獻"] L10["L10 paper-qa-lite
對已下載的論文/README
做本地 RAG 問答"] L12["L12 gh-tutorial-qd
(本文件產出管線)"] L15["L15 paper-tutorial
論文精讀教學 HTML"] L19["L19 tu-plan-generator
若涉及化合物開發計畫
可引用本專案方法論"] L4["L4 graphify
若專案被 clone 進本機
可建索引供架構問答"] end Repo["pretrain-gnns
GitHub Repo"] --> L2 L2 --> L12 Repo -.->|"論文全文"| L9 L9 --> L10 L10 --> L15 L12 -.->|"技術方法可引用"| L19 Repo -.->|"若需深入問答架構"| L4

7.3 潛在整合場景與價值

  1. 「論文 + 程式碼」雙軌知識鏈:先用 paper-search: 抓取 arXiv:1905.12265 全文與後續引用它的論文(例如 GraphCL、MGSSL),再用 paper-qa-lite: 建立本地 RAG,讓使用者可以直接問「這篇論文的 context prediction 和 GraphCL 的對比學習有什麼差異」——pretrain-gnns 教學文件(本文)與論文 RAG 互為補充。
  2. tu-plan-generator(L19)藥物開發計畫的分子建模章節:當計畫需要涉及虛擬篩選 / ADMET 預測的技術路線時,可以引用本專案的 8 個下游任務清單(Tox21/HIV/BBBP 等)作為「本團隊將採用的評測基準」範例。
  3. 價值總結pretrain-gnns 對 AIKT 而言的價值不在於「被 Layer 直接呼叫執行程式碼」(它是一個訓練用的研究程式碼庫,不是一個可組合的 CLI 工具),而在於作為高品質知識輸入,透過 L2/L9/L12/L15 等擷取與教學生成層,把一篇高影響力論文的方法論與程式碼實作,轉化為團隊可檢索、可引用、可教學的結構化知識資產。

7.4 現實限制的誠實說明

需要明確指出:pretrain-gnns 不具備 CLI-first 可組合介面(它是研究用 Python script,需要手動改參數執行),因此無法被包裝成 AIKT 的一個新 Layer(不符合 L26 layer-creator 對「可執行入口」的要求)。它在 AIKT 生態系中的角色定位是被消費的知識內容,而非執行工具——這個區分很重要,避免誤判整合方式。


8. 優缺點與生態系定位 (Strengths, Limitations & Ecosystem Position)

8.1 核心優勢與創新點

  1. 首創系統性驗證 GNN 預訓練普遍有效性:在此之前該領域缺乏被廣泛引用的正面結果,本文奠定了後續「圖預訓練」子領域的方法論基礎。
  2. 策略可組合、消融實驗完整:四種節點層級自監督策略 + 監督式預訓練可任意排列組合,論文本身提供了詳盡的消融實驗數據,程式碼結構也忠實反映這種可組合性(每種策略獨立成檔)。
  3. 開源生態完整:不只釋出程式碼,還釋出了大量預訓練 checkpoint(model_gin/model_architecture/ 共近 20 個權重檔),大幅降低後續研究者的重現成本。
  4. 評測方法嚴謹:採用 scaffold split 而非隨機切分,多種子取平均,符合分子性質預測領域的嚴謹評測慣例。

8.2 目前限制與改進空間

  1. 程式碼年代久遠、依賴版本鎖死torch==1.0.1torch_geometric==1.0.3 都是 2019 年的版本,直接執行需要額外的環境考古工作(見第 3 節安裝章節)。
  2. 不支援現代圖預訓練的對比學習框架:2020 年後興起的 SimCLR 式對比學習(如 GraphCL、SimGRACE)並未納入本專案,若要用最新方法需要另尋其他倉庫。
  3. 僅涵蓋分子與蛋白質兩個領域:對於其他圖領域(社交網路、知識圖譜、材料科學)的適用性未在原論文中驗證,遷移到新領域需要自行重新設計節點/邊特徵編碼。
  4. 缺乏現代化的 CLI / config 系統:所有超參數透過 argparse 手動指定,沒有 YAML config 或 Hydra 整合,批次實驗管理較為原始。
  5. 無自動化測試(tests/):作為研究程式碼,沒有單元測試覆蓋,對後續維護者做二次開發風險較高,需要自行補充驗證。

8.3 與同領域工具的比較

工具/方法發表年份核心策略與本專案的關係
pretrain-gnns(本專案)2020 (ICLR)Masking/Context/Edge/Infomax + Supervised 組合基準方法
GraphCL2020 (NeurIPS)圖層級對比學習(資料增強對比)後續工作,被視為與本專案互補的圖層級對比策略
GPT-GNN2020 (KDD)生成式自回歸預訓練(節點屬性+邊生成)另一種節點層級自監督設計,思路上呼應本專案的 masking
MGSSL2021 (NeurIPS)基於分子官能基 (motif) 的自監督針對化學領域的更細緻結構先驗,是本專案 Context Prediction 的進一步發展
OGB Leaderboard baselines持續更新各式 GNN + 預訓練組合本專案的資料處理管線與評測協定是 OGB 早期分子任務的重要參照

8.4 適用場景建議

  • 適合:學術研究需要一個「可信賴、有完整消融實驗支撐」的圖預訓練 baseline;藥物發現團隊需要現成的分子性質預測預訓練權重快速起步;教學用途講解「預訓練為何在圖領域比在 NLP/CV 領域更棘手」。
  • ⚠️ 需額外工作:要接軌現代 PyTorch/PyG 生態系統(版本遷移工作量不小);要用於分子/蛋白質以外的圖領域(需重新設計特徵編碼與驗證);要做大規模生產環境部署(本專案定位是研究程式碼而非生產級套件)。
  • 不建議:直接拿來做「最新 SOTA (state-of-the-art) 圖預訓練」的參照——2020 年後的對比學習類方法(GraphCL 等)在多數 benchmark 上已超越本專案的組合式策略,建議把本專案定位為「入門與方法論理解」的經典之作,而非「當前最強實作」。

附錄:快速指令參考卡

 1# ---- 化學分子任務 ----
 2cd chem/
 3
 4# 節點層級自監督(四選一或組合)
 5python pretrain_masking.py --output_model_file OUT_PATH
 6python pretrain_contextpred.py --output_model_file OUT_PATH
 7python pretrain_edgepred.py --output_model_file OUT_PATH
 8python pretrain_deepgraphinfomax.py --output_model_file OUT_PATH
 9
10# 疊加圖層級監督式預訓練
11python pretrain_supervised.py --input_model_file IN_PATH --output_model_file OUT_PATH
12
13# 下游微調(8 個任務:tox21/toxcast/sider/clintox/muv/hiv/bace/bbbp)
14python finetune.py --model_file MODEL_PATH --dataset bbbp --filename result.txt
15
16# 復現論文結果(10 種子平均)
17sh finetune_tune.sh SEED DEVICE
18
19# ---- 生物蛋白質任務 ----
20cd bio/
21python pretrain_masking.py --output_model_file OUT_PATH
22python finetune.py --model_file MODEL_PATH --filename result.txt