ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

知识图谱表示学习评估:hit@10与mean rank的深度解析

知识图谱表示学习评估:hit@10与mean rank的深度解析 1. 从一次模型评估翻车说起为什么hit10和mean rank值得单独拎出来讲刚接触知识图谱表示学习那会儿我犯过一个现在想起来都脸红的错误。当时用TransE在一个自建的小规模图谱上跑完训练看loss曲线降得挺漂亮就兴冲冲地把模型交给下游做链接预测。结果下游反馈说效果很差我还不服气回去把训练集上的三元组拿来测命中率高得离谱。问题出在哪我把评估指标用错了——用训练集评估、用错误的分割方式算hit10、mean rank的排序口径也没对齐。那次翻车让我意识到知识图谱表示学习里模型结构TransE、TransD、TransR只是半壁江山另一半全在评价指标的理解和实现上。这篇内容就是围绕这个痛点展开的。我会把TransE、TransD、TransR这几个经典翻译模型的评估环节彻底拆开讲清楚hit10到底在数什么、mean rank为什么容易被个别样本带偏、filtered和raw两种设置差在哪、为什么同一份预测结果换个口径指标能差出一大截。适合正在做链接预测、三元组分类或者要给自己的表示学习模型写评估脚本的读者。不管你是刚跑通第一个TransE demo的新手还是已经在调TransR复杂度的老手评估这块的坑大概率都踩过或者即将踩到。先把结论性的东西摆前面hit10衡量的是正确答案有没有挤进前10名mean rank衡量的是正确答案平均排在第几位。听起来简单但魔鬼全在细节里。下面我按指标定义→计算口径→模型差异→实操复现→踩坑排查的顺序一层层往下剥。2. hit10与mean rank到底在数什么把排序问题翻译成人话2.1 链接预测任务的本质是一个排序问题要理解这两个指标得先回到它们服务的任务本身。知识图谱表示学习的经典评估任务是链接预测给定一个不完整的三元组比如张三就职于让模型从全部实体里挑出最可能的答案。模型对每个候选实体打一个分数然后按分数排序。评估指标衡量的就是这个排序结果的质量而不是模型输出的绝对分数值。这里有个容易被忽略的点TransE这类翻译模型打出的分数是距离或者负距离分数越小表示越可能。而有些实现里用的是相似度越大越可能。方向搞反了hit10会直接变成hit倒数10指标惨不忍睹但你还以为是模型不行。我见过至少三个同学栽在这个符号问题上。具体到计算流程对测试集里的每一个三元组h, r, t评估时通常做两件事替换头实体固定r和t把h换成图谱里每一个实体得到一堆候选看正确头实体排第几。替换尾实体固定h和r把t换成每一个实体看正确尾实体排第几。每个测试三元组会产生两个排名头排名和尾排名所有测试三元组的排名汇总起来才算得出hit10和mean rank。2.2 hit10命中率视角的够用就好hit10的定义非常直白在所有测试样本中正确实体的排名落在前10的比例。公式上就是命中数除以总样本数。它的好处是对极端排名不敏感。假设某个样本正确答案排第1另一个排第500只要都在前10之外对hit10的贡献都是0反过来只要进了前10排第1和排第10贡献一样。这种截断特性让hit10特别适合衡量实际可用性——在很多下游应用里你只需要模型给出top候选让业务方去筛排第3还是第8差别不大但排到100名开外就没法用了。hit10通常还会配套hit1和hit3一起看。hit1反映模型的精准命中能力hit10反映召回兜底能力。如果hit1很低但hit10很高说明模型知道正确答案大概在附近但排序不够锐利如果hit10本身就很低那基本是表示空间没学好或者评估口径出了问题。2.3 mean rank平均排名视角的整体位置感mean rank是所有测试样本正确实体排名的算术平均值。它比hit10更细腻因为它用到了排名的具体数值而不只是是否进前10。但mean rank有个致命弱点对异常值极其敏感。假设1000个测试样本里999个正确答案都排第1只有1个排第10000mean rank就是(999×1 10000)/1000 ≈ 11。这个数字看起来还行但实际上模型在999个样本上表现完美只在一个样本上崩了。反过来如果模型整体排名都在50左右mean rank是50看起来比11差但实际分布更稳定。正因为这个特性学术界后来普遍改用MRRMean Reciprocal Rank平均倒数排名或者直接看hit10因为倒数排名对高排名的奖励更平滑异常值影响被压缩。不过mean rank作为经典指标仍然被大量论文引用所以你必须懂它但用的时候要留个心眼。2.4 两个指标放在一起看才有意义单独看任何一个指标都可能被误导。我的习惯是hit1、hit3、hit10、mean rank四个一起报再配一个排名分布的直方图。这样能看出模型到底是整体靠前但不够尖还是大部分不错但偶尔崩盘。举个我实际遇到的对比两个TransE变体A的hit10是0.82、mean rank是45B的hit10是0.79、mean rank是28。单看hit10A更好单看mean rankB更好。把排名分布画出来才发现A的排名集中在1-5和200-500两个区间双峰B的排名集中在10-40单峰。A在简单样本上极强在难样本上崩得厉害B更均衡。这种信息只有两个指标加分布图才能看出来。3. filtered与raw一个设置让指标天差地别的关键分歧3.1 raw设置下那些冤枉的高排名原始版本的评估raw setting有个很反直觉的问题。假设测试三元组是张三就职于某公司在替换尾实体时图谱里可能还存在张三就职于另一家公司这个真实存在的三元组。模型把另一家公司排在第一位把某公司排在第二位按raw口径正确排名是2。但问题是另一家公司也是对的啊模型没犯错却被当成了错误答案来惩罚。这就是raw设置的核心缺陷它把图谱中真实存在但不在当前测试三元组里的答案当成了干扰项。图谱越稠密、实体关系越丰富这种冤枉就越多指标被压得越低。在小规模图谱上这个问题不明显一旦图谱有几十万实体raw指标会低到让你怀疑人生。3.2 filtered设置把已知正确答案从候选里剔除filtered设置就是来解决这个问题的。在给某个测试三元组排序之前先把图谱中所有已知为真的候选实体从排名列表里删掉只保留那些未知真假的候选。这样模型排第几就是它在真正需要判断的候选里的位置。还是上面的例子filtered设置下另一家公司被剔除模型在剩余候选里给某公司排第1正确排名就是1。这个口径更符合链接预测的实际语义我们想知道的是模型能不能把正确答案从未知里挑出来而不是从已知正确里挑出来。3.3 两种口径的实测差距与选择建议我在一个中等规模图谱约4万实体、20万三元组上做过对比同一个TransE模型评估口径hit1hit10mean rankraw0.120.41386filtered0.210.63152差距非常明显hit10差了22个百分点mean rank差了一倍多。所以看论文或者对比模型时第一件事就是确认它报的是filtered还是raw。如果一篇论文报raw、另一篇报filtered直接比数字毫无意义。我的建议很明确做研究和对比一律用filtered这是当前的主流标准。raw指标只在你想了解模型在完全开放环境下的表现时才用而且要在报告里写清楚。另外要注意filtered的实现需要预先构建每个头关系对应的已知尾实体集合和每个关系尾对应的已知头实体集合这个索引构建如果写错指标会悄悄出错但不报异常非常隐蔽。提示filtered设置下如果某个测试三元组的正确答案在剔除后候选集为空极端情况需要特殊处理通常直接跳过该样本或按排名1计。不同实现的处理方式不一致跨实现对比时要留意。4. TransE、TransD、TransR在评估环节的差异化表现4.1 三个模型的核心机制差异决定了指标画像TransE把关系和实体都映射到同一个空间用h r ≈ t的平移假设建模。它的优点是参数少、训练快缺点是处理一对多、多对一、多对多关系时力不从心。反映到指标上TransE在1-to-1关系上hit10通常很高但在N-to-1关系上会明显掉。TransD引入了实体投影向量和关系投影向量为每个实体和关系分别学习一个投影矩阵把实体投影到关系相关的子空间再做平移。它相当于给TransE加了一层动态适配在复杂关系上指标更稳。实测中TransD相比TransEhit10通常能提升3-8个百分点mean rank改善更明显因为它在难样本上的排名不再那么离谱。TransR走得更远为每个关系单独学一个投影矩阵把实体从实体空间投影到关系空间。它的表达能力最强但参数量也最大训练慢、容易过拟合。在小图谱上TransR的hit10可能反而不如TransD因为过拟合导致泛化差在大图谱上TransR的优势才体现出来。4.2 用指标反推模型选择这里有个实用的经验看mean rank和hit10的比值。如果hit10高但mean rank也高说明模型在多数样本上能进前10但少数样本排名极差典型的是TransE在复杂关系上的表现。如果hit10和mean rank都改善说明模型整体排序质量提升TransD和TransR通常属于这类。我整理过一个粗略的选型参考场景特征推荐模型关注指标图谱小、关系简单、要快速出baselineTransEhit10为主关系类型复杂、有大量N-to-NTransDhit10 mean rank图谱大、算力充足、追求极致效果TransRhit1 hit10需要在线服务、延迟敏感TransE/TransDhit10 推理耗时注意这个表是经验性的不是铁律。最终还是要用你的数据跑一遍看filtered hit10和mean rank的实际分布。我见过TransR在某些领域图谱上被TransD反超的情况原因就是关系类型虽然多但每种关系的样本量太少TransR的投影矩阵学不好。4.3 负采样策略对指标的隐性影响评估指标虽然是在测试集上算的但训练时的负采样策略会深刻影响指标的性格。TransE原始论文用的是随机替换头或尾的均匀负采样这会导致模型对高频实体过度惩罚。后来常用的做法是伯努利负采样根据关系的头尾实体分布决定替换头还是尾的概率让负样本更难更合理。这个策略不改变评估公式但会改变模型学到的表示进而改变hit10和mean rank。我在同一个TransE上对比过均匀负采样的hit10是0.58伯努利负采样能到0.64mean rank从210降到165。所以当你对比两个模型的指标时要确认它们的负采样策略是否一致否则可能把负采样的功劳算到模型结构头上。5. 手写评估脚本从预测分数到hit10和mean rank的完整链路5.1 评估前的数据准备与索引构建自己写评估脚本第一步不是算指标而是把测试集和图谱的索引对齐。我习惯用三个字典entity2id实体到连续id的映射relation2id关系到连续id的映射true_triples一个集合存所有已知为真的三元组训练验证测试true_triples是filtered评估的关键。构建它的时候要注意验证集和测试集的三元组也要加进去因为它们在评估时都属于已知为真。很多人只加了训练集导致filtered不彻底指标偏低。# 构建filtered索引的示意 true_triples set() for h, r, t in train_triples valid_triples test_triples: true_triples.add((h, r, t)) # 为每个(h, r)构建已知尾实体集合为每个(r, t)构建已知头实体集合 hr_to_tails {} rt_to_heads {} for h, r, t in true_triples: hr_to_tails.setdefault((h, r), set()).add(t) rt_to_heads.setdefault((r, t), set()).add(h)这个索引构建看起来简单但如果图谱里有重复三元组或者id映射有冲突会静默出错。我的习惯是构建完后打印几个统计量len(true_triples)、len(hr_to_tails)、平均每个(h,r)对应的尾实体数跟原始数据对一下确认没漏没重。5.2 逐样本计算排名的核心逻辑对每个测试三元组分别做头替换和尾替换。以尾替换为例def evaluate_tail(model, h, r, t, all_entities, hr_to_tails): scores [] for e in all_entities: score model.score(h, r, e) # 距离越小越好 scores.append((e, score)) # 按分数升序排距离小在前 scores.sort(keylambda x: x[1]) # filtered剔除已知为真的其他尾实体 filtered [(e, s) for e, s in scores if e t or (h, r, e) not in true_triples] # 找正确实体的排名 for rank, (e, s) in enumerate(filtered, start1): if e t: return rank return len(filtered) # 理论上不会走到这这里有几个细节决定成败。排序方向TransE输出距离升序如果模型输出相似度要降序。filtered的剔除条件保留正确实体本身剔除其他已知为真的实体。排名从1开始还是从0开始学术界惯例从1开始但有些代码从0开始差1看起来小在hit1上就是天壤之别。头替换的逻辑对称把(h, r, t)换成(e, r, t)用rt_to_heads做filtered。每个测试三元组得到两个排名都存进列表。5.3 从排名列表到最终指标拿到所有排名后计算就简单了def compute_metrics(ranks): hit1 sum(1 for r in ranks if r 1) / len(ranks) hit3 sum(1 for r in ranks if r 3) / len(ranks) hit10 sum(1 for r in ranks if r 10) / len(ranks) mean_rank sum(ranks) / len(ranks) mrr sum(1.0 / r for r in ranks) / len(ranks) return hit1, hit3, hit10, mean_rank, mrr注意hit10的边界是r 10还是r 10标准是 10即排名第10也算命中。这个边界在排名恰好是10的样本多的时候会影响结果虽然通常影响不大但跨实现对比时要统一。另外mean rank要不要在filtered后重新计算要。filtered不仅影响hit也影响mean rank因为剔除候选后排名会前移。我见过有人hit用filtered、mean rank用raw报出来的数字自相矛盾。5.4 一个完整的评估流程示例把上面的片段串起来一个最小可用的评估流程是加载模型和id映射构建true_triples和两个filtered索引遍历测试集对每个三元组算头排名和尾排名汇总所有排名计算hit1/3/10、mean rank、MRR打印排名分布的分位数如25%、50%、75%、90%辅助判断第5步是我强烈建议加的。只看均值容易被骗分位数能告诉你排名的真实分布。如果90%分位数是8说明90%的样本都进了前10hit10至少0.9如果90%分位数是500那hit10肯定很难看。6. 那些年我在指标上踩过的坑与排查链路6.1 指标异常时的系统排查顺序当hit10低得离谱或者mean rank大得反常时不要急着改模型按下面的顺序排查确认排序方向打印几个样本的分数和排名看正确实体的分数是不是应该靠前的那个方向。方向反了hit10会接近0。确认filtered索引随机抽几个测试三元组手动检查hr_to_tails里是否包含了应该被剔除的实体。漏了会导致指标偏低多了把正确实体也剔了会导致排名算错。确认测试集没混入训练集如果测试三元组在训练集里出现过模型可能背答案指标虚高。反过来如果测试集构建有误指标虚低。确认实体全集替换时用的候选实体集合应该是全部实体不是测试集里出现的实体。用错了候选集排名会偏乐观。确认排名起始值从0开始还是从1开始统一口径。这个顺序是我踩坑踩出来的。有一次排查了一下午最后发现是第1步的排序方向问题——模型输出的是相似度我按升序排了hit10只有0.03改过来直接0.61。6.2 一个真实的排查案例hit10正常但mean rank爆炸有次评估TransEhit10是0.65看起来正常但mean rank高达2000多。按经验hit10 0.65的模型mean rank通常在100-300之间。这个矛盾说明有少量样本的排名极端大。我把排名列表排序看最大的几个值发现有几个样本的排名接近实体总数4万。单独看这几个样本发现它们的正确实体在模型里的表示向量几乎是零向量或者异常大的值。追查下去是训练时这几个实体出现次数极少长尾实体表示没学好。这不是评估的错是模型在长尾上的真实短板。这个案例的启示是mean rank爆炸时先看排名分布的长尾再决定是修评估还是修模型。如果是评估口径问题长尾不会那么极端如果是模型问题长尾会集中在特定类型的实体或关系上。6.3 跨论文对比指标时的三个陷阱读论文对比指标时我总结过三个高频陷阱filtered vs raw不统一前面讲过差距巨大。测试集划分方式不同有的论文用随机划分有的用按时间划分有的用按关系划分。划分方式不同难度不同指标不可比。负采样和评估的实体集不同有的实现评估时只用了测试集里出现过的实体作为候选这会让指标虚高。标准做法是用全部实体。我的做法是看到一篇论文的指标先找它的评估设置章节确认这三点再决定要不要信这个数字。如果论文没写清楚那这个指标基本没法用于对比。6.4 提升指标的几个实操方向如果你的模型hit10不理想除了换模型结构还有几个低成本的方向调负采样比例负样本太多会让模型学得保守太少会学得激进。我通常从1:1开始试逐步加到1:5、1:10。加正则TransE的表示容易发散加L2正则通常能提升mean rank。调维度实体和关系维度不是越大越好。小图谱上50-100维往往比200维好因为过拟合。用filtered评估指导训练训练过程中定期在验证集上算filtered hit10早停策略基于这个指标而不是loss。loss降但hit10不升说明过拟合了。这些方向我都实测过负采样比例和正则的影响往往比换模型结构还大。所以别一上来就上TransR先把TransE的评估和训练细节调好baseline可能就够用了。7. 写在最后的一点个人体会评估指标这东西看起来是算个数实际上是对整个任务理解的浓缩。hit10和mean rank的每一个细节——排序方向、filtered口径、排名起始值、候选实体集——背后都是对链接预测到底在预测什么的回答。我见过太多人模型结构调得很花哨评估却用错口径最后报出来的数字自己都解释不清。我的建议是先把评估脚本写对、写透再回头调模型。一个正确的filtered hit10和mean rank比十个花哨的模型结构更能告诉你问题在哪。另外别迷信单一指标hit1、hit10、mean rank、MRR、排名分布能一起看就一起看。指标之间的矛盾往往就是下一个优化方向的入口。最后分享一个小习惯每次评估完我会随机抽10个测试样本把它们的候选排名前5打印出来人工看一眼。这个动作花不了几分钟但能抓到很多自动指标抓不到的诡异问题比如某个关系下的实体全被排到了后面、某个高频实体霸占了所有top位置。机器算指标人看样本两者结合才靠谱。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进