经典图模型与节点分类实践:参考答案#
说明#
以下答案与正文10道题逐题对应。前四题给出主要推导与计算;第 5--7 题给出可以运行的程序和检查方法;第 8--10 题说明比较时需要保持哪些条件相同,以及实验结果能够说明什么、不能说明什么。
邻居均值为 \((1+3+5)/3=3\),拼接向量为 \([2,3]\)。线性运算和 ReLU 给出
\[\begin{split}[2,3]\cdot \begin{bmatrix}1&-1\\0.5&0.5\end{bmatrix} =[3.5,-0.5], \qquad \operatorname{ReLU}([3.5,-0.5])=[3.5,0].\end{split}\]GraphSAGE 的拼接保留了自身与邻居均值的两个来源;若先把自身混入邻居 mean,所实现的是不同更新规则。
两个多重集合的均值分别为
\[\frac{\bx}{1}=\bx, \qquad \frac{\bx+\bx}{2}=\bx,\]因而 mean 无法保留重复次数;sum 分别为 \(\bx\) 和 \(2\bx\),当 \(\bx\ne\boldsymbol{0}\) 时不同。GIN 使用 sum 为后续 MLP 保留更多多重性信息,但结论还依赖有限特征域和足够表达力的映射;一维 WL 本身也存在无法区分的非同构图,有限宽度、训练误差与数值精度会进一步限制实际模型。
邻居和为 \(1+3+5=9\)。当 \(\epsilon=0.5\) 时,MLP 输入和输出为
\[(1+0.5)2+9=12.\]当 \(\epsilon=0\) 时结果为 \(2+9=11\);当 \(\epsilon=-1\) 时自身项被消去,结果为 9。若 MLP 不是恒等映射,这些数先作为 MLP 输入,最终输出还取决于其参数和非线性。
忽略重叠时,节点出现次数上界为
\[128(1+10+10(5))=7808,\]采样边数为 \(128[10+10(5)]=7680\)。一般公式为
\[N_{\mathrm{occ}}=m(1+s_1+s_1s_2), \qquad M_{\mathrm{sample}}=m(s_1+s_1s_2).\]全邻居且平均度为 \(d\) 时,相应上界约为 \(m(1+d+d^2)\)。真实图中邻居会重叠,去重可降低唯一节点数,但某些采样管线仍按出现次数执行或存储消息,所以必须报告实际采样统计。
一个明确使用随机生成器的最小采样器为
import numpy as np def sample_neighbors(adjacency, targets, fanout, rng): sampled = [] for node in np.asarray(targets, dtype=np.int64): neighbors = np.unique(np.asarray(adjacency[int(node)], dtype=np.int64)) if len(neighbors) == 0: chosen = np.asarray([node], dtype=np.int64) # 明确采用自环策略 elif len(neighbors) <= fanout: chosen = neighbors else: chosen = rng.choice(neighbors, size=fanout, replace=False) sampled.extend((int(src), int(node)) for src in chosen) return np.asarray(sampled, dtype=np.int64).T def sage_mean(x, edge_index, targets, weight): send, receive = edge_index aggregate = np.zeros((len(x), x.shape[1]), dtype=float) count = np.zeros(len(x), dtype=np.int64) np.add.at(aggregate, receive, x[send]) np.add.at(count, receive, 1) if np.any(count[np.asarray(targets)] == 0): raise ValueError("目标节点没有采样邻居") mean = aggregate[targets] / count[targets, None] joined = np.concatenate([x[targets], mean], axis=1) return np.maximum(joined @ weight, 0.0)
两个同种子的生成器应产生相同边。未见节点只要在特征表和当前可见邻接表中存在,就可使用共享参数前向;训练时不能偷用部署时不可见的边。
先对发送节点状态按接收端点做 sum,再加 \((1+\epsilon)\boldsymbol{h}_v\) 并送入 MLP。固定 \(\epsilon\) 可存为普通常数,可学习时应注册为参数。第 2 题验证重复边或重复邻居使 sum 改变,第 3 题核验自身项;再用小图按照 手算结果与可信实现对照 的原则比较循环版与库层,并对输入、MLP 参数和 \(\epsilon\) 梯度做 自动微分对照。
置换测试应等变;孤立节点只保留自身项;高阶节点输入尺度可能很大,应检查有限性并结合归一化。重复边究竟表示多重关系还是数据重复必须在预处理中规定,不能无意改变 GIN 输入。
掩码检查包括维度一致、两两互斥且均非空。归纳设置还应给每条训练边检查两端是否属于训练时可见节点集合;时间图则检查边时间不晚于训练截止点。故意加入一条测试节点到训练节点的未来边,检查程序必须失败。GraphSAGE 前向只依赖共享参数、目标特征和传入邻域,因此可对新节点运行;但这只证明程序可执行,不保证新分布上的预测准确。
所有模型使用一次性确定的数据划分,以及相同的输入特征、随机种子、近似参数量范围和最大更新次数,并使用同一个验证集和相同标准选择模型;MLP 作为不使用图结构的对照模型。还应记录 GraphSAGE 的邻居采样随机种子、GAT 的注意力头数和实际计算的边得分数。报告准确率、macro-F1、训练时间、固定节点批量预测时间、峰值内存、参数量、实际处理边数与图层运行次数。
不同模型可以在同一个验证集上尝试相同的一组学习率,并按照相同标准选择,但不能使用测试集作出选择。传导学习和归纳学习的结果不能混在一张表中;如果模型能够使用的边不同,应在结果中写清楚每个模型能够使用哪些边。
所有扇出使用相同划分、模型宽度、种子集合、更新次数、目标节点批量大小和评价代码;对每次采样记录实际节点、边数。推断可以固定邻居集合比较确定性成本,也应补充多次随机采样的预测均值与波动。报告测试指标、训练和固定批量预测时间、峰值内存、采样规模与层调用次数。
较大扇出通常减小采样偏差但增加计算,不一定单调提高精度;全邻居消除采样随机性,却可能在高阶图上不可承受。若不同扇出导致每次更新处理的消息数不同,应同时给出固定更新次数和近似固定消息预算的结果。
先保留同一节点特征和标签划分,真实图与随机重连图尽量保持节点度分布;MLP 去除消息传播;结构特征模型只输入预先定义的度数等特征。固定种子集合、参数量范围、更新次数和评价程序,报告测试指标、训练与固定批量预测时间、峰值内存、实际边数和层调用次数,并计算同标签边比例等同质性指标。
如果真实图上的结果优于随机重连图和 MLP,只能说明给定的边与这个任务相关,还不能证明这些边是性能变化的原因;在异质图上,简单平滑还可能降低性能。如果随机重连同时改变了节点度、图的连通性或数据划分边界,就无法判断结果究竟由哪一项变化造成,因此必须检查并报告这些统计量。