图片是格子,句子是一行,一堆特征是一团数。
可一个分子、一群朋友没有「第一个」「第二个」,只有谁和谁连着。这一章给第四种数据形状补上课。
上一章《线性注意力与替代方案》换算法,数据还是排好队的:图片是网格、句子是一行、一堆特征是团成一个球的数。
现实里还有第四种:一堆点加一堆连线——一个分子有原子和化学键,一群人有朋友和来往,
城市之间有道路和航线,知识库里有实体和关系。换成图的说法,这些就是
麻烦在于普通网络只会收「排成一行的一串数」。那我们就把图排成一行试试: 下面这个 5 个原子的小分子,换一种编号,看排出来的那串数会怎么样。
互动 · 同一个分子,两种编号,两串数
右边这张 5×5 的表叫邻接矩阵(adjacency matrix):第 i 行第 j 列写 1,就表示 i 号、j 号之间有一条边。 换一种编号,同一张表只是行和列跟着重排。两串数长得完全不一样,但它们说的是同一个分子: 换成普通全连接网络,这就是两份毫不相干的输入;它费劲学到「第三个位置连着哪些位置」,一换编号就全对不上了。
所以图数据的第一条规则不是「怎么算」,而是「编号不重要,谁和谁连着才重要」。 这句话在数学里叫置换不变:编号怎么重排,答案都不该变。这一章的模型会从这条规则出发。
这是一个真实的故事。1977 年,Zachary 记下了一个空手道俱乐部里 34 个人之间谁常来往:34 个点、78 条线。后来教练和管理员闹翻,俱乐部真的裂成了两派。
现在假装我们几乎什么都不知道,只被告知一件事:0 号站在教练这边,33 号站在管理员那边。 每个人的「看法」记作 h,就是一个数:越正越偏教练,越负越偏管理员,0 表示还没表态。 规则也只有一条:每一轮,每个人听一听和自己常来往的人怎么看,取个平均,当成自己的新看法。 拖下面的滑块,看这条规则能不能把 34 个人分对。
规则只有一句话 · 听邻居,改自己
图里 v 是正在改看法的那个点,a、b、c 是它的三个邻居。
每个点同时做这件事:先把邻居的看法收上来,再加上自己,除以「自己 + 邻居的个数」。
文献里管这套动作叫
互动 · 只给两个人的标签,传几轮能把全俱乐部认出来
初始只有 0 号和 33 号有看法,其余 32 个人的 h 都是 0(灰)。
往下拖之前,先押一个:
先把滑块拖到 2 和 3:2 轮之后 34 个人全部表了态、猜对 32 人(94%),3 轮猜对 33 人(97%)。 从头到尾没人告诉它俱乐部该怎么分,它只知道谁和谁常来往。
再把滑块拖到 20、30、40:猜对的人反而掉到 30 人(88%)、23 人(68%)、17 人(50%)。
勾上「显示真实派别」,你会看到所有点的颜色越来越像——消息传得太远,大家的看法被互相抹平了。
这个现象叫
还有一个例外值得盯住:8 号——Zachary 论文里的 9 号,论文从 1 开始给节点编号,本页从 0 开始。 它的 5 个朋友里有 3 个后来站在管理员那一派,它自己却去了教练派——规则一直把它算错。 模型没有坏,是这张图里本来就藏着一个不随大流的人。
图神经网络做的事只有一件:每一轮,每个点都听一听邻居,再改一改自己。
第 2 节那条规则拆开只有两步:把邻居的看法收上来、平均一下、写成自己的新看法。 传一轮听到「朋友」,传两轮听到「朋友的朋友」。所以一个点能听多远,只取决于传了几轮。
互动 · 点一个点,看它几步以内能听到谁
右边那行算式是现算的:8 号在第 1 轮之后听到了朋友们的看法,加上自己平均一下, 就得到它第 2 轮的新看法。点别的点,数字会整个换一套;规则不变,变的只是邻居是谁。
同一件事,两种说法:CNN 看几圈像素,GNN 听几步邻居
这不是譬喻:CNN 的「几层」和 GNN 的「几轮」买的是同一件东西: 一个神经元/一个点的信息,能走多远。
这份直觉和 《感受野》那一章是同一件事的两面: CNN 叠一层,一个神经元往外多看一圈像素;GNN 传一轮,一个点往外多听一步邻居。 图上的「感受野」有多大,就看你传了几轮。
第 2 节那条规则里,「平均」是写死的:每个邻居说的一样重。可真实的数据里, 不同的邻居说的话本来就该有不同的分量。把平均换成「先按朋友数打个折、再乘一张表 W、过一个激活函数」, 这条规则就从写死变成了能学的,这才是 GNN 那一层真正的样子。
公式卡 · 一层 GNN 在算什么
W 是旋钮,学的是「听到的话怎么翻译成自己的看法」;σ 是那个折一下的 激活函数;d_v、d_u 是两个点各自的朋友数 +1(把自己也算一个邻居)。 把那一项取成 1 ÷(自己 + 邻居个数)、W 取成 1、σ 什么也不做,这条式子就退回第 2 节的纯平均。 所以新东西只有两处:邻居的汇总方式,和汇总之后的翻译方式。
互动 · 真的训练一个:只用两个人的标签
每个人没有任何特征,只是一个编号;网络只被告知 0 号、33 号两个人站哪边。 两层 GNN(隐藏 4 个神经元)、300 步、学习率 0.2,全部现算。
同一场训练 · 损失一路往下掉
横轴是步数(0~300),纵轴是 0 号和 33 号两个人的交叉熵平均。
两层就是第 2 节说的传两轮:每层做一次「听邻居、改自己」,第二层听到的已经是「朋友的朋友」。 训练完通常能猜对 33 个人;错的那个总是 8 号——正是第 2 节那个人。 只标 2 个人也够,是因为每传一轮,这两个标签就被各自的邻居平均一次、往外扩一圈, 同一个圈子里的人互相听,看法很快趋同——剩下 32 个人的派别就是这么被顺带分出来的。
第 M 节那张卡,其实就是 GCN 那一层。它留了两处可以动:邻居的消息怎么汇总、汇总之后怎么翻译成自己。 下面这张表里,第一行是 GCN 自己,另外四种方法各换它的一处。 表里的记号统一看:v 是要更新的点,u 是它的某个邻居,Σ_u 表示把每个邻居那一项加起来, d_v、d_u 是两边朋友数 +1(把自己也算上);分号表示把两个向量接在一起;M 负责把邻居的消息拼成一条,U 负责把它并进自己,ε 是一个可学的小数;e_vu 是 u→v 那条边自带的信息(比如友谊亲疏),边没有额外信息就省略。
一张卡,五个地方可以改
| 方法 | 它把卡上哪一处换了 | 一行公式 | 年份 |
|---|---|---|---|
| GCN(图卷积网络) | 平均时按两边朋友数 +1(把自己也算上)的开根号加权,朋友特别多的点自动说轻一点 | h′ = σ( Σ_u W·h_u / √(d_v·d_u) ) | 2017 |
| GraphSAGE | 朋友多到听不完,就只随机抽固定几个来听 | h′_v = σ( W·[h_v ; 平均(抽到的 h_u)] ) | 2017 |
| GAT(图注意力网络) | 不一律平均,给每个朋友算一个「该听多少」的权重 α | h′_v = σ( Σ α_vu·W·h_u ) | 2018 |
| MPNN(消息传递网络) | 消息不只来自邻居,边上也带信息(比如化学键的类型) | m_v = Σ_u M(h_v, h_u, e_vu) h′_v = U(h_v, m_v) | 2017 |
| GIN(图同构网络) | 把平均换成求和,让模型分得清更多形状 | h′_v = MLP( (1+ε)·h_v + Σ_u h_u ) | 2019 |
注意 GAT 那一行:给每个朋友一个「该听多少」的权重——那个东西就是 注意力。反过来看,Transformer 就是「每个词都连着每个词」的 GAT: 图里人人互为邻居,谁该听谁全部由数据自己算。所以两章讲的是同一件事,只是一个从图出发,一个从句子出发。
| 用在哪 | 代表工作 | 它做到了什么 |
|---|---|---|
| 天气 | GraphCast(Lam 等,2023) | 把地球表面铺成图做 10 天全球预报,分辨率 0.25°,一次算完不到 1 分钟; 在事先定好的 1380 个考核指标(各高度、各变量、各预报时长)里,有 90% 比传统数值模式更接近实况 |
| 材料 | GNoME(Merchant 等,2023) | 批量筛出 220 万个候选晶体结构,其中 38.1 万个是此前未知的稳定材料 |
| 分子性质 | MPNN 一路的模型 | 把分子当图算量子化学性质,「消息传递」这个说法就是从那里来的 |
第 2 节已经露过一次马脚:传得越多,猜对的人反而越少。这一节把 GNN 的几笔账算清楚。
猜对率随轮数先升后降(数据和第 2 节同一份)
| 这笔账 | 什么时候真的会痛 | 换成什么 |
|---|---|---|
| 过度平滑 over-smoothing |
任务要靠长距离上的差异(比如找关键人物、分开两个社区)时; 图越大、传得越多,大家的看法越趋同,信息被互相抹掉 | 常见做法是 2~3 层(Kipf 正文用两层),先试 2 层看验证集再决定要不要加;加残差(把上一层的输出直接加到下一层)或门控(像开关一样决定留多少);回看第 2 节滑块拖到 40 的样子 |
| 信息挤在独木桥上 over-squashing |
图有「细腰」:两头很多点,中间只有一两条边。远处的消息全要从这里过, 就像下班高峰只开一个闸口 | 重新布线、加一个和所有点都相连的虚拟节点,或改用全连接的注意力(就是第 4 节那条回链) |
| 有些形状它分不出 | 两个三角形和一个六边形,每个点都恰好 2 个朋友,这套规则给它们的读数完全一样, 但它俩是不同的分子 | 换聚合函数(把邻居汇总起来的那一步;GIN 用求和)、加边上或点上的额外特征;见下面那张小图 |
| 大图算不动 | 图有上亿个点、边还在长:一个点的三步邻居可能是几百万人,整张邻接矩阵根本放不下 | 邻居采样(GraphSAGE)、把大图切成小块(子图采样),拆成小批来练 |
互动 · 两个三角形和一个六边形,读数永远一样
每个点都恰好有 2 个朋友,一开始的值又一样,于是「平均」这一步在两张图上算出完全相同的结果。 一个分子是两个三元环还是一个六元环,化学性质天差地别;最朴素的 GNN 看不出—— 这是 GIN 把平均换成求和的理由(第 4 节表里最后一行)。
这一章站在「② 没有免费午餐」上:它先把「编号不重要、只看谁和谁连着」写成一条假设。 这条假设帮它只用两个标签猜对 33 个人,也让它分不出两个三角形和一个六边形。它同时站在 ⑥ 层层组合上:传 k 轮 = 叠 k 层。
回第 2 节,把「传几轮」滑块从 3 拖到 40:猜对的人数从 33 人掉到 17 人,图上颜色一点点糊成一片。
再去第 5 节点几下「传一轮」:左边两个三角形和右边一个六边形,读数永远一模一样——那是这套规则的天花板。
| 暗线 | 这一章的回答 |
|---|---|
| A 信息流动 / 它假设了什么 | 数据是「点 + 边」,信息沿边走:传 k 轮,一个点就听到 k 步以内所有邻居的消息(第 3 节)。 它假设「谁和谁连着」比「编号顺序」重要(置换不变),也假设消息只来自邻居(局部性)—— 比 Transformer 省,但也比 Transformer 看不见远处 |
| C 参数账本 | 输入特征是每个点一行。第 M 节这里每个点用一个 34 维的独热编码(自己的那一维是 1,其余是 0), 两层 W 的大小由特征维度决定,是 34×4 和 4×2,一共 34×4 + 4×2 = 144 个参数; 34 个点共用同一套 W。但换更多点时特征维度也要跟着变,所以真实任务里用点自带的特征,而不是独热。 |
| D 跑在什么上 | 带宽受限的那一类。图是不规则的读写:每个点要捞哪些邻居,事先不整齐, 喂不满张量核心;大图还得先做邻居采样,GPU 常常在等内存而不是等算力 |
它接住了《线性注意力与替代方案》什么:上一章换算法,这一章换数据——只看连着谁。 它接住了《感受野与下采样》什么:图上「看多远」和 CNN 的「看多大一块」是同一笔账(第 3 节)。 它接住了《注意力机制》什么:GAT 那一行给每个朋友算的权重就是注意力(第 4 节)。
它给后面留了什么:标签很少、关系很多时,把结构写进模型收益最大。下一章《扩散语言模型》换掉的是「生成顺序」先验。
图就是「点 + 连线」。GNN 给它的规则只有一条:每一轮,每个点听一听邻居、改一改自己; 传几轮就听到几步以内的点,所以层数本身是个要付代价的选择。
上面讲的都是「够用」的版本。想往下挖,这里有两个入口—— 它们不是必修内容,是给想再往前走一步的读者准备的。