新学期结束,教务处让每个班主任交一张“班级总评表”。班里几十个学生,每个人有语文、数学、英语三科成绩;教务处不要花名册,只要一行字:这个班整体怎么样?你要做的,就是把单个学生的信息浓缩成一句评语。图神经网络里的读出函数,干的正是这件事。先让节点特征经过消息传递层层更新,最后再用读出函数把所有节点向量合并成一个图级向量,为图分类、分子性质预测等任务提供判断依据。不同的总结方式——总分、平均分、最高分、按名次选尖子——就对应求和、平均、最大、排序等读出策略。
掌握读出函数,等于学会给 GNN 的“班级画像”收尾;图分类、分子属性预测这类图级任务的最后一公里,都靠它把节点特征变成模型能用的图特征。
可视化演示
\u5c55\u793a\u6c42\u548c\u3001\u5e73\u5747\u3001\u6700\u5927\u6c60\u5316\u4e09\u79cd\u8bfb\u51fa\u7b56\u7565\u5bf9\u6bd4\uff0c\u4ee5\u53ca\u6392\u5e8f\u6c60\u5316\u7684\u7ed3\u6784\u4fdd\u6301\u7279\u6027\u4e0eTop-K\u9009\u62e9\u8fc7\u7a0b\u3002
本节配有交互动效(进入视口后自动加载,约 3KB)。
\u8bfb\u51fa\u5bf9\u6bd4\u6a21\u5f0f SUM=\u6240\u6709\u8282\u70b9\u503c\u4e4b\u548c(3.20)\uff0c\u4fdd\u7559\u603b\u91cf\u4fe1\u606f AVG=\u5747\u503c(0.53)\uff0c\u5bf9\u56fe\u5927\u5c0f\u4e0d\u654f\u611f SUM=\u03a3h_i, AVG=\u03a3h_i/N, MAX=max(h_i)
图级任务需求
教务处让班主任交一张“班级总评表”,可班里几十个学生,总不能把花名册直接交上去。班主任必须把每个人的信息浓缩成一行评语:“这个班整体学风扎实、特长突出。”在图神经网络里,这一行评语就是图级向量,而负责浓缩的班干部就是读出函数。
在图神经网络中,每个节点经过若干轮消息传递后,会得到一个向量表示 \(h_v\)。如果任务是判断某个节点属于哪一类,直接拿节点向量去分类就行;但如果任务是判断整张图的类别,比如“这张分子图是否有毒性”“这个社交网络是否是垃圾群组”,就必须把图上所有节点的特征合并成整个图的特征。这个合并动作,正是图级读出。
读出函数通常放在所有 GNN 层之后,是图分类任务的最后一步。它的输入是一组节点向量,输出是一个定长的图向量 \(h_G\)。有了 \(h_G\),再接一个分类器,就能完成图级别的分类或回归。
这就像你最后写在表上的那句总评:学生还是那些学生,但评价对象已经从“每个人”变成了“整个班”。
- 取出全部节点把最后一层所有节点特征放进同一个集合,这里的 \(L\) 表示最后一层。
- 施加读出函数用求和、平均、取最大等汇总运算遍历整个节点集合。
- 得到图向量聚合结果就是整张图的表示,记作 \(h_G\)。
读出原理
无论学生按学号排还是按身高排,班级总评都不该变。图本身没有天然顺序,节点只是一个个元素的集合;如果打个乱节点顺序,图向量就变了,模型就会像“换个座位就看不出是同一个班”的老师一样不可靠。
这正是读出函数必须满足的核心性质:置换不变性。所谓置换不变性,是指把图的节点顺序任意打乱,最终输出的图向量保持不变。求和、平均、最大这类基础池化天然满足这个性质;排序池化本身也是先对节点排序再选取,因此排序结果同样不依赖节点输入的先后顺序。
班级画像不会因为学生换了座位就变成另一个班,这正是读出函数最可贵的品格。
- 定义节点集合原始图中所有节点构成集合 \(V\),\(\pi\) 表示任意一种排列方式。
- 交换节点顺序把每个节点换到新的位置上,但集合内容没有变。
- 读出结果不变读出函数对集合做汇总,因此集合内容不变,结果也就不变。
求和池化
班主任最直观的总结方式,是算全班总分。把每个学生的各科成绩都加一遍,得到一个“总分向量”。总分高,说明这个班整体“体量”大;但也正因如此,班里人数越多,总分通常越高。
求和池化就是对所有节点特征逐维相加:
它的优点是实现简单、保留总量的信息;缺点是对图规模敏感。两张结构相似的图,仅因为一张图的节点数更多,求和后的向量就可能整体偏大。好在分子性质预测这类任务里,分子的大小往往本身就有意义,因此求和池化仍是常用的强基线。
总分最高的班,不一定每门课都最强,但它一定拥有更大的“总量”——求和池化捕捉的正是这种规模感。
- 逐维累加对特征向量的每一维分别累加,符号 \(\sum\) 表示累加。
- 所有节点都参与每个节点特征 \(h_v\) 都被加入最终结果,一个都不能少。
- 得到同维图向量输出向量的维度和单个节点特征维度一致,但含义已从“单个节点”变成“整张图”。
平均池化
如果教务处要看“这个班整体水平怎么样”,总分就会被人多的班占便宜。聪明的班主任会改报平均分:把总分除以人数,得到一个不受班级人数影响的指标。
平均池化就是把求和结果除以节点数量:
平均池化的优势是减少了图规模带来的偏差。当图的大小差异很大,而我们希望模型更关注“整体水平”而非“总量”时,平均池化更稳定。代价是它丢失了节点总数这一信息:两个平均分相同的班,一个 20 人、一个 40 人,在图向量里看不出区别。
平均分能公平比较人数不同的班级,但也掩盖了“班级大小”这个本来可能有用的信息。
- 先求总和把所有节点特征逐维相加,得到总量。
- 统计节点数量计算图的节点个数 \(|V|\)。
- 除法归一化用总量除以节点数,得到每个节点特征的平均水平。
最大池化
有时教务处只想看“这个班最亮眼的科目是哪科”。比如要评“数学特色班”,只看全班数学最高分就够了。最大池化就是这种“单项冠军”思维。
最大池化对特征向量的每一维,在所有节点中取最大值:
其中 \([h_v]_i\) 表示节点 \(v\) 特征向量的第 \(i\) 维。最大池化擅长捕捉“图中是否存在某种突出信号”,比如分子中是否存在某个关键的化学基团。但它只保留了每个维度上最极端的那个值,大量关于分布、次数、普通节点的信息都被丢弃。
只看最高分,能快速发现“最闪光的科目”,但也可能漏掉全班整体偏科、只有一个人拔尖的真相。
- 取第 \(i\) 维只看特征向量的某一维,例如“数学成绩”这一列。
- 遍历所有节点在这一列上比较每个节点的数值。
- 写入图向量把找到的最大值放到图向量的第 \(i\) 个位置。
排序池化
如果班主任要推选“年级前十名”,不能只算总分,还要先按综合表现排序,再重点介绍前面的尖子生。排序池化就是这个思路:先给每个节点打分排序,再取前 \(k\) 个节点作为图的代表。
这里 \(s(v)\) 是节点 \(v\) 的排序分数,可以由模型学习得到。排序后取前 \(k\) 个节点,把它们各自的特征拼接成一个长向量。这个输出向量的维度是 \(k \times d\),\(d\) 是节点特征维度。相比求和、平均、最大,排序池化保留了更多“顺序结构”信息。
尖子榜不是每个学生都上榜,而是按名次挑出最有代表性的前几名,再把他们组合成班级印象。
- 给节点打分用函数 \(s(v)\) 计算每个节点的排序分数。
- 排序并截取把全部节点按分数从高到低排列,只保留前 \(k\) 个。
- 拼接成图向量把选出的 \(k\) 个节点特征展平,变成一维长向量。
注意力读出
有经验的班主任总结班级时,不会把每个学生看得一样重:班长说的话多一点,平时沉默的学生少提一点。这种“谁更重要”的判断,就是注意力读出。
注意力读出先给每个节点学一个分数 \(s_v\),再用 softmax 归一化成权重 \(\alpha_v\),最后做加权求和:
其中 \(w\) 是可学习的参数。权重越大,代表该节点对整张图贡献越大。注意力读出比朴素求和、平均更灵活,因为它能根据任务自动决定“哪些节点更值得听”。也可以加入门控机制,用 sigmoid 之类的方式控制信息流,进一步增强表达能力。
班主任心里有杆秤,注意力读出就是让模型自己学会这杆秤。
- 计算原始分数用可学习向量 \(w\) 点乘节点特征 \(h_v\),得到分数 \(s_v\)。
- softmax 归一化把所有分数指数化后相加,再逐个相除,得到总和为 1 的权重。
- 加权求和每个节点特征乘上自己的权重后相加,得到图向量。
实践选择
不同报告需要不同的总结方式:家委会想看总分,教育局想看平均分,表彰会看最高分,推优看名次。图任务也一样,没有一种读出策略能通吃所有场景。
实践中的选择逻辑可以这样看:如果图的大小本身有语义,比如分子越大性质越不同,求和池化常常更有优势;如果图大小差异大而任务与规模无关,平均池化更稳定;如果任务关心“是否存在某个极端信号”,最大池化更合适;如果关心节点之间的顺序结构,排序池化更合适;如果希望模型自动决定节点重要性,注意力读出更灵活。
读出函数得到图向量后,通常还会接一个下游分类头:
策略没有绝对好坏,只有是否匹配任务。多跑几次对比实验,比争论“哪个池化最好”更有价值。
- 线性映射把图向量 \(h_G\) 乘以权重矩阵 \(W\),加上偏置 \(b\)。
- softmax 归一化把每个类别的得分变成概率,且所有类别概率之和为 1。
- 输出预测类别取概率最大的类别作为整张图的预测结果 \(\hat{y}\)。
AI 应用场景
药物分子性质预测
阶段:图分类 / 分子属性预测
解决的问题:传统方法需要人工设计分子指纹或大量化学特征,工作量大且容易遗漏原子之间的连接结构。GNN 把原子看作节点、化学键看作边,消息传递学到原子表示后,再用读出函数得到整个分子的图向量,端到端预测水溶性、毒性等性质。
具体案例:某制药公司要筛选一万个候选分子,判断是否容易透过血脑屏障。模型先用 GIN 消息传递层更新原子特征,再用求和池化把分子图变成固定长度的图向量,最后接分类器输出“可透过/不可透过”。在公开的 MoleculeNet 数据集上,这种方案能显著减少人工特征工程。
社交网络群体分类
阶段:图级表征学习
解决的问题:判断一个用户群体是不是垃圾广告群,不能只看单个用户,还要看整个子图的结构和互动模式。传统规则容易误伤正常群组,AI 需要把整张子图压缩成一个向量再分类。
具体案例:风控团队把某个群聊的 7 天交互记录构造成一张图,每个用户是节点,消息互动是边。GNN 学习用户嵌入后,用平均池化得到群体向量,避免人数差异对判断的干扰,然后预测该群是否包含恶意导流行为。
程序代码缺陷检测
阶段:图分类 / 静态分析
解决的问题:把一段代码抽象成控制流图或抽象语法树,节点是语句或变量,边是跳转与依赖关系。判断代码片段是否有缺陷,需要对整张代码图做分类,而不是只看某一个节点。
具体案例:安全团队用图神经网络分析开源项目的函数级代码图,使用排序池化保留关键语句的先后顺序,再将图向量输入分类器,识别是否存在内存泄漏风险。排序池化对“先分配后释放”这类顺序依赖特别敏感。
Python 演示
import numpy as np def sum_readout(h): return np.sum(h, axis=0) def mean_readout(h): return np.mean(h, axis=0) def max_readout(h): return np.max(h, axis=0) def sort_readout(h, k): scores = h.sum(axis=1) idx = np.argsort(scores)[::-1][:k] return h[idx].reshape(-1) if __name__ == "__main__": np.random.seed(42) node_features = np.random.rand(6, 3) print("node_features:\n", node_features) print("sum:", sum_readout(node_features)) print("mean:", mean_readout(node_features)) print("max:", max_readout(node_features)) print("sort top2:", sort_readout(node_features, 2))
def sum_readout(h):定义求和池化函数。return np.sum(h, axis=0)axis=0表示按“所有节点”这一轴求和,即逐维相加。np.mean(h, axis=0)对所有节点求平均,等效于平均池化。np.max(h, axis=0)对所有节点逐维取最大值。scores = h.sum(axis=1)给每个节点算一个综合分,是排序池化的排序依据。idx = np.argsort(scores)[::-1][:k]按综合分倒序排列,取出前 \(k\) 个节点的下标。return h[idx].reshape(-1)把选中的 \(k\) 个节点特征展平,得到排序池化输出。
常见误区
误区很多人以为读出函数就是 `Linear` 或全连接层,写模型时直接在节点特征后接一个全连接层当作图输出。
正解全连接层只是对向量做线性变换,并不负责把多个节点合并成一个向量。读出函数的核心是“跨节点聚合”,先把 \(N\) 个节点向量变成 \(1\) 个图向量,之后才轮到全连接层做分类。好比班干部负责把全班的成绩汇总成一张表,教务处才负责给这张表评等级。
为何常见:因为很多分类模型最后一层都是全连接层,初学者容易把“输出层”和“聚合层”混为一谈。
误区看到某些论文说求和池化表达能力更强,就以为任何图任务都应该无脑用求和。
正解求和池化对图规模敏感,图越大向量数值越大。如果任务本身和图的规模无关,比如判断社交子图的用户密度,求和池化可能带来偏差。平均池化、最大池化、注意力读出各有适用场景,必须用验证集对比。
为何常见:论文结论往往基于特定数据集,容易让人忽略任务本身的差异。
误区最大池化听起来“最大最强”,有人认为它能把最重要的信息都留下来。
正解最大池化每个维度只保留一个最大值,把所有非最大值的分布信息全部丢弃。如果任务需要知道“有多少个节点具备某种特征”,最大池化完全无能为力。它更像只表扬最高分,却忽略了班级的整体水平。
为何常见:因为“最大值”天然带有显著性,容易让人误以为显著就等于信息完整。
误区实现排序池化时,以为必须把所有节点都保留,否则会丢失信息。
正解排序池化的核心价值恰恰是只取前 \(k\) 个节点,用固定长度的输出对齐不同尺寸的图。如果把所有节点都保留,图的节点数一变,输出维度就变了,无法直接拼 batch 做分类。
为何常见:初学者对“降维”有本能抗拒,总担心截断会丢信息,但图级任务本来就要求定长输出。
面试题
Q1. 读出函数最核心的任务是什么?
- A.把节点向量聚合成图向量← 正确答案
- B.把图向量拆成节点向量
- C.给节点特征增加维度
- D.把边特征变成点特征
答案:A。读出函数把一整组节点向量汇总成一个图向量,这是图分类任务的最后一步。把图向量拆开、增加维度、边特征转点特征都不是读出的职责。
Q2. 求和池化在图规模变大时可能出现什么问题?
- A.图向量数值整体偏大← 正确答案
- B.图向量数值整体偏小
- C.图向量维度自动增加
- D.图向量维度自动减少
答案:A。求和池化把所有节点特征逐维相加,节点越多,累加结果越大。它改变的是数值大小,不会改变输出维度。
Q3. 平均池化相比求和池化的主要优点是什么?
- A.减少图规模带来的偏差← 正确答案
- B.保留图的节点总数信息
- C.让输出维度变成可变
- D.不需要读取任何节点信息
答案:A。平均池化先求和再除以节点总数,把图规模的影响归一化,因此对节点数不同的图更公平。它不会保留节点总数,也不会改变输出维度。
Q4. 最大池化对每个维度做什么操作?
- A.取该维度所有节点的最大值← 正确答案
- B.取该维度所有节点的总和值
- C.取该维度所有节点的平均值
- D.取该维度所有节点的中位值
答案:A。最大池化是逐维比较所有节点,只保留该维度上的最大值。求和给总和,平均给均值,中位给中间值,都不是最大池化的定义。
Q5. 关于置换不变性,下列说法正确的是?
- A.节点顺序改变时输出保持不变← 正确答案
- B.节点顺序改变时输出随之变化
- C.只有求和池化能做到顺序无关
- D.读出函数不需要关心顺序问题
答案:A。读出函数必须满足置换不变性:无论节点输入顺序如何打乱,图向量都不变。求和、平均、最大都满足,排序池化通过排序也满足,不是只有求和池化能做到。
Q6. 排序池化输出向量的维度由什么决定?
- A.由节点数量加特征维度决定
- B.由特征维度和选取的k值决定← 正确答案
- C.由图边数加上节点数决定
- D.由消息传递的层数多少决定
答案:B。排序池化取前 \(k\) 个节点,每个节点特征维度为 \(d\),展平后输出维度是 \(k \times d\)。节点总数和边数只决定候选集合,不影响最终输出维度。
Q7. 注意力读出中的注意力权重通常如何得到?
- A.对节点打分后做softmax归一化← 正确答案
- B.对节点特征直接求平均处理
- C.随机固定而且不参与任何训练
- D.只根据节点自身的度数来计算
答案:A。注意力读出先给每个节点算一个可学习分数,再用 softmax 把所有分数归一化成权重,权重总和为 1。直接求平均是平均池化,随机固定或只看度数都不需要训练。
Q8. 以下哪些属于常见的读出函数?
- A.求和池化← 正确答案
- B.平均池化← 正确答案
- C.最大池化← 正确答案
- D.最短路径
答案:ABC。求和、平均、最大是最基础的三种读出函数。最短路径是一种图算法,用来计算节点之间的距离,不是把节点特征变成图特征。
Q9. 关于读出函数的描述,哪些是正确的?
- A.通常在GNN层之后使用← 正确答案
- B.把节点集合变成图向量← 正确答案
- C.图分类任务依赖图级输出← 正确答案
- D.输出维度和节点数相同
答案:ABC。读出函数一般放在所有消息传递层之后,把一组节点向量聚合为图向量,供图分类任务使用。输出维度由特征维度决定,和节点数量没有必然关系。
Q10. 选择读出策略时需要考虑哪些因素?
- A.图规模是否变化较大← 正确答案
- B.任务关注总量还是极值← 正确答案
- C.是否需要保留顺序信息← 正确答案
- D.是否使用ReLU激活函数
答案:ABC。图规模大且与任务无关时平均更稳,任务关注总量时求和更合适,关注极值时最大更合适,关注顺序时排序更合适。激活函数是消息传递层里的选择,不属于读出策略选择的决定性因素。