尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

把链接预测当作影响力传播:多关系图建模新思路

把链接预测当作影响力传播:多关系图建模新思路 多关系图上的链接预测之前我做过不少实验通常都是把不同关系类型拆开算特征或者直接用关系图神经网络做消息传递。最近我认真试了一个新视角把链接预测当作影响力传播过程来建模。这个思路不只是换了个说法而是把“关系怎么产生”这个因果问题引入建模整个数据构造、训练方式、可解释性都会跟着变。如果你也在处理知识图谱、社交网络、异构网络这类多关系图这个视角值得花时间理解。下面我会从实际实验的角度拆解它到底解决什么问题、需要准备什么、怎么落地以及容易踩哪些坑。1. 从影响力传播角度看链接预测到底改了什么1.1 多关系图链接预测的传统思路多关系图通俗说就是节点之间不只一种连接方式。比如知识图谱里的“出生地”“任职于”“获奖”是不同关系社交网络里的“关注”“点赞”“好友”也是不同关系。链接预测要解决的问题就是判断两个节点之间是否可能存在某种尚未记录的关系或者未来会不会产生某种关系。传统做法主要分三类。第一类是结构相似度方法。把多关系图拆成多个单关系子图在每个子图上算共同邻居、Jaccard、Adamic-Adar 等指标再把各种关系下的分数加权合并。优点是简单缺点是只利用直接邻居或低阶路径关系类型之间的交互很难建模。第二类是图神经网络方法。典型代表就是关系图卷积网络 R-GCN 这类模型每种关系类型对应一个独立的变换矩阵消息传递时先按关系类型投影再聚合邻居信息。这种方法能捕捉多跳结构但对每个关系类型都定义独立矩阵关系很多时参数膨胀很快。第三类是知识图谱嵌入方法。把三元组 (头节点, 关系, 尾节点) 看作打分对象用 TransE、RotatE 等模型把实体和关系映射到向量空间。这类方法擅长处理知识图谱但多数模型没有显式建模影响如何沿着路径扩散很难解释一条边为什么被预测出来。这些传统思路有一个共同点关系是被当作一种静态分类标签。模型需要学习“有这种关系则两种实体在向量空间满足某种约束”而不是问“这种关系从哪里来经过哪些节点传播到目标”。1.2 影响力传播视角的核心转变影响力传播视角把链接预测重新定义为一个扩散过程。假设某个源节点有一个“影响信号”这个信号会沿着不同类型的边向外传播。当一个信号经过多跳路径最终抵达某个目标节点就说明这两个节点之间存在潜在链接。这个转变带来的第一好处是让多跳路径有了明确含义。传统方法里二阶邻居、三阶邻居只是图结构上的远近在影响力传播视角下每一跳对应一次真实的信息传递或影响扩散。比如社交网络里用户 A 转发内容到粉丝 BB 又转发到 C那么 C 和 A 之间的距离虽然远但存在传播链上的关联。如果只看共同邻居很难表达这种链式影响。第二好处是关系类型可以统一成传播信道。不同关系可以看成不同的传播通道每条通道有自己的传播强度、方向和衰减特性。知识图谱里“导师”关系的传播强度可能很高“打过一次招呼”的传播强度就很低。这个建模方式比单纯的边类型嵌入更接近真实场景。第三好处是预测结果自带解释。优化得好时模型不仅能给出链接得分还能指出得分来自哪几条传播路径。比如推荐好友时系统可以说“因为你关注的技术博主和这个人有合作关系而且这条技术领域路径传播了两次”这种解释在业务上很实用。需要清醒一点这里的影响力传播并不是严格的社会学模型而是一种数学假设。我们是在用“传播”来归纳链接生成机制并希望模型能学到与数据匹配的传播参数。如果某个数据集的边根本不是由传播产生的而是共享属性造成的这个视角可能就不合适。后面第 6 章会专门讨论适用边界。2. 先搭数据多关系图怎么构造关系类型怎么处理2.1 数据格式与关系划分不管最后用什么模型多关系图的数据通常都可以整理成三元组列表每一行是(头节点, 关系, 尾节点)。知识图谱里是(实体A, 关系R, 实体B)社交网络里可能是(用户A, follow, 用户B)。实际实验中我一般先把节点和关系都映射为整数 ID保证节点 ID 连续关系 ID 从 0 开始。这样可以方便地构建邻接矩阵或稀疏张量。一个重要步骤是关系频率统计。多关系图里关系类型极不均匀有的关系出现几十万次有的只有几十次。如果直接全量建模低频关系不仅学不好还会带来噪声。我通常的做法是过滤掉出现次数少于某个阈值的关系。这个阈值怎么定一般用验证集调一下比如在 5 到 50 之间试。如果任务允许还可以把低频关系归并成一个独立类别或者用关系层级来解决。接着是数据集划分。链接预测任务里我们不能用普通分类任务的随机划分因为一条边在训练中出现后它的两端节点信息可能被模型记住导致测试泄漏。常用做法有两种按时间划分用历史时间段的边做训练未来时间段的边做测试或者按边随机划分但要保证测试集中的边不出现在训练集、验证集的邻接矩阵中。对于多关系图还要注意不同关系类型在训练、验证、测试中的比例尽量保持一致。可以直接按关系类型分别划分再把结果合并。2.2 边权重和传播概率的初始化构建传播矩阵时第一步是把每种关系变成一个带方向的邻接矩阵。如果图是有向的矩阵不一定对称如果无向可以令矩阵对称。初始化传播概率我建议不要直接用原始邻接矩阵而是先做归一化。原因是不同节点度差异很大。如果一个高热度节点有十万粉丝原始邻接矩阵中它所在的行数值很大在传播迭代中会主导全局导致低度节点的影响力被淹没。按列归一化或者按行归一化可以让每个节点的传播总量可控。下面是一个最小示例用 Python 构建多种关系类型对应的传播矩阵import numpy as np node2id {n: i for i, n in enumerate(nodes)} relation_ids sorted(set(r for _, r, _ in edges)) # 每种关系对应一个二维矩阵 adj {r: np.zeros((len(node2id), len(node2id))) for r in relation_ids} for h, r, t in edges: adj[r][node2id[h], node2id[t]] 1.0 # 按列归一化得到每种关系下的传播概率矩阵 P_r P {} for r, A in adj.items(): deg A.sum(axis0, keepdimsTrue) deg[deg 0] 1.0 P[r] A / deg这里为什么要按列归一化因为我们希望传播概率矩阵每一列可以表示“从该节点出发向外传播的分布”。在后面的迭代公式里矩阵乘上节点状态向量时每一列乘以该节点的初始状态再累加给邻居相当于把当前节点的状态按比例分配给邻居。如果换成按行归一化表示从邻居聚合到当前节点的信息比例语义上变成“聚合”而不是“传播”。两种都能用但含义不同需要保持一致。还需要初始化一个全局保留比例 alpha。这个参数用于平衡“节点自身信息”和“邻居传播信息”。alpha 太大会导致传播基本上没发生alpha 太小会导致多轮传播后节点表示都趋同。初中期实验可以取 0.15 到 0.3 之间的值后面再根据验证集调节。3. 从传播过程建模链接预测的完整流程3.1 传播模型的选择落地时我们不需要实现完整的动力学模型只需要一个可微的传播迭代过程。也就是说模型的前向传播要像真实传播过程一样逐层扩散同时每一层都能计算梯度。最简单的模型是线性混合传播H_{l1} (1 - alpha) * (1/R) * sum_{r1}^{R} P_r H_l alpha * H_0其中 H_0 是节点初始表示P_r 是关系 r 的传播矩阵R 是关系类型数量。可以看到每一轮迭代都要遍历所有关系把每种关系下的邻居表示做平均再和自身表示做残差连接。这个形式和多关系图神经网络的聚合过程很像但它是显式地模拟“信号传播”。更灵活的做法是给每种关系一个可学习权重 beta_rH_{l1} (1 - alpha) * sum_{r1}^{R} beta_r * P_r H_l alpha * H_0beta_r 初始值可以设成 1/R表示开始时所有关系等权重参与传播。训练后观察 beta_r 的大小就能知道每种关系在链接生成中的相对重要性。还有一种做法是引入注意力机制让每个头节点根据自身状态决定在哪种关系上投入更多传播比例。但注意力会引入额外计算如果刚开始实验建议先用固定的可学习权重 beta_r稳定后再加注意力。3.2 传播路径与节点表示经过多轮传播后不同层的 H 包含了不同传播范围的信息。第一轮结束后节点表示主要包含一阶邻居的影响第二轮后二阶邻居的影响也被揉进来。如果只用最后一层表示信息可能被过度压缩。更常用的做法是把每一层表示拼接起来得到节点最终表示Z [H_0, H_1, ..., H_L]这个拼接类似残差网络里的 dense connection好处是让模型可以自适应地选择使用浅层还是深层信息。例如如果某对节点在二阶传播中出现强信号模型可以直接利用 H_1 或 H_2 中的特征。拼接之后节点 u 和节点 v 之间是否存在关系 r可以通过一个打分函数计算。最常使用的是双线性打分score(u, r, v) z_u^T M_r z_v其中 M_r 是一个可训练矩阵表示关系 r 在嵌入空间里定义的度量方式。如果关系数量很多为每个关系定义一个完整矩阵会导致参数爆炸。可以约束 M_r 为对角矩阵或者使用低秩分解。低秩分解就是把矩阵拆成两个低维矩阵的乘积这样既能减少参数又能保留关系语义。如果不想定义打分矩阵也可以用简单的内积但是实验效果通常弱一些。因为不同关系对向量方向的要求不一样直接用同一个内积会限制表达力。3.3 链路得分与预测输出训练时我们的输入是一批正样本三元组。对每个正样本要采样一些负样本。负样本通常是“不存在的边”或“未来一段时间内没出现的边”。在影响力传播视角下负样本采样不能太随机。如果随机采样两个没有边连接的节点模型很容易学到一个简单的规则离得远就得分低根本不需要学传播结构。一种更合理的做法是“局部负采样”。针对一个正样本 (u, r, v)可以从 v 的 k 跳邻居中采一个与 u 没有 r 关系的节点作为负样本或者把 v 替换成另一个在某些关系类型下与 u 相邻但不满足当前关系约束的节点。这样负样本会更难区分模型必须借助关系和传播路径来分辨。损失函数可以用二分类交叉熵。把正样本得分通过 sigmoid 后接近 1负样本接近 0。也可以使用对比损失让正样本得分高于负样本得分足够大的间隔。预测阶段我们需要对所有候选边打分。最简单的枚举法是对每个关系类型计算所有节点对得分然后取 TopK。但节点规模大时会很昂贵。工业落地一般会用图采样、子图剪枝或者 ANN 索引来加快候选集生成。在这个思路里我们可以用传播路径强度做一个初步筛选只考虑那些在传播迭代中经过多跳后仍然有较高影响值的节点对再进一步用打分函数精排。下面是一个示例模型框架以 PyTorch 风格表达核心前向逻辑不包含完整训练代码import torch import torch.nn as nn class InfluenceLinkPredictor(nn.Module): def __init__(self, num_nodes, num_rels, hidden_dim, alpha0.15, L3): super().__init__() self.alpha alpha self.L L self.node_emb nn.Parameter(torch.randn(num_nodes, hidden_dim)) self.rel_weights nn.Parameter(torch.ones(num_rels) / num_rels) self.rel_matrices nn.Parameter(torch.randn(num_rels, hidden_dim, hidden_dim)) def forward(self, P_list): H0 self.node_emb H H0 layer_reprs [H] for _ in range(self.L): agg 0 for r, P in enumerate(P_list): H_neigh torch.mm(P, H) agg agg self.rel_weights[r] * H_neigh H (1 - self.alpha) * agg self.alpha * H0 layer_reprs.append(H) Z torch.cat(layer_reprs, dim-1) return Z def score(self, Z, heads, tails, rels): h Z[heads] # [batch, hidden_dim * (L1)] t Z[tails] Mr self.rel_matrices[rels] # [batch, hidden_dim, hidden_dim] h_small h[:, :self.node_emb.shape[1]] # 为了演示取第一层维度 t_small t[:, :self.node_emb.shape[1]] return torch.bmm(torch.bmm(h_small.unsqueeze(1), Mr), t_small.unsqueeze(-1)).squeeze()这里为了演示打分时只取了拼接后的前部分维度实际实现中需要保持维度一致。真实模型里要注意 embedding 的维度与关系矩阵维度对齐层拼接后可以再经过一个线性层压缩到统一维度。4. 用一个小型实验验证思路4.1 数据集和评估指标如果手边没有现成的多关系图数据可以先造一个小型数据集验证思路。比如节点数量在 20 到 50关系类型 3 到 5边数量控制在几百条。重点不是刷新性能而是验证传播模型能否正确区分关系类型。推荐公开数据集的话可以从知识图谱常用子集开始例如包含少数关系和实体的子集。不要一开始就上百万级数据因为排查数据和模型问题会非常吃力。评估指标建议先用 AUC 和 Hits10。AUC 衡量的是正样本得分高于负样本得分的概率Hits10 是正确边排在候选列表前 10 的比例。这两个指标计算直观便于早期判断模型是否学到有效信息。MRR 也可以看但更适合推荐排序场景。4.2 核心代码结构实验的核心流程大致如下加载三元组列表构建节点和关系 ID。按时间或随机划分训练、验证、测试集。基于训练集构建每种关系的传播矩阵 P_r并格式化为稀疏矩阵。初始化 InfluenceLinkPredictor 模型。对每个 batch 的正样本按局部负采样生成负样本。计算正负样本的得分和交叉熵损失。反向传播更新参数。每个 epoch 后在验证集上计算 AUC保存最佳模型。训练时batch size 可以从小一点开始比如 64 或 128。因为传播矩阵如果不用 sparse tensor而直接用稠密矩阵的话节点数大会很占显存。所以小图上可以用稠密矩阵大图一定要用稀疏矩阵并配合 PyTorch 的 sparse 张量或者专门的图学习库。4.3 参数调节与结果判断几个关键参数的影响传播层数 L建议从 2 到 5 调试。层数太低多跳信息不够层数太高可能出现过平滑所有节点表示都趋近。判断标准就是验证集 AUC 是否上升如果从第 3 层到第 4 层 AUC 明显下降就要减小层数或增加 alpha。alpha 保留比例alpha 太小时节点自身特征会慢慢消失模型偏向结构相似性alpha 太大时传播效果减弱偏向局部结构。可以按 0.1、0.2、0.3 三档试。关系权重初始化有的实验里关系权重用均匀分布训练后可能所有权重仍然接近均匀说明模型没有区分关系。这时可以给不同关系不同的初始权重或者加入关系类型嵌入。隐藏维度64 到 128 通常足够。小数据集上 32 也可能够。维度太高会导致过拟合训练集 AUC 很高验证集 AUC 很低。负采样比每个正样本配 1 到 5 个负样本。负样本越多训练越慢但 AUC 往往更稳定。如果负样本太多注意正负样本比例不要失衡。判断一个关系类型是否学到可以单独按关系类型计算 AUC。例如把测试集按关系 r 分组统计模型对关系 r 的预测能力。如果某类关系 AUC 接近 0.5说明没有学到有效传播模式。我一般会先检查该关系的训练样本数量再检查传播矩阵中对应的邻接分布。如果该关系数据太少可以合并到相似关系里如果数据不少就调整该关系的权重或矩阵初始化。5. 常见坑与排查顺序5.1 多关系聚合不当导致的过平滑过平滑是图传播模型里最常见的现象。具体表现是验证集 AUC 在层数增加到一定程度后突然下降或者多个节点的表示向量几乎相同。原因很直接每一轮传播都把邻居信息均匀混合经过很多轮后局部细节被抹平。排查时先看每一层表示向量的均值方差。如果最后一层的节点表示方差很小基本就是过平滑。解决方案可以组合使用减少传播层数 L。调大 alpha让自身信息占比更高。使用残差连接直接把 H_0 加到每一层输出上。用对称归一化传播矩阵避免高度数节点影响过大。我在实验里一般偏好“层数 3 alpha 0.2 拼接所有层”的组合这个配置在多数中等规模图上不会立刻过平滑。5.2 传播概率不平衡多关系图里不同关系类型的传播范围差异可能很大。比如知识图谱里“属性”关系通常是局部属性影响范围很小“合作关系”可能在图中形成密集子图影响范围很大。如果模型把所有关系矩阵都用同样的方式归一化那么高频关系的传播信号可能淹没低频关系。常见处理办法有两种。第一种是对每个关系矩阵单独做标准化让每种关系的总传播量在一个量级。可以在构建矩阵时除以该关系的边数或总度数。第二种是给关系权重增加约束。比如使用 softmax 对 beta_r 做归一化让所有权重和等于 1。这样训练后权重可以被理解为“该关系在传播中的贡献比例”。如果发现某类关系完全不工作可以先固定其他关系权重单独训练该关系的权重和打分矩阵观察是否恢复。5.3 负采样方式影响负采样方式直接影响训练难度和稳定程度。如果随机负采样只在全局采样模型可能轻松根据节点度数区分正负样本但它并没有学会关系语义。这是很多多关系链接预测实验看起来指标不错、但实际业务效果不理想的原因。更稳妥的方式是“困难负采样”。比如对于正样本 (u, r, v)把 v 替换成另一个与 u 至少存在一条其他关系路径的节点但这条边 (u, r, v) 不在图中。这样模型必须理解关系 r 的语义而不只是看 u 和 v 是否有连接。负采样比例也不要固定太死。训练初期可以用 1 个负样本让模型先收敛后期增加到 3 到 5 个增强区分能力。5.4 训练不收敛怎么排查训练不收敛的原因通常不是模型复杂而是数据或前置设置有问题。我的排查顺序是先看 loss 曲线。如果 loss 基本不下降可能是学习率设置不当或者输入矩阵没有归一化。可以把学习率调到 1e-3 或 1e-2在小型数据集上试跑 10 个 epoch。再看正负样本得分分布。如果正样本得分正样本得分一直低于负样本说明打分函数和关系矩阵不匹配。先退回去用简单内积打分跑通后再换双线性。检查梯度是否出现 NaN 或爆炸。可以用梯度裁剪。NaN 经常来自传播矩阵中存在未归一化的无穷值或嵌入初始值过大。检查数据泄漏。如果训练集和测试集中的边同时出现在传播矩阵里测试指标会异常高但随迭代波动大。需要重新划分数据。最后用小数据集做 sanity check。把节点数缩小到个位数观察传播矩阵是否符合预期这能帮助发现矩阵构造错误。经验是先固定关系权重不更新只调初始化和层数模型能收敛后再放开关系权重观察关系影响力是否符合直觉。不要一开始就让所有模块同时学习否则出问题很难定位。6. 从实验到落地这个视角适合哪些场景6.1 适用场景和优势影响力传播视角在多关系图上的优势主要体现在三方面路径建模、关系交互和可解释性。知识图谱补全是比较典型的应用。很多实体之间的关系可以通过多跳传播形成。比如“A 的导师是 BB 是 C 的合作者”推断 A 与 C 可能熟悉。传统嵌入模型很难直接把这个路径作为证据而传播模型天然支持多跳路径。社交网络推荐也适合。在社交平台上用户之间的关注、转发、评论都是一种传播信号。如果把“好友推荐”变成“影响力传播预测”模型可以找到那些虽然距离远但在传播链上影响强的人员组合。工业推荐系统中的用户行为链也可以用。用户点击、收藏、购买构成不同关系购买行为可能受某个 KOL 的传播链影响。用传播模型可以给推荐结果附上“传播路径依据”方便解释。6.2 局限和边界这类模型也有很明显的边界。第一如果关系类型非常多比如超过 100 种为每种关系构建传播矩阵或打分矩阵会带来较大内存开销。这时需要做关系分组、矩阵低秩化或者只对核心关系建模。第二如果图里的边不是由传播生成的而是因为共享属性产生的传播假设就不成立。比如两个商品被同时购买不一定是影响力传播结果更可能是价格、功能相似。这时候用传播模型可能不如直接用物品属性模型。第三静态传播矩阵丢失了时序信息。真实影响力传播有先后顺序而且强度随时间衰减。如果数据没有时间戳或者不关系时间模型会丢失动态信号。可以引入时间衰减因子让旧边对传播的贡献降低但代价是建模复杂度上升。第四大规模图上传播矩阵的存储和迭代仍是挑战。稠密矩阵肯定不行稀疏矩阵可以在中等规模上工作但超过千万节点时还要依赖图采样和邻域聚合。这个视角的核心思想可以保留但工程实现需要换一套算法。6.3 后续优化方向从实验走向生产有几个可以持续优化的方向。第一个是引入节点属性。目前我们主要用节点 ID 的嵌入向量作为初始表示如果能同时使用文本、图片或数值特征传播过程可以更准确。可以把属性向量与 ID 嵌入拼接再作为 H_0。第二个是引入时间衰减。给传播矩阵乘以一个时间折扣因子越久远的边对当前影响越小。这样模型可以更贴合真实传播现象。第三个是路径约束和剪枝。传播过程中并不需要所有路径都参与计算。可以基于路径长度、关系兼容性做剪枝只保留语义上合理的传播路径。比如“导师”之后接“合作者”很合理但“出生地”之后接“合作者”可能不合理。可以用关系序列的统计频率来决定是否保留该路径。第四个是把传播过程套进更大的框架。比如在推荐系统里把传播得分作为召回结果再用精排模型微调在知识图谱问答里用传播路径解释推理过程。这样可以兼顾效果、效率和可解释性。如果你也打算做多关系图的链接预测我的建议是先用一个只有几百条边的小图把传播矩阵、层数和打分函数跑通再考虑上大规模数据和复杂模型。这个视角最值得借鉴的不是某一个具体模型而是把“关系”从分类标签变成一个传播过程来思考。这个转换会直接影响到你对数据、特征和模型结构的设计。
返回列表