4. GraphSAGE原理:采样邻居、聚合函数与前向/反向传播
GraphSAGE(Graph Sample and AggregatE)的核心思想是:通过采样邻居节点并聚合其特征,来生成目标节点的嵌入表示。与GCN等全图训练方法不同,GraphSAGE采用归纳式学习,能够泛化到未见过的节点。本章将深入拆解其三大核心模块:邻居采样策略、聚合函数设计以及前向传播与反向传播的数学机制。
4.1 邻居采样:固定大小的局部邻域
在全图上进行消息传递计算量巨大,且图结构可能高度动态。GraphSAGE通过固定大小采样来解决这一问题:对每个目标节点,从其邻居中均匀采样固定数量的节点,形成计算子图。
| 采样参数 | 说明 | 典型值 |
|---|---|---|
| 采样深度 K | 聚合的跳数(层数),决定感受野范围 | 2 或 3 |
| 每层采样数 Sk | 第 k 层对每个节点采样的邻居数量 | S₁=25, S₂=10 |
| 采样方式 | 有放回均匀采样(邻居数不足时重复采样) | Uniform |
采样过程示例(K=2):
- 第一跳(k=1): 对目标节点 v,从其一阶邻居中采样 S₁ 个节点。
- 第二跳(k=2): 对第一跳采到的每个节点,再从其邻居中采样 S₂ 个节点。
- 结果: 形成一个以 v 为根、深度为 2 的计算树,总节点数 ≤ 1 + S₁ + S₁×S₂。
4.2 聚合函数:三种核心设计
聚合函数是GraphSAGE的核心,它决定了如何将邻居节点的特征信息“融合”到目标节点。论文提出了三种聚合器,各有优劣:
| 聚合器 | 核心公式 | 对称性 | 表达能力 | 适用场景 |
|---|---|---|---|---|
| Mean Aggregator | hN(v) = mean({hu, ∀u ∈ N(v)}) | ✅ 对称 | 低(仅均值) | 同质图、特征分布均匀 |
| LSTM Aggregator | hN(v) = LSTM([hu1, hu2, ..., huS]) | ❌ 非对称(依赖顺序) | 高(序列建模) | 时序图、邻居有顺序关系 |
| Pooling Aggregator | hN(v) = max({σ(W·hu + b), ∀u ∈ N(v)}) | ✅ 对称 | 中(捕捉最显著特征) | 异质图、团伙识别 |
4.2.1 Mean Aggregator(均值聚合器)
对邻居节点的特征向量逐元素取平均,然后与目标节点自身特征拼接。这是最简单的聚合方式,相当于GCN的归纳式版本。
# 伪代码:Mean Aggregator
def mean_aggregator(neighbor_features):
# neighbor_features: [S, d] S个邻居,每个d维
return torch.mean(neighbor_features, dim=0) # [d]
4.2.2 LSTM Aggregator(LSTM聚合器)
将邻居节点视为一个序列,输入LSTM网络,取最后一个隐藏状态作为聚合结果。由于LSTM对输入顺序敏感,通常需要对邻居节点进行随机排序来引入不变性。
# 伪代码:LSTM Aggregator
def lstm_aggregator(neighbor_features):
# neighbor_features: [S, d] 需先随机打乱顺序
lstm_out, (h_n, c_n) = lstm(neighbor_features.unsqueeze(1))
return h_n.squeeze(0) # [d]
4.2.3 Pooling Aggregator(池化聚合器)
对每个邻居节点先经过一个全连接层(MLP),然后对所有邻居的变换结果进行逐元素最大池化(或平均池化)。这是团伙识别任务中最常用的聚合器,因为它能捕捉到邻居中“最异常”或“最显著”的特征信号。
# 伪代码:Pooling Aggregator
def pooling_aggregator(neighbor_features):
# neighbor_features: [S, d]
W = nn.Linear(d, d) # 可学习的变换矩阵
transformed = torch.relu(W(neighbor_features)) # [S, d]
pooled = torch.max(transformed, dim=0)[0] # [d] 逐元素取最大
return pooled
4.3 前向传播:从采样到嵌入生成
GraphSAGE的前向传播过程是一个逐层聚合的过程。假设模型有 K 层,每层对应一跳邻居的聚合。以下是完整的计算流程:
- 初始化: 每个节点 v 的第 0 层表示 hv(0) 等于其原始特征 xv。
- 逐层聚合(k = 1 到 K):
- 对每个节点 v,使用聚合函数 AGGk 聚合其采样邻居 N(v) 的上一层表示:
hN(v)(k) = AGGk({hu(k-1), ∀u ∈ N(v)}) - 将聚合结果与节点自身的上一层表示拼接,经过全连接层和非线性激活:
hv(k) = σ(Wk · CONCAT(hv(k-1), hN(v)(k))) - 可选:对 hv(k) 进行 L2 归一化,防止数值爆炸。
- 对每个节点 v,使用聚合函数 AGGk 聚合其采样邻居 N(v) 的上一层表示:
- 输出: 最后一层的表示 hv(K) 即为节点 v 的最终嵌入,可用于下游分类或聚类任务。
# 伪代码:GraphSAGE 前向传播(单节点视角)
def forward(node_features, adj_list, K, W_list, agg_funcs):
# node_features: [N, d] 所有节点的初始特征
# adj_list: 采样后的邻居索引列表
h = {v: node_features[v] for v in range(N)} # h^(0)
for k in range(1, K+1):
h_next = {}
for v in range(N):
# 1. 聚合邻居
neighbor_h = [h[u] for u in adj_list[v][k-1]] # 第k跳邻居
agg_h = agg_funcs[k-1](neighbor_h) # [d]
# 2. 拼接 + 线性变换 + 激活
combined = torch.cat([h[v], agg_h], dim=0) # [2d]
h_next[v] = torch.relu(W_list[k-1] @ combined) # [d_out]
# 3. 可选归一化
h = {v: F.normalize(h_next[v], p=2, dim=0) for v in range(N)}
return h # 最终嵌入
4.4 反向传播:基于采样子图的梯度计算
GraphSAGE的反向传播与标准神经网络类似,但有一个关键区别:梯度只流经被采样到的节点和边。由于前向传播时我们构建了固定的计算子图,反向传播时只需在该子图上应用链式法则。
4.4.1 损失函数
在团伙识别任务中,通常使用交叉熵损失(有监督)或图对比损失(无监督/自监督)。
# 有监督损失:交叉熵
def supervised_loss(z_v, y_v):
# z_v: 节点嵌入 [d]
# y_v: 真实标签(0: 正常, 1: 团伙)
logits = classifier(z_v) # 线性分类头
loss = F.cross_entropy(logits, y_v)
return loss
# 无监督损失:负采样(GraphSAGE原文)
def unsupervised_loss(z_v, z_u, z_neg):
# z_v: 目标节点嵌入
# z_u: 正样本邻居嵌入
# z_neg: 负样本嵌入(随机采样非邻居)
pos_score = torch.sigmoid(torch.dot(z_v, z_u))
neg_score = torch.sigmoid(torch.dot(z_v, z_neg))
loss = -torch.log(pos_score) - torch.log(1 - neg_score)
return loss
4.4.2 梯度计算与参数更新
需要更新的参数包括:
- 每层的权重矩阵 Wk:用于拼接后的线性变换。
- 聚合函数内部参数:如LSTM的权重、Pooling中MLP的权重。
- 分类头参数(有监督时)。
由于每个batch的计算子图独立,GraphSAGE支持mini-batch训练,这是其扩展到大规模图的关键。训练流程如下:
- Batch采样: 随机选取一批目标节点。
- 邻居采样: 对每个目标节点,递归采样K跳邻居,构建计算子图。
- 前向传播: 在子图上逐层聚合,计算目标节点的嵌入。
- 损失计算: 根据任务计算损失。
- 反向传播: 在子图上计算梯度,更新参数。
- 重复: 直到收敛。
| 方法 | 每epoch计算复杂度 | 内存占用 | 可扩展性 |
|---|---|---|---|
| GCN(全图) | O(|E|·d) | 高(需存储全图邻接矩阵) | 差(>10⁶节点时受限) |
| GraphSAGE(mini-batch) | O(B·S₁·S₂·d) | 低(仅存储batch子图) | 优(可扩展到10⁹节点) |
4.5 本章小结
GraphSAGE通过固定大小邻居采样解决了大规模图训练的计算瓶颈,通过可学习的聚合函数实现了归纳式学习。在团伙识别场景中,推荐使用Pooling Aggregator配合2层采样(S₁=25, S₂=10),在保持高表达能力的同时控制计算开销。前向传播逐层聚合邻居信息,反向传播在采样子图上高效计算梯度,使得模型能够端到端地学习团伙的拓扑特征。