前阵子接手一个图数据的用户行为预测项目,最初跑得挺顺,后来每来一批新用户,模型效果就肉眼可见地掉。一开始我以为只是特征没做好,调了一周才意识到,问题出在我用的学习范式上——我一直在一张静态图上做转导式(Transductive)学习,而业务早就进入了需要归纳式(Inductive)能力的阶段。这次把“AI 从转导向归纳范式转变”的过程完整拆开讲,包括概念、动因、实操案例和踩坑记录,希望对正在处理动态图数据或者打算切换模型范式的朋友有点参考价值。1. 从两个词说起:转导与归纳到底在争什么1.1 一个很容易被忽视的边界很多做机器学习的朋友对“训练集、验证集、测试集”这套划分非常熟悉,却很少意识到:这套划分方式本身默认了一种归纳式学习假设——我们学到的规则要能应用到“从未见过”的数据上。但在真实项目里,尤其在做图数据、半监督学习时,我见过太多团队其实是在做转导式学习,只是没意识到这个名字。转导式学习的特点是:在训练阶段,模型已经看到了所有测试样本的特征信息(甚至可以利用测试样本之间的结构关系),只是没看到测试样本的标签。比如经典的标签传播算法,或者早期全图训练的图卷积网络,它们把整张图的邻接矩阵和所有节点特征一次性喂给模型,在训练时“偷看”了测试节点的特征和连接关系。归纳式学习则不同:它要求模型从训练数据中提炼出一套通用规则,学完之后可以独立面对任意一个新输入。这套规则不能依赖测试样本的额外信息,也不能假设推理时还能访问训练图的全貌。1.2 用“开卷考试”和“解题能力”来类比我习惯跟团队同学这样解释两者的区别:转导式学习像开卷考试,考试范围就是那本固定的参考书,题目再多,你只需要在书里翻答案,书没收录的内容你就没法答。归纳式学习像学会了数学解题方法,不管题目怎么变,只要题型在规则覆盖范围内,你都可以现场推导。这带来一个非常实际的差异:转导式模型在“当前这堆数据”上往往效果很好,因为它隐式利用了测试样本的结构信息;但一旦数据分布稍有变化,比如新用户、新商品、新关系加入,模型就没有任何办法——它没有学到“如何面对新样本”的规则。对比项转导式学习归纳式学习训练时是否接触测试特征是,常见于图半监督、标签传播否,测试样本在推理时才进入对新样本的处理一般需要重训或重推全图可直接用学到的规则推理适合场景静态图、小数据、标签稀缺动态数据、持续增长、在线服务代表方法标签传播、早期全图 GCNGraphSAGE、普通 MLP、CNN/Transformer严格来说,这两种范式没有绝对的好坏。转导式在小规模、分布稳定的场景里实现简单,效果也能打;但如果你要做在线推理、要处理持续到达的新节点,迟早得切换到归纳式。2. 为什么越来越多项目开始从转导走向归纳2.1 业务的动态性把转导式逼到了墙角我在做的那个用户行为预测项目,数据是典型的内容社区场景。每天都有新用户注册、新内容发布,用户之间不断产生新的关注、互动关系。最初团队用的是“全图标签传播 + 图嵌入”的方案:每天凌晨定时跑全量数据,把图嵌入算好,再交给下游分类器用。上线初期效果不错,准确率能到 83% 左右。问题出现在规模涨起来之后:全图从几十万节点涨到几千万节点,全量重算的耗时从半小时涨到十几个小时。更要命的是,新用户当天产生的行为完全无法预测,因为模型从来没有在新用户身上“见过”今天凌晨之后新增的边。这其实是转导式学习的结构性缺陷——它天然假设测试集是一个已经存在的、固定的集合。2.2 技术侧的变化:从“全图”到“采样”技术上推动范式转变的力量同样明显。早期图神经网络,比如 GCN,训练时要依赖完整的邻接矩阵,本质上是转导式:它在训练时使用全图信息,包括测试节点的连接。所以当图中出现新节点时,邻接矩阵变了,整个模型等于要重新学。后来出现的 GraphSAGE 等模型,核心改进是:不再依赖全图邻接矩阵,而是通过采样邻居来逐节点计算表示。训练时模型学到的是“如何聚合邻居特征”的映射函数,而不是“这张图里每个节点长什么样”。新节点进来时,只需要按同样的方式采样它的邻居、聚合特征,就能算出表示。这就是典型的归纳式学习。我们项目切换到 GraphSAGE 风格的结构后,测试集准确率从 83% 提升到 87.5%——看起来提升不算夸张,但新用户当天的推理响应时间从“等第二天凌晨重算”变成“毫秒级实时计算”,这个体验差距是本质性的。2.3 大模型时代对“规则提取”的更高要求还有一个背景值得提:当前 AI 行业对“模型学会了什么”这件事越来越在意。转导式模型容易被诟病为“记性好但理解差”,它可能只是记住了训练图的结构模式,并没有形成真正可迁移的规律。归纳式模型则强迫模型把知识压缩成参数化的规则,训练时更接近“理解”而非“记忆”。在做这类切换时,我并不建议为了赶时髦而换范式。**标准只有一个:你的业务是否要求模型面对训练时不存在的新输入。**如果是,那你迟早要走上从转导到归纳的这条路,早切换比晚切换好。3. 一个完整的上手案例:把图节点分类从转导改成归纳3.1 场景设定与数据切分方式的变化具体说说我是怎么改的。原始任务是把用户节点分成几类兴趣群体,用于后面做推荐召回。原始转导式方案分三步:构建全图:节点是用户和内容,边是互动行为。用标签传播算法给缺失标签的节点打上伪标签。在全图嵌入上训练一个多层感知机分类器。切换成归纳式方案后,最重要的改变不是换了模型结构,而是重写了数据切分逻辑。归纳式学习要求训练、验证、测试的节点集合互不重叠,并且测试节点在训练期间完全不可见,包括它们的特征和连边也不允许出现在训练邻域里。我按时间切分:前 60 天的数据作为训练子图,第 61 到 75 天作为验证子图,第 76 到 90 天作为测试子图。这样切分能最大程度模拟线上“新节点在推理时才出现”的真实场景。注意:如果只是随机切节点,训练时仍然可能通过高阶邻居“间接看到”测试节点的信息,导致评估结果虚高。按时间切分是最贴近业务的做法,因为线上新用户本质上就是时间维度上新出现的节点。3.2 转导式做法:标签传播与全图 GCN 的问题转导式方案里,标签传播这一步最直观。核心逻辑是:相似的节点应该有相似标签,标签沿着边不断扩散。它的公式不复杂,但有个致命问题——它需要对整张图的邻接矩阵做迭代运算,每一次迭代都在使用测试节点的连接关系。当测试节点和训练节点比例发生变化时,整个传播结果都会变。后来我们试过全图 GCN,本质上也是转导式。因为 GCN 的层间传播公式里有归一化邻接矩阵,这个矩阵包含了全部节点,包括测试节点。训练过程中,测试节点的特征会通过图卷积传播到训练节点上,参与模型参数更新。这在学术实验里常被接受,但在业务里会带来“评估过乐观、上线后效果缩水”的问题。当时我拿全图 GCN 做了一版,离线 AUC 比标签传播高不少,结果上线后新用户预测效果很差。后来排查发现,问题就出在转导式评估和线上推理设置不一致:离线时模型见过新节点的特征和邻居,线上时新节点只有自己的特征和少量冷启动行为,邻居还没长出来。3.3 归纳式实现:GraphSAGE 风格的采样与聚合切换到归纳式方案,我选择的是 GraphSAGE 风格模型,核心代码逻辑大致如下:import torch import torch.nn as nn import torch.nn.functional as F class SAGELayer(nn.Module): def __init__(self, in_dim, out_dim, aggregator="mean"): super().__init__() self.aggregator = aggregator self.linear_self = nn.Linear(in_dim, out_dim) self.linear_neigh = nn.Linear(in_dim, out_dim) def forward(self, node_feats, neighbor_feats): # 聚合邻居特征 if self.aggregator == "mean": neigh_agg = torch.mean(neighbor_feats, dim=1) elif self.aggregator == "max": neigh_agg = torch.max(neighbor_feats, dim=1)[0] # 自身特征和邻居特征分别变换后拼接 h_self = self.linear_self(node_feats) h_neigh = self.linear_neigh(neigh_agg) return F.relu(h_self + h_neigh) class GraphSAGE(nn.Module): def __init__(self, in_dim, hidden_dim, num_layers=2): super().__init__() self.layers = nn.ModuleList() self.layers.append(SAGELayer(in_dim, hidden_dim)) for _ in range(num_layers - 1): self.layers.append(SAGELayer(hidden_dim, hidden_dim)) def forward(self, node_feats, neighbor_lists): h = node_feats for layer in self.layers: neighbor_feats = [h[n_ids] for n_ids in neighbor_lists] neighbor_feats = torch.stack(neighbor_feats, dim=1) h = layer(h, neighbor_feats) return h上面是示意代码,实际工程里会用现成的图学习框架做采样,避免手工维护邻居索引。关键的参数有三个:采样邻居数量:我最终设为 20,即每一层最多采样 20 个邻居。采样数太少,聚合出的表示方差大;采样数太多,训练速度下降明显。20 在这个数据规模下是性价比比较高的值。层数:用了 2 层。层数越深,感受野越大,但在千万级图上做邻居采样时,指数级扩张的邻居数量会很快让训练变慢。2 层已经能覆盖二阶邻居信息,对用户兴趣分类足够。聚合器:试过 mean、max、LSTM 三种,mean 和 max 效果接近,LSTM 训练慢一个量级且收益有限。最终选了 mean,图结构稀疏时 mean 比 max 更稳定。3.4 训练与推理方式的差异归纳式模型的训练采用 mini-batch 方式:每次随机采样一批中心节点,再采样它们的多阶邻居,形成一个子图。模型只在这个子图上计算表示和损失。这样做有两个好处:一是显存占用不再和全图规模挂钩,千万级图也能在单卡上训练;二是每一步训练时模型根本看不到批外节点的信息,和线上推理场景完全一致。推理时,对新节点只用做一步操作:把它的特征和它已有的邻居特征按同样方式采样、聚合,得到表示,过分类器。整个过程不涉及全图重算,所以能够支撑在线实时推理。方案离线 AUC全量重算耗时新节点在线推理标签传播 + MLP0.8112 小时以上,不可扩展不支持全图 GCN0.868 小时以上,显存受限基本不支持GraphSAGE 归纳式0.85无需全量重算毫秒级,支持全图 GCN 离线分数最高,但实际业务中并不能把新用户压进全图重算,所以那个 0.86 是“看得见用不上”的分数。归纳式方案离线略低,但线上新用户预测准确率反而更高,原因就是训练和推理场景一致。4. 从转导到归纳的坑,我都替你踩过4.1 推理阶段遇到没见过的邻居类型怎么办归纳式模型要求邻居特征在推理时可用,但新用户在一开始往往只有极少邻居,甚至一个邻居都没有。这时邻居采样会退化成空集合,聚合结果不稳定,模型容易给出偏高或偏低的预测分数。我们当时的处理办法是:在训练阶段刻意加入“零邻居”样本——从训练集中随机挑一部分节点,把它们的邻居信息置空,只用自己的特征做预测。这样模型在训练时就见过“孤立节点”的情况,线上推理遇到真正的新用户时,行为不会太离谱。这个技巧说起来简单,但确实把新用户冷启动预测的准确率提升了 5 个百分点左右。4.2 训练图与线上图的分布漂移切换成归纳式之后,我一度以为只要模型是归纳式的,就天然能泛化到未来数据。事实证明这是想多了。归纳式解决的是“新节点进入已有图结构”的问题,但如果一段时间之后,整个图的结构模式都变了,比如互动关系从密集变为稀疏、内容传播路径明显改变,模型学到的聚合规则同样会失效。我在第二个季度就踩过这个坑:训练子图来自冬季数据,测试子图来自来年春季数据,两者在平均度、子图密度上差得比较多,离线验证 AUC 一口气掉到 0.77。后来加了“时间衰减采样”——训练时越靠近当前时间的数据,采样权重越高——才把离线指标拉回到 0.83。做归纳式图模型,数据漂移监控要像监控模型分数一样常态化。4.3 半监督标签稀疏时,转导式的优势不能忽略转导式方法最拿手的一个场景是标签极少。标签传播可以利用未标注节点的结构信息来辅助分类,这在标注成本高的业务里非常诱人。切换到归纳式之后,模型只能从有标签样本中学习,如果标签数量太少,效果往往不够好。我们的处理方案是“两阶段训练”:先用转导式标签传播或者伪标签方法在整张图上生成一批高质量伪标签,再把这些伪标签当作训练目标,用归纳式模型去拟合。这本质上是把转导式的“答案”蒸馏成归纳式的“规则”。做了这一步之后,标签稀疏场景下的归纳式模型 F1 提升明显,从 0.68 到 0.75。5. 什么时候不该急着转归纳,以及我现在的判断标准5.1 静态小数据的场景,转导式仍然更香如果业务是一个固定的学术数据集、一张几年不变的知识图谱、或者一次性的离线分析,我不建议引入归纳式模型的复杂度。转导式方案在静态图上通常训练更快、参数更少、效果也有保障。我自己在另一个小型内部项目中就保留了转导式方案,因为那张图一年才更新两次,做归纳式纯粹是给自己添麻烦。范式切换是有成本的:数据切分要改、模型结构要改、训练流程要改、监控方式要改。如果业务不需要面对未知的新样本,维持转导式是理性的选择。5.2 一个可以拿去用的决策检查清单面对要不要切换的问题,我整理了一份检查清单,基本能覆盖大多数情况:你的测试数据是否在训练时已经已知?如果测试集是固定且已知的,转导式完全够用。线上是否存在实时到达的新样本?不存在就不急,存在就要考虑归纳式。全量重算的耗时是否已经影响业务节奏?比如只能每天更新一次模型,而业务要求分钟级响应,那就是切换信号。团队是否有精力维护采样、批处理等更复杂的训练管线?归纳式的工程复杂度确实高一些。离线评估方式是否和线上推理方式一致?如果不一致,优先修正评估方式,再决定换不换模型。5.3 范式转变不是换模型,而是重新定义问题最后想分享一个更抽象的体会。刚开始接触到“从转导向归纳”的时候,我以为是换一个模型结构的事,后来发现根本不是。真正变的是我们怎么定义问题:以前我们问“这堆数据里有什么规律”,现在问的是“来了新数据,模型能不能立刻说点什么”。这个转变会连锁影响到特征工程、数据切分、评估体系、在线架构甚至团队分工。比如评估体系,转导式时代我们习惯随机划分数据集,这在归纳式范式下就是错的;又比如特征工程,转导式可以放心使用全图统计特征,归纳式则必须保证推理时那些统计量能实时算得出来。任何一环没跟上,模型切换都会打折扣。我个人的实操习惯是:接到一个新的图数据任务时,先问业务方三个问题——数据更新频率是多少、新样本是否要求实时推理、标注成本高不高。这三个问题的答案基本就决定了范式选型。还没想清楚之前,不要急着上最复杂的模型;想清楚之后,也不要因为工程麻烦而继续在转导式的舒适区里耗着。这次项目做完以后,我把“先定范式、再选模型”写进了团队的技术规范。回过头看,那次从转导向归纳的转变真正解决的问题不是某个指标提升了多少,而是让模型从“只能活在某一张图里”变成了“能面对不断变化的数据流”。这条路走下来,踩了不少坑,但也把图数据建模的很多底层逻辑想明白了,希望这篇记录也能帮你少走几步弯路。
前阵子接手一个图数据的用户行为预测项目,最初跑得挺顺,后来每来一批新用户,模型效果就肉眼可见地掉。一开始我以为只是特征没做好,调了一周才意识到,问题出在我用的学习范式上——我一直在一张静态图上做转导式(Transductive)学习,而业务早就进入了需要归纳式(Inductive)能力的阶段。这次把“AI 从转导向归纳范式转变”的过程完整拆开讲,包括概念、动因、实操案例和踩坑记录,希望对正在处理动态图数据或者打算切换模型范式的朋友有点参考价值。1. 从两个词说起:转导与归纳到底在争什么1.1 一个很容易被忽视的边界很多做机器学习的朋友对“训练集、验证集、测试集”这套划分非常熟悉,却很少意识到:这套划分方式本身默认了一种归纳式学习假设——我们学到的规则要能应用到“从未见过”的数据上。但在真实项目里,尤其在做图数据、半监督学习时,我见过太多团队其实是在做转导式学习,只是没意识到这个名字。转导式学习的特点是:在训练阶段,模型已经看到了所有测试样本的特征信息(甚至可以利用测试样本之间的结构关系),只是没看到测试样本的标签。比如经典的标签传播算法,或者早期全图训练的图卷积网络,它们把整张图的邻接矩阵和所有节点特征一次性喂给模型,在训练时“偷看”了测试节点的特征和连接关系。归纳式学习则不同:它要求模型从训练数据中提炼出一套通用规则,学完之后可以独立面对任意一个新输入。这套规则不能依赖测试样本的额外信息,也不能假设推理时还能访问训练图的全貌。1.2 用“开卷考试”和“解题能力”来类比我习惯跟团队同学这样解释两者的区别:转导式学习像开卷考试,考试范围就是那本固定的参考书,题目再多,你只需要在书里翻答案,书没收录的内容你就没法答。归纳式学习像学会了数学解题方法,不管题目怎么变,只要题型在规则覆盖范围内,你都可以现场推导。这带来一个非常实际的差异:转导式模型在“当前这堆数据”上往往效果很好,因为它隐式利用了测试样本的结构信息;但一旦数据分布稍有变化,比如新用户、新商品、新关系加入,模型就没有任何办法——它没有学到“如何面对新样本”的规则。对比项转导式学习归纳式学习训练时是否接触测试特征是,常见于图半监督、标签传播否,测试样本在推理时才进入对新样本的处理一般需要重训或重推全图可直接用学到的规则推理适合场景静态图、小数据、标签稀缺动态数据、持续增长、在线服务代表方法标签传播、早期全图 GCNGraphSAGE、普通 MLP、CNN/Transformer严格来说,这两种范式没有绝对的好坏。转导式在小规模、分布稳定的场景里实现简单,效果也能打;但如果你要做在线推理、要处理持续到达的新节点,迟早得切换到归纳式。2. 为什么越来越多项目开始从转导走向归纳2.1 业务的动态性把转导式逼到了墙角我在做的那个用户行为预测项目,数据是典型的内容社区场景。每天都有新用户注册、新内容发布,用户之间不断产生新的关注、互动关系。最初团队用的是“全图标签传播 + 图嵌入”的方案:每天凌晨定时跑全量数据,把图嵌入算好,再交给下游分类器用。上线初期效果不错,准确率能到 83% 左右。问题出现在规模涨起来之后:全图从几十万节点涨到几千万节点,全量重算的耗时从半小时涨到十几个小时。更要命的是,新用户当天产生的行为完全无法预测,因为模型从来没有在新用户身上“见过”今天凌晨之后新增的边。这其实是转导式学习的结构性缺陷——它天然假设测试集是一个已经存在的、固定的集合。2.2 技术侧的变化:从“全图”到“采样”技术上推动范式转变的力量同样明显。早期图神经网络,比如 GCN,训练时要依赖完整的邻接矩阵,本质上是转导式:它在训练时使用全图信息,包括测试节点的连接。所以当图中出现新节点时,邻接矩阵变了,整个模型等于要重新学。后来出现的 GraphSAGE 等模型,核心改进是:不再依赖全图邻接矩阵,而是通过采样邻居来逐节点计算表示。训练时模型学到的是“如何聚合邻居特征”的映射函数,而不是“这张图里每个节点长什么样”。新节点进来时,只需要按同样的方式采样它的邻居、聚合特征,就能算出表示。这就是典型的归纳式学习。我们项目切换到 GraphSAGE 风格的结构后,测试集准确率从 83% 提升到 87.5%——看起来提升不算夸张,但新用户当天的推理响应时间从“等第二天凌晨重算”变成“毫秒级实时计算”,这个体验差距是本质性的。2.3 大模型时代对“规则提取”的更高要求还有一个背景值得提:当前 AI 行业对“模型学会了什么”这件事越来越在意。转导式模型容易被诟病为“记性好但理解差”,它可能只是记住了训练图的结构模式,并没有形成真正可迁移的规律。归纳式模型则强迫模型把知识压缩成参数化的规则,训练时更接近“理解”而非“记忆”。在做这类切换时,我并不建议为了赶时髦而换范式。**标准只有一个:你的业务是否要求模型面对训练时不存在的新输入。**如果是,那你迟早要走上从转导到归纳的这条路,早切换比晚切换好。3. 一个完整的上手案例:把图节点分类从转导改成归纳3.1 场景设定与数据切分方式的变化具体说说我是怎么改的。原始任务是把用户节点分成几类兴趣群体,用于后面做推荐召回。原始转导式方案分三步:构建全图:节点是用户和内容,边是互动行为。用标签传播算法给缺失标签的节点打上伪标签。在全图嵌入上训练一个多层感知机分类器。切换成归纳式方案后,最重要的改变不是换了模型结构,而是重写了数据切分逻辑。归纳式学习要求训练、验证、测试的节点集合互不重叠,并且测试节点在训练期间完全不可见,包括它们的特征和连边也不允许出现在训练邻域里。我按时间切分:前 60 天的数据作为训练子图,第 61 到 75 天作为验证子图,第 76 到 90 天作为测试子图。这样切分能最大程度模拟线上“新节点在推理时才出现”的真实场景。注意:如果只是随机切节点,训练时仍然可能通过高阶邻居“间接看到”测试节点的信息,导致评估结果虚高。按时间切分是最贴近业务的做法,因为线上新用户本质上就是时间维度上新出现的节点。3.2 转导式做法:标签传播与全图 GCN 的问题转导式方案里,标签传播这一步最直观。核心逻辑是:相似的节点应该有相似标签,标签沿着边不断扩散。它的公式不复杂,但有个致命问题——它需要对整张图的邻接矩阵做迭代运算,每一次迭代都在使用测试节点的连接关系。当测试节点和训练节点比例发生变化时,整个传播结果都会变。后来我们试过全图 GCN,本质上也是转导式。因为 GCN 的层间传播公式里有归一化邻接矩阵,这个矩阵包含了全部节点,包括测试节点。训练过程中,测试节点的特征会通过图卷积传播到训练节点上,参与模型参数更新。这在学术实验里常被接受,但在业务里会带来“评估过乐观、上线后效果缩水”的问题。当时我拿全图 GCN 做了一版,离线 AUC 比标签传播高不少,结果上线后新用户预测效果很差。后来排查发现,问题就出在转导式评估和线上推理设置不一致:离线时模型见过新节点的特征和邻居,线上时新节点只有自己的特征和少量冷启动行为,邻居还没长出来。3.3 归纳式实现:GraphSAGE 风格的采样与聚合切换到归纳式方案,我选择的是 GraphSAGE 风格模型,核心代码逻辑大致如下:import torch import torch.nn as nn import torch.nn.functional as F class SAGELayer(nn.Module): def __init__(self, in_dim, out_dim, aggregator="mean"): super().__init__() self.aggregator = aggregator self.linear_self = nn.Linear(in_dim, out_dim) self.linear_neigh = nn.Linear(in_dim, out_dim) def forward(self, node_feats, neighbor_feats): # 聚合邻居特征 if self.aggregator == "mean": neigh_agg = torch.mean(neighbor_feats, dim=1) elif self.aggregator == "max": neigh_agg = torch.max(neighbor_feats, dim=1)[0] # 自身特征和邻居特征分别变换后拼接 h_self = self.linear_self(node_feats) h_neigh = self.linear_neigh(neigh_agg) return F.relu(h_self + h_neigh) class GraphSAGE(nn.Module): def __init__(self, in_dim, hidden_dim, num_layers=2): super().__init__() self.layers = nn.ModuleList() self.layers.append(SAGELayer(in_dim, hidden_dim)) for _ in range(num_layers - 1): self.layers.append(SAGELayer(hidden_dim, hidden_dim)) def forward(self, node_feats, neighbor_lists): h = node_feats for layer in self.layers: neighbor_feats = [h[n_ids] for n_ids in neighbor_lists] neighbor_feats = torch.stack(neighbor_feats, dim=1) h = layer(h, neighbor_feats) return h上面是示意代码,实际工程里会用现成的图学习框架做采样,避免手工维护邻居索引。关键的参数有三个:采样邻居数量:我最终设为 20,即每一层最多采样 20 个邻居。采样数太少,聚合出的表示方差大;采样数太多,训练速度下降明显。20 在这个数据规模下是性价比比较高的值。层数:用了 2 层。层数越深,感受野越大,但在千万级图上做邻居采样时,指数级扩张的邻居数量会很快让训练变慢。2 层已经能覆盖二阶邻居信息,对用户兴趣分类足够。聚合器:试过 mean、max、LSTM 三种,mean 和 max 效果接近,LSTM 训练慢一个量级且收益有限。最终选了 mean,图结构稀疏时 mean 比 max 更稳定。3.4 训练与推理方式的差异归纳式模型的训练采用 mini-batch 方式:每次随机采样一批中心节点,再采样它们的多阶邻居,形成一个子图。模型只在这个子图上计算表示和损失。这样做有两个好处:一是显存占用不再和全图规模挂钩,千万级图也能在单卡上训练;二是每一步训练时模型根本看不到批外节点的信息,和线上推理场景完全一致。推理时,对新节点只用做一步操作:把它的特征和它已有的邻居特征按同样方式采样、聚合,得到表示,过分类器。整个过程不涉及全图重算,所以能够支撑在线实时推理。方案离线 AUC全量重算耗时新节点在线推理标签传播 + MLP0.8112 小时以上,不可扩展不支持全图 GCN0.868 小时以上,显存受限基本不支持GraphSAGE 归纳式0.85无需全量重算毫秒级,支持全图 GCN 离线分数最高,但实际业务中并不能把新用户压进全图重算,所以那个 0.86 是“看得见用不上”的分数。归纳式方案离线略低,但线上新用户预测准确率反而更高,原因就是训练和推理场景一致。4. 从转导到归纳的坑,我都替你踩过4.1 推理阶段遇到没见过的邻居类型怎么办归纳式模型要求邻居特征在推理时可用,但新用户在一开始往往只有极少邻居,甚至一个邻居都没有。这时邻居采样会退化成空集合,聚合结果不稳定,模型容易给出偏高或偏低的预测分数。我们当时的处理办法是:在训练阶段刻意加入“零邻居”样本——从训练集中随机挑一部分节点,把它们的邻居信息置空,只用自己的特征做预测。这样模型在训练时就见过“孤立节点”的情况,线上推理遇到真正的新用户时,行为不会太离谱。这个技巧说起来简单,但确实把新用户冷启动预测的准确率提升了 5 个百分点左右。4.2 训练图与线上图的分布漂移切换成归纳式之后,我一度以为只要模型是归纳式的,就天然能泛化到未来数据。事实证明这是想多了。归纳式解决的是“新节点进入已有图结构”的问题,但如果一段时间之后,整个图的结构模式都变了,比如互动关系从密集变为稀疏、内容传播路径明显改变,模型学到的聚合规则同样会失效。我在第二个季度就踩过这个坑:训练子图来自冬季数据,测试子图来自来年春季数据,两者在平均度、子图密度上差得比较多,离线验证 AUC 一口气掉到 0.77。后来加了“时间衰减采样”——训练时越靠近当前时间的数据,采样权重越高——才把离线指标拉回到 0.83。做归纳式图模型,数据漂移监控要像监控模型分数一样常态化。4.3 半监督标签稀疏时,转导式的优势不能忽略转导式方法最拿手的一个场景是标签极少。标签传播可以利用未标注节点的结构信息来辅助分类,这在标注成本高的业务里非常诱人。切换到归纳式之后,模型只能从有标签样本中学习,如果标签数量太少,效果往往不够好。我们的处理方案是“两阶段训练”:先用转导式标签传播或者伪标签方法在整张图上生成一批高质量伪标签,再把这些伪标签当作训练目标,用归纳式模型去拟合。这本质上是把转导式的“答案”蒸馏成归纳式的“规则”。做了这一步之后,标签稀疏场景下的归纳式模型 F1 提升明显,从 0.68 到 0.75。5. 什么时候不该急着转归纳,以及我现在的判断标准5.1 静态小数据的场景,转导式仍然更香如果业务是一个固定的学术数据集、一张几年不变的知识图谱、或者一次性的离线分析,我不建议引入归纳式模型的复杂度。转导式方案在静态图上通常训练更快、参数更少、效果也有保障。我自己在另一个小型内部项目中就保留了转导式方案,因为那张图一年才更新两次,做归纳式纯粹是给自己添麻烦。范式切换是有成本的:数据切分要改、模型结构要改、训练流程要改、监控方式要改。如果业务不需要面对未知的新样本,维持转导式是理性的选择。5.2 一个可以拿去用的决策检查清单面对要不要切换的问题,我整理了一份检查清单,基本能覆盖大多数情况:你的测试数据是否在训练时已经已知?如果测试集是固定且已知的,转导式完全够用。线上是否存在实时到达的新样本?不存在就不急,存在就要考虑归纳式。全量重算的耗时是否已经影响业务节奏?比如只能每天更新一次模型,而业务要求分钟级响应,那就是切换信号。团队是否有精力维护采样、批处理等更复杂的训练管线?归纳式的工程复杂度确实高一些。离线评估方式是否和线上推理方式一致?如果不一致,优先修正评估方式,再决定换不换模型。5.3 范式转变不是换模型,而是重新定义问题最后想分享一个更抽象的体会。刚开始接触到“从转导向归纳”的时候,我以为是换一个模型结构的事,后来发现根本不是。真正变的是我们怎么定义问题:以前我们问“这堆数据里有什么规律”,现在问的是“来了新数据,模型能不能立刻说点什么”。这个转变会连锁影响到特征工程、数据切分、评估体系、在线架构甚至团队分工。比如评估体系,转导式时代我们习惯随机划分数据集,这在归纳式范式下就是错的;又比如特征工程,转导式可以放心使用全图统计特征,归纳式则必须保证推理时那些统计量能实时算得出来。任何一环没跟上,模型切换都会打折扣。我个人的实操习惯是:接到一个新的图数据任务时,先问业务方三个问题——数据更新频率是多少、新样本是否要求实时推理、标注成本高不高。这三个问题的答案基本就决定了范式选型。还没想清楚之前,不要急着上最复杂的模型;想清楚之后,也不要因为工程麻烦而继续在转导式的舒适区里耗着。这次项目做完以后,我把“先定范式、再选模型”写进了团队的技术规范。回过头看,那次从转导向归纳的转变真正解决的问题不是某个指标提升了多少,而是让模型从“只能活在某一张图里”变成了“能面对不断变化的数据流”。这条路走下来,踩了不少坑,但也把图数据建模的很多底层逻辑想明白了,希望这篇记录也能帮你少走几步弯路。