Repository: https://github.com/snap-stanford/GraphRNN Stars: 430 | Language: Python | License: MIT 論文: GraphRNN: Generating Realistic Graphs with Deep Auto-regressive Model(ICML 2018) 作者: Jiaxuan You*, Rex Ying*, Xiang Ren, William L. Hamilton, Jure Leskovec(Stanford SNAP Group)
1. 專案概覽 (Project Overview)
1.1 背景與研究團隊
GraphRNN 是 Stanford SNAP(Stanford Network Analysis Project;史丹佛網路分析專案)實驗室在 2018 年發表於 ICML(International Conference on Machine Learning; 國際機器學習大會)的圖生成 (graph generation; 圖形生成) 模型。作者群包含 Jiaxuan You 與 Rex Ying(共同一作),以及該實驗室的靈魂人物 Jure Leskovec 教授——SNAP 是後續 GraphSAGE、PinSAGE、OGB (Open Graph Benchmark)、DeepSNAP 等一系列圖神經網路 (graph neural network; GNN) 相關工具的發源地,GraphRNN 是這個生態系中「圖生成」方向的奠基性工作。
1.2 解決什麼問題
在 GraphRNN 之前,圖生成領域長期被兩類方法把持:
- 傳統統計模型:Erdős–Rényi (ER) 隨機圖、Barabási–Albert (BA) 無標度網路模型、Kronecker graph model(SNAP 團隊自己的前作)。這些模型都預先假設了圖的生成機制(例如「每條邊獨立同機率出現」),對真實世界圖(分子結構、社群網路、蛋白質交互作用網路)的複雜統計特性(degree distribution、clustering coefficient、community structure)擬合能力有限。
- 早期深度生成模型:直接把圖的鄰接矩陣 (adjacency matrix; 相鄰矩陣) 當成一張「圖片」丟進 VAE (Variational Autoencoder; 變分自編碼器) 或 GAN (Generative Adversarial Network; 生成對抗網路)。問題是鄰接矩陣是 $n \times n$($n$ 為節點數),生成 $n^2$ 個獨立元素的複雜度太高,且忽略了圖中「node ordering 不唯一」(node permutation invariance; 節點排列不變性) 的本質特性。
GraphRNN 的核心創新,是把「生成一張圖」重新表述成「生成一個序列 (sequence)」的問題:透過 BFS (Breadth-First Search; 廣度優先搜尋) 為圖的節點排序,再把圖拆解成「一個節點接一個節點加入、每個節點決定要跟哪些先前節點連邊」的自回歸 (auto-regressive) 過程。這讓模型可以用兩層 RNN (Recurrent Neural Network; 遞歸神經網路)——一層管節點層級的狀態、一層管每個節點的邊層級決策——來逐步生成整張圖。
1.3 為什麼重要
這個問題之所以重要,是因為「能生成逼真的圖」直接對應到許多實務場景:
- 藥物設計:分子結構本質上是圖(原子=節點,化學鍵=邊),生成新分子等同生成新圖。
- 網路科學研究:測試網路韌性、模擬社群演化、生成合成資料做壓力測試。
- 異常偵測:先學會「正常圖長什麼樣子」,才能判斷什麼是「異常圖」。
- 知識圖譜補全:理解圖的生成分佈,有助於推斷缺失的邊或節點。
GraphRNN 首次證明「深度自回歸序列模型」可以同時捕捉圖的局部結構(degree distribution)與全域結構(clustering、社群),並在多個 benchmark 資料集(grid、community、citation network 等)上大幅超越傳統統計模型與同時期的深度生成模型基準(B-A、E-R、Kronecker、MMSB、DeepGMG、GraphVAE)。
1.4 在 snap-stanford 生態系中的定位
graph TD
A["SNAP 研究生態系"] --> B["圖分析基礎設施
SNAP C++ library"]
A --> C["圖生成 (Graph Generation)"]
A --> D["圖表徵學習 (Graph Representation Learning)"]
A --> E["圖神經網路 Benchmark"]
C --> C1["GraphRNN (2018)
本教學主角"]
C --> C2["GraphVAE (baseline 對照)"]
C --> C3["後續工作:GRAN, GraphAF 等"]
D --> D1["node2vec"]
D --> D2["GraphSAGE"]
D --> D3["PinSAGE"]
E --> E1["Open Graph Benchmark (OGB)"]
E --> E2["DeepSNAP"]
B --> B1["Kronecker graph model
(GraphRNN 的 baseline)"]
style C1 fill:#4a90d9,color:#fff
GraphRNN 承接了 SNAP 早期 Kronecker graph model 的「圖生成」研究脈絡,並把它從「參數化統計模型」推進到「深度學習模型」;同時它也是 SNAP 後續一系列 GNN 工具(node2vec、GraphSAGE)在「生成式」而非「判別式/表徵式」方向上的重要分支。
2. 核心架構 (Core Architecture)
2.1 整體系統架構圖
flowchart TB
subgraph sg1["資料準備層 (Data Preparation)"]
D1["create_graphs.py
準備目標圖資料集"] --> D2["data.py
Graph_load / Graph_sequence_sampler_*"]
D2 --> D3["BFS 節點排序 + 鄰接向量編碼
encode_adj"]
end
subgraph sg2["模型層 (Model)"]
M1["model.py
GRU_plain / LSTM_plain
(graph-level RNN)"] --> M2["MLP_plain 或
output GRU/LSTM
(edge-level RNN)"]
M2 --> M3["sample_sigmoid
(採樣下一條邊)"]
end
subgraph sg3["訓練/推論層 (Train & Generate)"]
T1["main.py
參數載入 + 流程總控"] --> T2["args.py
Args 設定物件"]
T1 --> T3["train.py
train_rnn / test_rnn_epoch"]
end
subgraph sg4["評估層 (Evaluation)"]
E1["evaluate.py"] --> E2["eval/stats.py
MMD: degree/clustering"]
E1 --> E3["eval/orca
orbit counts (motif 統計)"]
end
D3 --> M1
T3 --> M1
T3 --> M2
M3 --> E1
E1 --> R["figures/ · eval_results/
視覺化與量化報告"]
style M1 fill:#4a90d9,color:#fff
style M2 fill:#4a90d9,color:#fff
2.2 關鍵模組與資料流
| 檔案 | 角色 | 說明 |
|---|---|---|
main.py | 主執行入口 | 讀取 args.py 設定,串起資料載入 → 建模 → 訓練 → 生成 → 存檔全流程 |
args.py | 超參數集中管理 | Args class:模型變體 (note)、資料集 (graph_type)、RNN 隱藏層維度、學習率排程等 |
data.py | 資料集載入與序列化 | 載入 ENZYMES/DD/PROTEINS/citation network 等資料,將 networkx.Graph 轉為訓練用的序列 tensor |
model.py | 模型定義 | LSTM_plain / GRU_plain(graph-level RNN)、MLP_plain(edge-level 輸出頭)、採樣函式 (sample_sigmoid、gumbel_softmax 等) |
train.py | 訓練與生成迴圈 | train_rnn_epoch(訓練一個 epoch)、test_rnn_epoch(自回歸生成新圖) |
utils.py | 工具函式 | 圖視覺化 (draw_graph_list)、圖存取 (save_graph_list/load_graph_list)、圖擾動 (perturb) |
evaluate.py | 評估總控 | 讀取生成圖與真實圖,呼叫 MMD 計算,輸出 eval_results/ |
eval/stats.py | 統計距離計算 | 用 MMD (Maximum Mean Discrepancy; 最大平均差異) 比較 degree distribution、clustering coefficient distribution |
eval/orca/ | Motif 統計 | C++ 實作的 ORCA 演算法,計算 graphlet/orbit counts,用於更細粒度的結構相似度評估 |
baselines/ | 對照組模型 | baseline_simple.py(B-A、E-R)、mmsb.py(MMSB)、graphvae/(GraphVAE) |
main_DeepGMG.py | 對照組模型 | DeepGMG baseline 的獨立實作 |
2.3 設計哲學與技術選擇分析
為什麼用兩層 RNN 而非一層? 這是 GraphRNN 最核心的設計決策。作者把「生成一張圖」分解成兩個巢狀的自回歸問題:
- Graph-level RNN(
LSTM_plain/GRU_plain,has_output=False版本):管理「目前生成到第幾個節點」的整體狀態,輸出一個 hidden vector 作為 edge-level RNN 的初始狀態。 - Edge-level RNN 或 MLP(
GraphRNN_RNN用第二層 RNN,GraphRNN_MLP用 MLP 取代):在「加入第 $i$ 個節點」的當下,決定它要跟前面 $M$ 個節點(max_prev_node)中的哪些連邊,逐 bit 預測一個二元向量。
這個設計對應論文中「圖的分解定理」:任何圖都可以表示成節點依序加入、每次加入伴隨一個鄰接向量的序列。比起直接生成 $n \times n$ 矩陣,複雜度從 $O(n^2)$ 降到 $O(n \times M)$($M \ll n$,因為多數真實圖是稀疏的、BFS 排序後鄰接向量的有效長度很短)。
為什麼要 BFS 排序? 圖沒有「自然」的節點順序——同一張圖可以有 $n!$ 種節點編號方式。如果不排序,RNN 要學習的序列分佈會被這 $n!$ 種等價表示法稀釋,訓練訊號極度稀疏。BFS 排序後,鄰接矩陣呈現「帶狀」結構(band-limited),使得 max_prev_node 可以被大幅限制在一個較小範圍,大幅降低模型要建模的邊數。
MLP 版 vs RNN 版的取捨:GraphRNN_MLP 假設同一節點的多條邊彼此獨立(給定 graph-level hidden state 之後);GraphRNN_RNN 用額外一層 RNN 顯式建模「邊與邊之間的相依性」(dependent Bernoulli sequence)。後者表達力更強但訓練成本更高——這是專案原始碼中 args.py 裡 self.note 選項的取捨依據。
flowchart LR
subgraph concept["自回歸圖生成的兩層分解"]
direction TB
N0["節點 0
初始狀態"] -->|hidden state| N1["節點 1
graph-RNN 更新"]
N1 -->|hidden state| N2["節點 2
graph-RNN 更新"]
N2 -->|hidden state| N3["節點 3 ...
graph-RNN 更新"]
N1 -.->|生成鄰接向量| E1["edge-RNN/MLP:
是否連到節點 0?"]
N2 -.->|生成鄰接向量| E2["edge-RNN/MLP:
是否連到節點 0,1?"]
N3 -.->|生成鄰接向量| E3["edge-RNN/MLP:
是否連到節點 0,1,2?"]
end
3. 安裝與設定 (Installation & Setup)
3.1 環境需求
⚠️ 重要提醒:這是一份 2018 年發表、對應 PyTorch 0.2.0~0.4.0 的舊版程式碼。原始碼中直接使用 Variable(PyTorch 0.4 後已併入 Tensor,Variable 是相容殼但已非慣用寫法)、nn.init.xavier_uniform(新版 API 已改名 xavier_uniform_)、F.sigmoid/F.softmax(新版建議用 torch.sigmoid/F.softmax(dim=...))等已棄用或已改名的 API。若要在現代環境(PyTorch 2.x)跑起來,必須做相容性修改,不能直接 pip install -r requirements.txt 後跑。
- Python 3.6+(原始開發環境約為 Python 3.5/3.6)
- PyTorch(原生測試 0.2.0/0.4.0;建議另建 legacy conda env 精確對齊,或自行修補 API)
- CUDA GPU(程式碼內部大量硬編碼
.cuda()呼叫,CPU-only 環境需要額外修改) networkx、numpy、scipy、matplotlib、torchvision- C++ 編譯器(
g++,用於編譯eval/orca/orca.cpp,做 orbit-count 評估)
3.2 完整安裝步驟
1# 1. Clone 專案
2git clone https://github.com/snap-stanford/GraphRNN.git
3cd GraphRNN
4
5# 2. 建議:用 conda 建立對齊舊版 PyTorch 的隔離環境(避免污染系統環境)
6conda create -n graphrnn python=3.6 -y
7conda activate graphrnn
8
9# 3. 安裝 PyTorch(官方頁面依 CUDA 版本挑選;舊版 GPU 環境常用 cuda90 對應舊 driver)
10conda install pytorch torchvision cuda90 -c pytorch
11
12# 4. 安裝其餘相依套件
13pip install -r requirements.txt
14
15# 5. 編譯 ORCA(用於 orbit-count 評估;repo 內已附 Ubuntu 預編譯二進位,
16# 非 Ubuntu 平台或版本不合需重新編譯)
17cd eval/orca
18g++ -O2 -std=c++11 -o orca orca.cpp
19cd ../..
3.3 資料集下載與準備
dataset/ 目錄下已隨 repo 附帶多個標準圖分類資料集的原始檔(.txt 格式的鄰接表 + 節點標籤 + 節點屬性),包含:
ENZYMES、DD、PROTEINS_full:生物資訊圖分類資料集(data.py的Graph_load_batch()負責解析)ind.cora.*、ind.citeseer.*、ind.pubmed.*:citation network 資料集(Planetoid 格式,Graph_load()負責解析)
此外,create_graphs.py 也能現場合成多種經典圖拓樸做為訓練目標,不需下載外部資料:
1# 合成圖類型範例(於 args.py 的 graph_type 欄位設定):
2# 'grid' — 規則格狀圖
3# 'caveman' — Caveman graph(社群結構的經典模型)
4# 'community4' — 4 個社群組成的複合圖
5# 'barabasi' — Barabási–Albert 無標度網路
6# 'ladder_small' — 梯狀圖
3.4 快速測試
1python main.py
main.py 會依 args.py 中預設的 self.graph_type = 'grid' 與 self.note = 'GraphRNN_RNN' 設定,載入/合成 grid 資料集,訓練 GraphRNN_RNN 模型,並依 epochs_save(預設每 100 epoch)將產出寫入 graphs/、model_save/、figures/、nll/ 等目錄(皆位於 args.dir_input,預設為 ./)。
3.5 常見問題排解
| 問題 | 原因 | 解法 |
|---|---|---|
AttributeError: module 'torch.nn.functional' has no attribute 'sigmoid' | 新版 PyTorch 移除頂層 F.sigmoid/F.softmax 別名 | 全域替換為 torch.sigmoid(x) / F.softmax(x, dim=-1) |
TypeError: xavier_uniform() missing... 或找不到函式 | 新版 API 改名為 xavier_uniform_(in-place 版本) | 將 init.xavier_uniform 改為 init.xavier_uniform_ |
RuntimeError: CUDA error 或無 GPU 環境直接崩潰 | 程式碼內大量硬編碼 .cuda() | 需要自行加入 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') 並全面替換 .cuda() 呼叫 |
orca 執行檔無法執行 (Permission denied) | 預編譯二進位權限或平台不符 | chmod +x eval/orca/orca,或依 3.2 節重新編譯 |
| 訓練記憶體暴增 | max_prev_node 設為 None 時會自動依全資料集計算,遇到含高 degree 節點的圖集會使鄰接向量過長 | 在 args.py 手動設定較保守的 max_prev_node 上限 |
4. 核心概念詳解 (Key Concepts)
4.1 把「圖」看成「序列」——核心類比
想像你在逐格畫一張社群關係圖:先畫第一個人(節點 0),畫第二個人時決定「他跟誌 0 認不認識」,畫第三個人時決定「他跟前兩人各自認不認識」……直到畫完所有人。這正是 GraphRNN 的核心類比——把畫圖這件事變成一格一格填空的過程,而不是一次把整張關係表 (鄰接矩陣) 畫出來。
用數學語言:給定一個節點排序 $\pi$,圖 $G$ 可以表示成一個序列
$$S^\pi = (S_1^\pi, S_2^\pi, \dots, S_n^\pi)$$
其中 $S_i^\pi \in {0,1}^{i-1}$ 是第 $i$ 個節點與前面所有節點的連邊向量。生成整張圖等價於生成這個序列,機率可以用鏈式法則 (chain rule) 分解:
$$p(S^\pi) = \prod_{i=1}^{n} p(S_i^\pi \mid S_1^\pi, \dots, S_{i-1}^\pi)$$
這正是 RNN 最擅長的建模型態——「給定過去,預測下一步」。
4.2 為什麼要 BFS 排序?——類比「整理書架」
如果隨便排列節點順序,鄰接向量 $S_i^\pi$ 的長度理論上要涵蓋前面所有 $i-1$ 個節點(因為任何一個都可能連邊),這讓模型要處理的向量長度隨節點數線性成長,且大量位置永遠是 0(稀疏、難學)。
BFS 排序就像整理書架時「按照類別/關聯性排列書本」——BFS 走訪保證:任兩個相鄰的節點在排序中的位置差距,不會超過該圖的「BFS 寬度」。這讓有效的 max_prev_node(模型只需回顧多少步之前的節點)大幅縮小,把稀疏、瑣碎的邊決策,壓縮成密集、有意義的局部決策視窗。
flowchart TD
subgraph before["未排序:任意節點順序"]
direction LR
B1["節點順序混亂
鄰接向量長度 = i-1
(隨 i 線性成長)"]
end
subgraph after["BFS 排序後"]
direction LR
A1["鄰接向量長度
≈ max_prev_node
(遠小於 n,且固定上限)"]
end
before -->|"BFS 排序 (encode_adj)"| after
style after fill:#4a90d9,color:#fff
4.3 兩層 RNN 的角色分工——類比「導演與演員」
可以把 graph-level RNN 想像成導演:他不直接決定每個演員的台詞,而是掌握整齣戲目前演到哪一幕、氛圍如何(對應 hidden state $h_i$)。edge-level RNN/MLP 則是演員:拿到導演給的「這一幕的氛圍指示」後,具體決定「這句台詞要不要講」(也就是「這條邊要不要連」)。
- graph-level RNN(
model.py的LSTM_plain(has_output=False)):輸入是「上一個節點的鄰接向量」,輸出是更新後的 hidden state,傳給下一步。 - edge-level 模組:
GraphRNN_MLP版本:直接用一個 MLP (MLP_plain) 把 hidden state 映射成整條鄰接向量的機率(假設向量內各 bit 條件獨立)。GraphRNN_RNN版本:用另一個 RNN 逐 bit 生成鄰接向量(bit 之間有序列相依性,即論文所稱 dependent Bernoulli sequence)。
4.4 訓練時的「監督式取樣」 vs 生成時的「自回歸取樣」
訓練階段用 teacher forcing(train.py 中直接餵真實圖的鄰接向量做監督),模型看到的永遠是「正確答案」;生成階段則用 sample_sigmoid(model.py)做自回歸取樣——模型自己上一步的輸出,會變成下一步的輸入。這是所有自回歸生成模型共通的「exposure bias」議題:訓練時看到的都是真實資料,測試/生成時卻要吃自己犯過的錯(累積誤差)。GraphRNN 用 sample_time 參數(一個時間步嘗試多次取樣,挑「至少產生一條邊」的結果)來緩解生成初期容易「整條全 0」的退化問題。
4.5 評估:如何量化「這張生成的圖有多真實」?
單一張圖沒有辦法直接比較「相似度」,因為節點數、拓樸都不同。GraphRNN 採用 MMD (Maximum Mean Discrepancy; 最大平均差異) 比較一組真實圖與一組生成圖在某個統計量(degree distribution、clustering coefficient distribution、orbit/motif counts)上的分佈差異,而非逐點比較。可以類比成:不比較「兩個人的身高完全一樣嗎」,而是比較「兩個班級的身高分佈曲線像不像」。
flowchart LR
RG["真實圖集合
(Test set)"] --> RD["計算統計量分佈
degree / clustering / orbit"]
GG["生成圖集合
(GraphRNN 輸出)"] --> GD["計算統計量分佈"]
RD --> MMD["MMD 距離計算
eval/stats.py"]
GD --> MMD
MMD --> Score["MMD 分數
越小 = 越逼真"]
5. 使用方式與程式碼範例 (Usage & Code Examples)
5.1 基礎用法:直接跑訓練
最基本的用法就是修改 args.py 中的設定物件,再執行 main.py:
1# args.py(節錄修改示範)— 設定模型變體、資料集與訓練規模
2class Args():
3 def __init__(self):
4 self.cuda = 0 # 使用第 0 號 GPU
5 self.note = 'GraphRNN_RNN' # 使用兩層 RNN 版本(相較 GraphRNN_MLP 表達力更強)
6 self.graph_type = 'community4' # 用內建合成的 4-社群圖做訓練
7 self.max_num_node = None # 自動計算資料集內最大節點數
8 self.max_prev_node = None # 自動計算 BFS 排序後的最大回顧範圍
9
10 self.hidden_size_rnn = 128
11 self.hidden_size_rnn_output = 16
12 self.embedding_size_rnn = 64
13 self.embedding_size_rnn_output = 8
14
15 self.batch_size = 32
16 self.epochs = 3000 # 3000 epoch,每 epoch = batch_ratio(32) 個 batch
17 self.lr = 0.003
18 self.milestones = [400, 1000] # 學習率在第 400、1000 epoch 時衰減
19 self.lr_rate = 0.3
20
21 self.epochs_save = 100 # 每 100 epoch 存一次 checkpoint + 生成樣本
1# 執行訓練(會自動依上面設定跑完整流程:載入/合成資料 → 訓練 → 定期生成 → 存檔)
2python main.py
5.2 進階用法:讀取已訓練模型並生成新圖、視覺化
1# 示範腳本:載入已存的圖清單並視覺化(依 utils.py 提供的工具函式)
2import pickle as pkl
3from utils import load_graph_list, draw_graph_list
4
5# graphs/ 目錄下的檔名格式一般為
6# {note}_{graph_type}_{...超參數...}_pred_{epoch}_1.dat
7generated_graphs = load_graph_list(
8 'graphs/GraphRNN_RNN_community4_4_128_pred_3000_1.dat',
9 is_real=False
10)
11
12print(f'共生成 {len(generated_graphs)} 張圖')
13print(f'第一張圖節點數: {generated_graphs[0].number_of_nodes()}')
14print(f'第一張圖邊數: {generated_graphs[0].number_of_edges()}')
15
16# 視覺化前 16 張生成圖,存成 4x4 grid 圖檔
17draw_graph_list(
18 generated_graphs[:16],
19 row=4, col=4,
20 fname='figures/my_generated_samples'
21)
5.3 進階用法:自訂 MMD 評估流程
1# evaluate.py 的核心邏輯示範:計算 degree distribution 的 MMD
2from eval.stats import degree_stats, clustering_stats
3from utils import load_graph_list
4
5real_graphs = load_graph_list('graphs/GraphRNN_RNN_community4_4_128_test_0.dat', is_real=True)
6pred_graphs = load_graph_list('graphs/GraphRNN_RNN_community4_4_128_pred_3000_1.dat', is_real=False)
7
8# degree distribution 的 MMD(值越低代表生成圖的度分佈越接近真實圖)
9mmd_degree = degree_stats(real_graphs, pred_graphs)
10print(f'Degree distribution MMD: {mmd_degree:.4f}')
11
12# clustering coefficient distribution 的 MMD
13mmd_clustering = clustering_stats(real_graphs, pred_graphs)
14print(f'Clustering coefficient MMD: {mmd_clustering:.4f}')
執行完整評估流程(含 orbit counts):
1python evaluate.py
5.4 實際應用場景展示:自訂資料集訓練
若要用自己的資料(例如公司內部的社群互動圖、分子資料集),核心步驟是把資料轉成 networkx.Graph 物件的清單,接到 create_graphs.py 的資料載入介面:
1# 自訂資料集接入範例
2import networkx as nx
3import pickle as pkl
4
5def load_my_custom_graphs(edge_list_dir):
6 """
7 將自己的邊清單檔案(每行 'node_a,node_b')轉為 networkx.Graph 清單
8 """
9 graphs = []
10 for fname in edge_list_dir_files(edge_list_dir): # 假設的檔案枚舉函式
11 G = nx.Graph()
12 with open(fname) as f:
13 for line in f:
14 a, b = line.strip().split(',')
15 G.add_edge(a, b)
16 # 過濾太小的圖(GraphRNN 對節點數過少的圖訓練訊號不足)
17 if G.number_of_nodes() >= 10:
18 graphs.append(G)
19 return graphs
20
21# 後續接到 create_graphs.py 中新增一個 elif 分支,
22# 對應到 args.py 的 self.graph_type = 'my_custom_dataset'
6. 進階應用場景 (Advanced Use Cases)
6.1 真實世界的應用案例
- 分子生成 (Molecule Generation):把原子當節點、化學鍵當邊,GraphRNN 系的自回歸序列生成思路直接啟發了後續分子生成模型(如 GraphAF、MoFlow),差異在於加入化學鍵類型 (bond type) 與原子價 (valence) 的約束。
- 社群網路合成資料生成:在資料隱私法規(如 GDPR)限制下,用生成模型產生「統計上相似但非真實使用者」的社群圖,供演算法測試或壓力測試使用。
- 網路韌性模擬:生成大量結構相似但個體不同的圖,測試某種防禦/攻擊策略在「一類圖」而非「單一圖」上的穩健性。
- 教學與 benchmark 基準:作為圖生成領域公認的基準模型,後續論文(GraphAF、GRAN、GraphGen)幾乎都會引用 GraphRNN 的 MMD 評估協議做比較。
6.2 與其他 snap-stanford 工具的整合
flowchart LR
GR["GraphRNN
生成合成圖"] --> N2V["node2vec
對生成圖做節點嵌入"]
GR --> GS["GraphSAGE
用生成圖做資料增強
(data augmentation)"]
GR --> OGB["OGB benchmark
可作為圖生成任務的
對照基準模型"]
SNAP["SNAP C++ library"] -->|"Kronecker graph
作為 baseline"| GR
- 與 node2vec / GraphSAGE 整合:GraphRNN 生成的合成圖可以作為下游 GNN 模型的訓練資料擴增來源,尤其在真實圖資料稀缺(如罕見疾病的蛋白質交互作用網路)時,先用 GraphRNN 學會「這類圖的統計特性」,再生成更多樣本供 GraphSAGE 類模型訓練,緩解小樣本問題。
- 與 SNAP C++ library 整合:
baselines/baseline_simple.py直接沿用 SNAP 的 Kronecker graph 實作做為對照基準,說明 GraphRNN 從一開始就設計成「可與既有 SNAP 工具鏈並存比較」。
6.3 效能調校與最佳實踐
max_prev_node是效能的關鍵旋鈕:這個值決定了 edge-level 模組每步要處理的向量長度,設太大會讓訓練變慢且梯度稀疏(大部分位置仍是 0),設太小會漏掉遠距連邊。建議先讓args.py自動計算一次,再依實際訓練 loss 曲線微調。batch_ratio與epochs的關係:程式碼把「一個 epoch」定義為batch_ratio個 batch(非傳統定義的「跑過一次全資料集」),調整訓練規模時要注意這個非標準用法,避免誤解訓練進度。sample_time影響生成品質與速度的權衡:生成階段每步嘗試多次取樣以避免退化解,sample_time越大生成品質越穩定但速度越慢,建議先用預設值 2 驗證,再視生成圖是否常見「全空/退化圖」問題調整。- 學習率排程 (
milestones+lr_rate):預設在第 400、1000 epoch 做 0.3 倍衰減,屬於典型的階梯式衰減 (step decay);遷移到新資料集時建議先監控 loss 曲線再決定是否需要調整 milestone 位置。
7. 與 AIKT 的關聯分析 (AIKT Integration Analysis)
7.1 GraphRNN 可作為 AIKT 的資料來源或分析工具嗎?
可以,且有兩個明確角色:
- 作為 L2(ai-gh-save)的知識擷取對象:GraphRNN 本身就是一個典型的「值得收錄」的 GitHub repo——有論文、有明確方法論、有 430 stars 的社群驗證。本篇教學正是透過
gh-tutorial-qd(L12)流程產出的範例。 - 作為 L4(graphify)知識圖譜的「圖生成」節點類比參照:graphify 本身建構的是「AIKT 系統內部的知識圖譜」(repo 之間、概念之間的關聯),而 GraphRNN 是「學習如何生成逼真圖」的模型。兩者的關聯不是直接呼叫關係,而是方法論類比:如果 AIKT 未來需要「生成合成的知識圖譜」(例如測試 graphify 在大規模圖上的效能、或產生匿名化但統計相似的知識圖供分享),GraphRNN 的自回歸圖生成思路就是可直接借鏡的技術路徑。
7.2 AIKT 的哪些 Layer 可以包裝或編排此專案?
flowchart TB
subgraph L1_3["L1-3 知識擷取"]
GH["L2 ai-gh-save
已完成:收錄 GraphRNN repo"]
end
subgraph L12_15["L12-15 教學與智財"]
TQ["L12 gh-tutorial-qd
本教學文件的產出流程"]
end
subgraph L4_6["L4-6 知識索引"]
GF["L4 graphify
將本教學納入知識圖譜節點"]
GN["L6 gitnexus
若需深度分析 GraphRNN 原始碼
符號圖/呼叫關係"]
end
subgraph L18_19["L18-19 研究與藥物"]
RP["L18 research-pipeline-v2
若研究主題涉及分子生成
可將 GraphRNN 列為方法論參考"]
TU["L19 tu-plan-generator
藥物開發計畫中若涉及
de novo 分子設計,GraphRNN 系
模型是背景技術參照"]
end
subgraph L9_11["L9-11 研究工具"]
PS["L9 paper-search
搜尋 GraphRNN 後續引用文獻
(GraphAF/GRAN/MoFlow 等)"]
end
GH --> TQ --> GF
GH --> GN
PS -.->|"若需深入方法論比較"| RP
RP -.->|"分子生成場景"| TU
style TQ fill:#4a90d9,color:#fff
具體場景說明:
- L9 paper-search:若後續研究需要追蹤 GraphRNN 之後的圖生成技術演進(GraphAF、GRAN、MoFlow、GraphGen 等),可用
paper: GraphRNN citations或類似查詢,透過跨資料庫學術搜尋找到引用鏈。 - L6 gitnexus:若需要對 GraphRNN 原始碼做更深入的符號級分析(例如追蹤
sample_sigmoid在train.py與model.py之間的呼叫關係),可用gitnexus:前綴建立程式碼符號圖,輔助理解或做 code review。
7.3 潛在整合場景與價值
- 教學資產沉澱:本篇教學本身即是 L12 → L4 的閉環範例——
gh-tutorial-qd產出教學文件後,透過graphify update .讓 GraphRNN 這個節點的方法論摘要(BFS 序列化、雙層 RNN、MMD 評估)成為 AIKT 知識圖譜中可被檢索、可被關聯到其他圖生成/分子生成主題的節點。 - 方法論比較基準:未來若有其他圖生成類 repo 被收錄(GraphVAE、GraphAF、GRAN 等),graphify 的知識圖譜可以把它們與 GraphRNN 關聯起來,形成一條「圖生成技術演進時間線」,供研究時快速定位技術脈絡而非逐篇重讀論文。
- 價值與限制:GraphRNN 本身不是可以直接被 AIKT 各 Layer 呼叫的 API 或服務——它是一個需要 GPU、需要訓練資料、需要相容性修補的研究型程式碼庫。因此它在 AIKT 中的角色定位主要是知識資產與方法論參照,而非可編排執行的工具鏈節點(不同於 docling、quarkdown 這類「可直接被腳本呼叫」的 Layer)。
8. 優缺點與生態系定位 (Strengths, Limitations & Ecosystem Position)
8.1 核心優勢與創新點
- 理論貢獻扎實:把圖生成問題嚴謹地表述成「透過 BFS 排序後的序列生成」,並給出機率分解的數學依據(chain rule),不是憑經驗拼湊的架構。
- 兩層 RNN 分解優雅:graph-level / edge-level 的分工清楚對應「節點加入順序」與「邊的相依性」兩個不同粒度的建模需求,是後續多篇圖生成論文沿用的設計範式。
- 評估協議成為業界標準:MMD-based 的 degree/clustering/orbit 三項統計量比較,至今仍是圖生成論文(包含非 RNN 系的 GraphAF、GRAN 等)的標準評估方式,這比模型本身的影響力更為長遠。
- 開源完整度高:附帶多組 baseline(B-A、E-R、Kronecker、MMSB、DeepGMG、GraphVAE)的可執行實作,方便直接復現論文的比較實驗,而非只放核心模型。
8.2 目前限制與改進空間
- 程式碼時效性差:對應 PyTorch 0.2.0/0.4.0 的舊版 API(
Variable、F.sigmoid、xavier_uniform無底線版),直接在現代環境執行會報錯,需要相容性修補(見第 3.5 節)。 - 強耦合 CUDA:程式碼內大量硬編碼
.cuda(),沒有 GPU 就無法直接執行,缺乏 CPU fallback 的彈性設計。 - 可擴展性受限於序列長度:BFS 排序雖然降低了
max_prev_node,但對節點數極大(數萬以上)的圖,自回歸生成仍然是逐步驟的序列計算,生成速度慢於後續一次性 (one-shot) 生成的方法(如部分基於 GAN 或 Diffusion 的圖生成模型)。 - 缺乏化學/領域約束:作為通用圖生成模型,沒有內建分子價數、環狀結構合法性等領域知識,若直接套用到分子生成需額外加約束層(這也是後續 GraphAF/MoFlow 等工作補強的方向)。
8.3 與同領域工具的比較
| 模型 | 生成方式 | 相依性建模 | 主要優勢 | 主要限制 |
|---|---|---|---|---|
| GraphRNN(本專案) | 自回歸序列(BFS 排序) | 雙層 RNN 顯式建模 | 理論扎實、評估協議業界標準 | 序列生成速度慢、程式碼老舊 |
| Kronecker graph model | 遞迴矩陣運算 | 參數化統計假設 | 計算快、理論簡潔 | 表達力有限,難擬合複雜真實圖 |
| GraphVAE | 一次性生成鄰接矩陣 | VAE 隱空間 | 生成速度快(非序列) | $O(n^2)$ 複雜度,難擴展到大圖 |
| DeepGMG | 逐步生成(節點+邊決策) | 訊息傳遞 (message passing) | 可建模更豐富的節點/邊屬性 | 訓練與生成成本高 |
| GraphAF(後續工作) | Normalizing Flow + 自回歸 | Flow-based 精確似然 | 精確似然估計、適合分子生成 | 架構複雜度更高 |
8.4 適用場景建議
- 適合:學術研究中需要生成式圖模型作為 baseline 比較對象、需要理解「序列化圖生成」方法論、教學用途展示 RNN 如何應用在非序列型資料(圖)上。
- 不建議直接生產環境使用:若需要工業級部署(如即時分子生成服務),建議直接採用後續更成熟、對 API 相容性維護更好的框架(如支援 PyTorch Geometric 生態的現代圖生成模型),GraphRNN 更適合作為理解基礎方法論與復現經典評估協議的教學/研究工具,而非直接落地的生產系統。
參考資料
- 論文:You, J., Ying, R., Ren, X., Hamilton, W. L., & Leskovec, J. (2018). GraphRNN: Generating Realistic Graphs with Deep Auto-regressive Model. ICML 2018. https://arxiv.org/abs/1802.08773
- 程式碼:https://github.com/snap-stanford/GraphRNN
- 補充教材:Jesse Bettencourt & Harris Chan 在 David Duvenaud 教授研討課的介紹投影片:https://duvenaud.github.io/learn-discrete/slides/graphrnn.pdf
Comments