第3章:RotatE模型原理 — 旋转嵌入、关系语义与目标函数

各位同学,今天咱们聊聊 RotatE。讲真,我第一次看到这个模型时,第一反应是:「这名字听着像是个旋转餐厅?」后来真正上手才发现——它确实是在复平面上玩旋转。而且玩得很漂亮。

我之前在做一个药物-靶点关系预测项目时,用 TransE 和 DistMult 都试过,效果一般。后来换成 RotatE,嗯,效果一下子就上来了。不是说它万能,但至少在对称 / 反对称 / 组合关系这些场景下,RotatE 的建模能力确实强。

3.1 旋转嵌入:把实体放到复空间

先看最核心的概念。传统知识图谱嵌入模型(比如 TransE)把实体和关系都映射到实数向量空间。RotatE 不一样——它把实体嵌入放到复向量空间里。

为什么要这么做?

我个人的理解是:关系本质上是一种变换。比如关系 r 把头实体 h 变成尾实体 t。在实数空间里,这个变换可能是平移(TransE)、线性映射(DistMult)等等。但在复空间里,有一种天然且优美的变换——旋转。

RotatE 的核心假设:

  • 每个实体 h, t 表示为复向量(维度为 d)
  • 每个关系 r 表示为一个逐元素旋转操作
  • 对于第 k 维,旋转角度为 θr,k

公式表达就是:

t = h ∘ r
其中:
h_k = a_k + i·b_k
r_k = cos θ_r,k + i·sin θ_r,k
t_k = h_k · r_k = (a_k cos θ_r,k - b_k sin θ_r,k) + i·(a_k sin θ_r,k + b_k cos θ_r,k)

说白了,就是把每个维度的实体向量乘上关系对应的旋转因子。这个方式在复数模长上是保范的——旋转不改变向量的模长,只改变方向。这个性质特别好,因为它天然约束了关系的语义。

关键理解:TransE 是平移(h + r ≈ t),RotatE 是旋转(h ∘ r ≈ t)。都是线性变换,但旋转能建模更丰富的模式。

3.2 关系语义:对称、反对称、组合、逆关系

咱们看看 RotatE 到底能表达哪些关系模式。我做过对比实验,下面这张表是我根据项目经验整理的:

关系模式 解释 RotatE 能力 条件
对称关系 r(h,t) 且 r(t,h) ✅ 可建模 r ∘ r = 1 → θ = 0 或 π
反对称关系 r(h,t) 且 ¬r(t,h) ✅ 可建模 θ ≠ 0, π
逆关系 r1(h,t) 且 r2(t,h) ✅ 可建模 r2 = conj(r1)
组合关系 r3(h,t) = r1 ∘ r2 ✅ 可建模 θ3 = θ1 + θ2

举个例子,在药物知识图谱里,"与-相互作用-产生副作用" 这个关系,通常是不对称的(药A引起副作用S,但副作用S一般不会反过来引起药A)。RotatE 能很好地区分这种方向性。

我曾经踩过一个坑:在某个数据集上,用 TransE 做链接预测,对称关系(比如 "化学结构相似")总是预测反了。后来换成 RotatE,效果好得多。为什么?因为 TransE 对一个对称关系只能学出 r ≈ 0,但 RotatE 可以学出 θ = 0(即旋转0度)——同样是恒等变换,但 RotatE 保留了维度细节,更稳定。

3.3 目标函数与损失

模型设计好了,怎么训练?

RotatE 使用的是负采样 + 自对抗损失(self-adversarial loss)。这个损失函数在当年是很有新意的。

咱们先看评分函数:

score(h, r, t) = -||h ∘ r - t||

也就是说,如果 h∘r 和 t 越接近,score 越大。负样本则希望 score 尽量小。

损失函数形式:

L = -log σ(γ - d(h,r,t)) - Σ [w_i · log σ(d(h_i', r, t_i') - γ)]
其中 d(h,r,t) = ||h ∘ r - t||
w_i 是自对抗采样权重

这里的 γ 是固定边距(margin)。我在调参时习惯先设 γ=9.0,然后看验证集表现调整。

实际技巧:负采样数量一般取 256~1024。数据集越大,负样本数可以适当减少;数据集小,反而要多用负样本来避免过拟合。

3.4 自对抗负采样

自对抗采样是 RotatE 的一大亮点。传统方法随机替换头实体或尾实体生成负样本,但很多负样本太"弱"了(比如明显错误的三元组),模型学不到东西。

RotatE 的做法是:根据当前模型对每个正三元组附近的候选实体的评分,动态分配采样概率。评分越高的实体(越容易让模型混淆),被选为负样本的概率越大。

算法流程:

1. 对每个正三元组 (h,r,t),随机采样 N 个候选实体
2. 计算每个候选的 score
3. 用 softmax 归一化得到采样概率
4. 根据概率采样负样本
5. 使用这些负样本计算损失

这样做的好处很明显——模型会越来越"关注"那些真正有挑战性的负例,训练效率高不少。

3.5 RotatE 整体流程

咱们用一张图把整个流程串起来:

RotatE训练流程 RotatE 模型训练流程 输入三元组 (h,r,t) 实体 h,t → 复数向量 关系 r → 旋转角度 h ∘ r = t' 逐元素旋转 score = -||t'-t|| 自对抗负采样 损失计算 L 梯度更新 → 优化嵌入 说明 自对抗:选择模型 当前更容易混淆的 负样本进行训练

曾经踩过的坑:我在实现自对抗采样时,忘了给候选实体分数加一个温度参数(默认是1.0),导致采样分布过于尖锐,模型只关注最难的几个样本,训练不稳定。后来加了温度系数 β=0.5 才收敛。如果你复现时感觉 loss 震荡厉害,先检查一下这个 β。

3.6 训练超参数参考

根据我的项目经验,RotatE 在药物知识图谱上的常用配置如下:

参数 推荐值 说明
嵌入维度 d 200~500 药物KG通常实体数不多,d=300 比较稳妥
边距 γ 9.0~24.0 我习惯先设 9.0,看效果再调
负采样数 n_sample 256 如果实体数超过 5 万,可以降到 128
自对抗温度 β 0.5~1.0 太难收敛就降 β
学习率 0.00005~0.001 Adam优化器,初始 0.0001
批大小 batch_size 512~2048 GPU 显存够就大一点

我建议你刚开始跑时,先在小型子集上试一遍流程,确认收敛曲线平稳了再上全量数据。不然一次训练几个小时,发现 loss 不降就尴尬了。

好,RotatE 的核心原理就这些。咱们后面会再把它和 GCN 结合起来聊聊怎么在药物知识图谱上落地。今天就先消化这些。