1. 为什么今天还要聊 Freebase先说结论Freebase 是一个已经停止官方服务的老牌开放知识图谱数据集但它在今天依然是知识图谱、实体链接、关系抽取、问答系统这些方向里绕不开的一块基石。我第一次接触它是在做一个实体消歧的小项目时当时手头的语料里出现了大量人名、地名、机构名混在一起的情况规则匹配根本扛不住后来翻了半天资料发现很多论文的评测基准都是从 Freebase 上切出来的子集比如 FB15k、FB15k-237、WebQuestions 这些名字你应该多少都见过。它的定位说白了就是一个把现实世界的实体和关系用结构化三元组建起来的巨型数据库。实体就是某个人、某个地方、某部电影关系就是出生于、导演了、属于哪个类型三元组就是实体A - 关系 - 实体B这种形式。听起来跟现在的很多知识图谱没区别但 Freebase 的价值在于它当年的规模和覆盖面以及它衍生出来的那一批评测数据集几乎成了这个领域事实上的公共标尺。什么人适合看这篇如果你在做知识图谱相关的算法、想找一个靠谱的公开数据集练手或者你在读论文时被 FB15k、FB15k-237 这些名词绕晕了想知道它们到底从哪来、怎么用那这篇就是给你写的。我会把 Freebase 的结构、它的衍生数据集、下载和处理方式、以及实际踩过的坑都摊开讲尽量让你看完就能动手。如果你只是想知道热词榜里那些数据集名词背后的逻辑这篇也能帮你建立一个大框架。2. Freebase 到底是什么结构长什么样2.1 从人肉维基到结构化知识库的演变Freebase 最早的出发点其实很朴素维基百科的文本信息太散机器读不懂那就人工把事实拆成结构化的条目。它的数据模型核心叫主题Topic每个主题有唯一的 ID形如/m/0f8l9c这种这串 ID 在整个体系里是全局唯一的。每个主题下面挂着一堆属性Property属性又分为两类一类是指向另一个主题的关系比如导演指向某个具体的人另一类是字面值比如上映年份是 1999 这种数字或字符串。这种设计的好处是灵活。它不像传统关系型数据库那样要求你先定义好表结构而是允许不同类型的实体有完全不同的属性集合。一部电影可以有时长、票房、分级一个科学家可以有研究领域、毕业院校、获奖记录互不干扰。代价就是查询和推理会复杂一些因为关系是稀疏的很多实体之间并没有直接连接。它背后用到的存储和查询体系早期是基于图结构的后来开源成了一个叫 graphd 的查询引擎配合自己的查询语言 MQL。你写查询的时候思路很像在描述一个子图模式我要找所有类型是电影、且导演的国籍是某国、且上映年份在某个区间的实体。这种描述形状的方式比写 SQL 的 join 更贴近人的直觉但学习成本也不低。2.2 三元组才是真正被广泛使用的形态虽然 Freebase 自己有一套复杂的主题-属性模型但后来被学术界用得最多的其实是把它拍平成三元组。原因很简单绝大多数知识图谱嵌入模型比如 TransE、DistMult、ComplEx输入的都是 (头实体, 关系, 尾实体) 这种统一格式。Freebase 的原始 dump 里关系被简化成类似/film/director/film这样的路径字符串头尾实体就是主题 ID。这里有个细节值得说清楚Freebase 里的关系名其实是带命名空间的路径/film表示电影这个领域/director表示导演这个关系最后一段/film表示这个关系的取值范围还是电影。理解这个层级你在筛选关系的时候就不会乱。比如你想只保留人物相关的三元组就可以用/people/这个前缀去过滤。我实测下来的感受是直接用原始 dump 做嵌入训练效果往往不如用它官方切好的子集。原因有两个一是原始数据规模太大噪声也多二是不同关系出现的频次差异极大热门关系几万条冷门关系可能只有几条直接训练会让模型严重偏向高频关系。这也是为什么后来会有 FB15k 这种精选版。2.3 数据规模与覆盖范围的真实情况Freebase 在停止维护前积累的实体数量在千万级别关系类型有上万个三元组总量是数十亿这个量级。这个规模在当年是相当恐怖的放到今天虽然被一些更大的语料库超越但它的数据质量、实体对齐程度、以及被学术界的引用量依然有很强的参考价值。覆盖范围上它明显偏重几个领域影视、音乐、人物、地点、体育、书籍。这几个领域的条目最完整关系也最丰富。而像医学、法律、工程这些专业领域覆盖就比较稀疏了。你在选数据集的时候要特别注意这一点如果你的任务领域是医学实体关系抽取用 Freebase 基本是浪费时间。还有一个隐藏问题Freebase 的不少数据是从维基百科和人工编辑来的不同来源的标注标准不统一。同一个实体可能出现重复条目或者关系方向和定义有细微差异。这在做严格评测时是个坑需要额外的清洗步骤。3. 从 Freebase 衍生出的那些数据集3.1 FB15k 与 FB15k-237被引用最多的两个FB15k 是从 Freebase 里挑出来的一个子集包含约 1.5 万个实体和 1300 多种关系三元组数量在 59 万左右。挑选的逻辑大致是保留那些在 Freebase 里出现频次较高、且实体之间连接比较密集的部分。这样切出来的图训练起来不会太稀疏评测也相对稳定。但 FB15k 后来被发现有一个严重缺陷存在大量的反向关系。也就是说如果存在(A, 导演, B)数据里几乎必然存在(B, 被导演, A)这种镜像。模型只要学会这个规律就能在链接预测任务上刷出高分但它其实没有真正学到语义。这个问题在 2015 年被明确指出后就催生了 FB15k-237。FB15k-237 的做法是把那些和训练集存在明显泄漏或冗余关系的数据剔除掉保留了约 1.4 万个实体和 237 种关系三元组降到 31 万左右。关系种类从 1300 多砍到 237砍掉的主要就是那些反向、冗余、过于相似的关系。它的评测指标因此更可信也让后续很多模型不得不认真对待泛化能力而不是靠记住镜像关系。提示如果你在复现老论文注意它用的是 FB15k 还是 FB15k-237这两个数据集上的指标没有可比性混用会得出错误结论。3.2 WebQuestions 与复杂问答基准WebQuestions 这个名字你可能在问答系统的论文里见过它的问题是从搜索引擎的查询日志里来的答案则通过 Freebase 来标注。典型的例子是谁导演了某部电影某个演员出生于哪一年答案就是 Freebase 里对应的实体或字面值。它的价值在于把自然语言问题和结构化知识库连了起来。你在做问答系统时第一步要把问题解析成实体和关系第二步才是去知识库里查。WebQuestions 提供了端到端的评测样本让你能衡量整个流程的效果而不只是单步的抽取准确率。后来还出现了更难的版本比如 WebQuestionsSP它要求模型输出一个可执行的查询路径而不只是给出答案。这种设计对模型的推理能力要求更高也更接近真实应用场景。3.3 与其他热词榜数据集的横向对比热词里出现了 coco2017、ImageNet、KITTI、nuScenes、CWRU 轴承数据集、MNIST 这些。它们和 Freebase 属于完全不同的类型但放在一起看能帮你建立数据集分类的直觉。数据集领域数据形态典型任务Freebase通用知识三元组、图知识图谱补全、实体链接COCO2017视觉图像标注框/掩码目标检测、分割ImageNet视觉图像类别标签图像分类KITTI/nuScenes自动驾驶点云图像标定3D检测、跟踪CWRU工业信号振动时序故障诊断MNIST视觉灰度图手写数字分类看懂这张表你就能明白一个道理选数据集的第一步永远是明确任务类型再去匹配数据形态。Freebase 是图结构、离散符号的它天然适合做关系推理你拿它去做图像任务就是南辕北辙。很多人在热词榜上看到一堆数据集名字就盲目下载结果发现格式完全不匹配自己的模型这个坑我见得太多了。Freebase 这类知识图谱数据集还有一个独特之处它是有语义类型的。每个实体通常属于一个或多个类型类型本身也是主题这让你可以做类型约束的推理。视觉数据集就没有这种显式的类型体系这是它在结构上的差异。4. 下载、处理与格式转换的实操4.1 从哪里获取以及版本选择Freebase 的官方服务早已下线现在的数据主要通过几个渠道获取。一是它的历史数据存档二是各大评测平台和论文附带的子集链接。FB15k、FB15k-237 这些子集在不少公开仓库里都能找到它们通常以文本文件形式提供格式是每行一个三元组用制表符分隔。版本选择上有个原则做学术复现就严格用论文指定的版本做工程实践就优先选清洗更彻底的 FB15k-237。如果你需要更广的覆盖可以找找 Freebase 的完整 dump但要做好清洗的心理准备那个工作量不小。注意下载时务必核对数据的 entity2id 和 relation2id 映射文件是否齐全。很多仓库只给了三元组文本没给 ID 映射导致你无法还原实体名称这在后续分析时非常麻烦。4.2 文本格式的三元组怎么读进来FB 系列数据集通常包含三个文件训练集、验证集、测试集每行形如头实体ID 关系ID 尾实体ID。用 Python 读的话很简单def load_triples(path): triples [] with open(path, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue h, r, t line.split(\t) triples.append((h, r, t)) return triples train load_triples(train.txt) valid load_triples(valid.txt) test load_triples(test.txt)读进来之后建议先做一次统计实体总数、关系总数、每个关系的频次分布、是不是存在孤立实体。这些数字能帮你判断数据是否健康。我一般会算一下关系频次的中位数和最小值如果最小值只有个位数就要考虑是否把长尾关系合并或者过滤掉。4.3 转换成模型需要的张量格式大部分知识图谱嵌入模型只接受整数索引。所以你需要在读入三元组后自己构建实体和关系的词表把字符串 ID 映射成从 0 开始的连续整数。同时要保存正反向映射方便后续把预测结果翻译回可读名称。ent2id {} rel2id {} def build_vocab(triples): for h, r, t in triples: if h not in ent2id: ent2id[h] len(ent2id) if t not in ent2id: ent2id[t] len(ent2id) if r not in rel2id: rel2id[r] len(rel2id) build_vocab(train valid test)注意这里一定要用训练集、验证集、测试集的并集来建词表否则测试集里出现训练时没见过的实体你的索引会越界。这个细节看起来小但很多人第一次做的时候就在这翻车。建完词表再生成张量import torch def to_tensor(triples): idx [[ent2id[h], rel2id[r], ent2id[t]] for h, r, t in triples] return torch.tensor(idx, dtypetorch.long) train_t to_tensor(train)4.4 负采样与数据划分的要点链接预测任务默认是给定头实体和关系预测尾实体。训练时除了正样本还要构造负样本最常用的办法是随机替换头或尾实体。这里有个经验替换出来的负样本要检查是否恰好是真实存在的三元组如果是就要重新采样否则会引入错误标签。数据划分上标准做法是训练集占大头验证集和测试集各占一小部分。FB15k 系列的官方划分已经给好了你直接用就行。但如果你自己从完整 Freebase 里切数据一定要按实体或时间做划分不能随机按三元组切否则会出现信息泄漏——同一个实体的不同关系分散在训练和测试里模型等于提前见过答案。5. 实际使用中的常见问题与排查5.1 指标高得离谱是怎么回事如果你在 FB15k 上训练一个简单模型发现 Hits10 轻松上到 0.9 以上先别高兴这大概率是反向关系泄漏导致的。解决办法就是换用 FB15k-237或者自己手动检测数据里是否存在(h, r, t)和(t, r_inv, h)成对出现的情况。检测方法很直接统计每个关系的成对出现率。如果某个关系 A 和某个关系 B满足绝大多数 A 三元组的头尾恰好是 B 三元组的尾头那基本可以判定是互逆关系。动手写个小脚本跑一遍几分钟就能出结果。5.2 长尾关系让模型学不动FB 数据集里关系频次的分布是典型的幂律分布少数关系占了大部分三元组。模型在训练时会被高频关系主导长尾关系上的表现很差。常见的缓解手段有三种一是对高频关系降采样二是对长尾关系做数据增强三是在损失函数里给不同关系加权。我个人的做法是先把频次低于某个阈值的关系整体过滤掉虽然会损失一部分覆盖率但模型整体指标的方差会小很多评测结果更稳定。这个阈值取多少取决于你的任务对召回率的要求。如果任务更看重精度阈值可以高一点。5.3 实体类型信息丢失的问题Freebase 原始数据里其实带了实体的类型但很多衍生子集在拍平成三元组时把类型信息丢掉了。这就导致你没法做类型约束也无法按领域筛选。如果你需要这部分信息得回溯到更原始的版本去找。有个折中办法用关系本身做近似推断。比如一个实体频繁出现在/film/相关的关系里那它大概率是电影类实体。这种推断不精确但胜在不需要额外数据。5.4 常见问题速查表现象可能原因排查方向指标异常高反向关系泄漏换 FB15k-237 或检测互逆关系索引越界报错词表未覆盖全集用三个集合的并集建词表长尾关系效果差频次分布不均过滤、加权或增强无法还原实体名缺少 ID 映射文件找回 entity2id 表训练不收敛学习率或负采样问题调学习率、检查负样本合法性数据量过大跑不动完整 dump 太大改用精选子集6. 我踩过的坑和一些实操心得第一个心得是关于数据版本。我曾经为了省事直接从某个仓库下载了一份自称FB15k的数据跑出来的指标比论文高出一大截当时还以为自己调参调出了奇迹。后来仔细核对才发现那个版本没有做标准的训练测试划分测试集里混进了训练集的三元组。从那以后我养成一个习惯拿到任何数据集先算训练集和测试集的交集非空就直接弃用。这一步花不了两分钟但能省掉后面的所有返工。第二个心得是不要迷信规模。很多新手觉得数据集越大越好恨不得把整个 Freebase 都塞进模型。但图数据的特点是连通性和密度比绝对数量更重要。一个连接紧密的小子图训练出来的嵌入质量往往比一个松散的大图要好。我做过一次对比同样用 TransEFB15k-237 上的效果就明显比我从完整 dump 里随机切的同样大小的子集要稳。原因就在于官方子集在切分时考虑了连接性。第三个心得是善用验证集做早停。知识图谱嵌入模型很容易过拟合尤其是实体数量少、关系种类多的配置下。我一般会把验证集上的 MRR 作为早停依据连续几轮不提升就停。这个策略比固定训练轮数靠谱得多能避免模型在后期把训练集的关系频次背下来。关于实体链接这个任务再补充一点。Freebase 的实体 ID 是全局唯一的这在做链接时是个天然优势你可以直接用它做锚点。但要注意别名的处理同一个实体在文本里可能有多种写法需要先做归一化。我处理过的语料里光是一个人名就有全称、简称、带头衔、英文转写好几种形式如果不先做别名映射链接准确率会低得很难看。最后说一个关于评测的细节。链接预测的评测有两种模式原始模式和过滤模式。过滤模式会把那些在知识库里真实存在、但不在当前划分里的正确三元组从候选里排除避免它们被误判为错误预测。论文里报告的基本都是过滤模式你自己评测时一定要对齐否则数字没法比。这个细节很多人第一次做会忽略导致自己的指标莫名其妙偏低然后到处怀疑是模型的问题。Freebase 虽然官方不再更新但它衍生出的评测体系和方法论已经深深嵌进了知识图谱这个领域的日常工作中。你理解了它的结构和那些经典子集的设计逻辑再看今天各种新出的知识图谱数据集会有一个很清晰的参照系。至于它后续还能怎么用我觉得最值得关注的是它和文本语料的结合比如用 Freebase 的结构化关系去监督文本里的关系抽取这类跨模态的用法实际效果往往比纯结构或纯文本的单一路线更扎实。