经典KG模型:TransE、TransR、DistMult、ComplEx
搞药物知识图谱的都知道,选对模型比调参更重要。我个人习惯从最熟悉的模型入手,这样出了问题也好定位。今天咱们把四个经典模型掰开揉碎讲清楚。
| 模型 | 核心思想 | 适用场景 | 个人评价 |
|---|---|---|---|
| TransE | 头实体 + 关系 ≈ 尾实体 | 大规模、简单关系 | 快,但处理复杂关系吃力 |
| TransR | 关系独立映射空间 | 多语义、复杂关系 | 精度高,参数多 |
| DistMult | 对角矩阵分解 | 对称关系 | 简洁,但不支持非对称 |
| ComplEx | 复数空间嵌入 | 非对称、对称混合 | 均衡,我的主力模型 |
TransE:简单粗暴的基线模型
TransE 的思路特别直观。它假设 h + r ≈ t,也就是头实体加上关系,应该等于尾实体。说白了,就是把知识图谱的每一个三元组,用一个向量加法来解释。
为什么这么简单的东西还有用?在药物KG中,很多关系确实是可加的。比如“阿司匹林”+“治疗”≈“头痛”。这个假设在大规模数据上成立得特别好。
我曾经在计算药物相似度时用过TransE。当时数据量有500万三元组,别的模型跑不动,只有TransE能在8小时内收敛。不过后来发现,它对1-N、N-1、N-N这种复杂关系束手无策。
# PyG 示例:TransE 评分函数
def transE_score(head, relation, tail):
return torch.norm(head + relation - tail, p=1, dim=-1)
TransR:关系独立投影
TransR 解决了TransE的核心问题——每个关系都有自己的映射空间。你可以把它想象成不同的场景用不同的语言翻译。
在药物KG里,“靶向”和“抑制”这两种关系,显然不在一个语义空间里。TransR 为每个关系学一个投影矩阵,让实体在高维空间里灵活转换。我记得有一次做药物重定位,用TransR找到了几个已知药物的新靶点,效果出奇的好。
不过代价也很明显:参数太多了。每个关系都要学一个矩阵,如果关系数上万,显存直接爆炸。
# TransR 投影计算
def transR_score(head, relation, tail, W_r):
head_proj = torch.matmul(head, W_r)
tail_proj = torch.matmul(tail, W_r)
return torch.norm(head_proj + relation - tail_proj, dim=-1)
DistMult:对角矩阵简化
DistMult 走的是另一条路——不投影,改用点积。它把关系表示成一个对角矩阵,头实体和尾实体直接相乘。好处是计算极快,参数少。
有个大坑:DistMult假设所有关系都是对称的。也就是说,“A治疗B”和“B治疗A”的分数必须一样。在药物KG里这显然不对——药物和疾病的关系不是双向的。
我曾经在基因-疾病关系上用过DistMult,结果一塌糊涂。后来才意识到问题出在对称性假设上。所以它的适用场景,只限于“相似于”、“相互影响”这类对称关系。
# DistMult 评分:h * diag(r) * t
def distmult_score(head, relation, tail):
return torch.sum(head * relation * tail, dim=-1)
ComplEx:复数空间的革命
ComplEx 是我现在的主力模型。它在DistMult基础上,把实数扩展到了复数空间。你可以想象成分量实部+虚部,每个实体和关系都有两个向量。
为什么这样就能处理非对称关系了?因为复数乘法不是对称的。嗯,这里要注意,复数的共轭操作让 “h→t” 和 “t→h” 不一样。这样既能保留DistMult的高效,又能支持非对称关系。
我在DrugBank上做过测试,ComplEx在Hit@10指标上比DistMult高出15%。尤其是药物-靶点这类有方向性的关系,表现特别好。唯一的缺点是,虚部的解释性不如实数直观。
# ComplEx 评分:Re(h * diag(r) * conj(t))
def complex_score(head, relation, tail):
return torch.real(torch.sum(head * relation * torch.conj(tail), dim=-1))
四个模型的对比总结
说句实话,没有最好的模型,只有最合适的。我自己的经验是:
- 数据量大、关系简单 → 直接用TransE,快且稳定
- 关系语义复杂 → 上TransR,但要做好参数裁剪
- 关系以对称为主 → DistMult,效率最高
- 混合关系、需要精度 → ComplEx,我的首选
我个人强烈建议,不管最终用哪个模型,先用TransE跑一遍基线。它能帮你快速发现数据的问题,比如缺实体、关系炸裂等等。我在项目中吃过亏,跳过基线直接上复杂模型,结果调了个把月才发现是数据脏了。
你会注意到,四个模型其实有一个清晰的演进脉络。TransE 是基石,TransR 解决了映射能力,DistMult 走了点积捷径,ComplEx 最终统一了对称与非对称。我个人建议,先从TransE开始,哪里不够补哪里。