文章目录

  • 前言
    • 论文结构
  • 导读
    • 研究背景
    • Trans系列算法概述
    • 数据集简介
    • 研究成果
    • 研究意义
    • 摘要
    • 论文结构
  • 论文精读
    • 知识树
    • 算法模型总览
      • 算法系列图谱
      • Notation
    • 细节一:TransE模型精讲
      • 负采样的trick
      • TransE模型的不足
    • 细节二:TransH模型精讲
    • 细节三:TransR模型精讲
      • CTransR
    • 细节四:TransD模型精讲
    • 细节五:模型对比与总结
  • 实验设置和结果分析
    • 数据集
    • Mean rank metric
    • 参数规模
    • 超参数设置
    • Link prediction
    • 多种关系的三元组的效果统计
    • 模型inference示例
    • 新关系预测
  • 论文总结
  • 复现
  • 开源库的安装
  • TransE主要代码
    • 主程序: train_transe_FB15K237
    • Trainer
    • NegativeSampling
    • MarginLoss
    • TransE
  • 作业

前言

本课程来自深度之眼,部分截图来自课程视频。

文章标题:Translating Embeddings for Modeling Multi-relational Data
知识图谱向量化表示
作者:Antoine Bordes, Nicolas Usunier, Alberto Garcia-Duran/Jason Weston, Oksana Yakhnenko

单位:CNRS, France/Google
发表会议及时间:NIPS 2013
公式输入请参考:在线Latex公式
文章虽然较早,但是有好几个衍生模型:trans算法系列,本文将一并介绍。
TransH:Knowledge Graph Embedding by Translating on Hyperplanes
TransR:Learning entity and relation embeddings for knowledge graph completion
TransD:Knowledge Graph Embedding via Dynamic Mapping Matrix
本文是GNN系列的第二篇非简单图,也是这个系列的最后一篇。
上篇论文讲的是异质图,这篇是知识图谱。

论文结构

  1. Abstract:提出基于对多关系数据的建模,将实体(点)和关系(边)映射到低维空间。前几篇文章只对点进行映射。
  2. Introduction:多关系数据广泛存在于社交网络、推荐系统和知识图谱,难点在于多类型的点和边。
  3. TransE:基于embedding、最大间隔、负采样,提出transE模型。
  4. TransD(扩展内容):与TransR相比将参数映射矩阵换成了两个向量,减少了模型参数。
  5. TransR(扩展内容):与TransE/TransH相比参数较多,关系空间(space)。
  6. TransH(扩展内容):TransH使一个实体在不同的关系中拥有不同的角色,关系超平面(hyperplane)。
  7. Related work:与SE、SME、LFM等模型比较,TransE模型减少了参数,而且模型更有效。
  8. Experiments:实验选取了Wordnet和Freebase作数据集,探究模型有效性:边的预测、案例分析。
  9. Conclusion:总结提出的transE模型的优点:参数少、效果好、易扩展。

导读

研究背景

知识图谱常用三元组(triples)来表示,例如:(Beijing,Capital City,China)
上例中前后两个元素论文中都称为实体,中间元素称为关系,Beijing是Header,Capital City是Relation,China是Tail。从图的角度来看实体就是结点,关系就是边。本文的目的就是:Learn low-dimensional vectors for words and KB(knowledge base) entities and relations.
知识图谱的应用场景有:
Question answering
Search
Recommender Systems
Natural language understanding

论文中提到的多关系数据的定义,原文用的是Multi-relational Data,其实就是知识图谱。下面来看Multi-relational Data和GRAPH的对应关系。
Data is structured as a graph
Each node=an entity
Each edge=a relation/fact
A relation=(sub, rel, obj):
. sub=subject,
. rel=relation type,
. obj=object.
Nodes w/o features.

对于上面这个知识图谱的例子,我们如果可以把里面的实体进行embedding得到低维向量(Encode entities as vectors)那么就可以得到:
Paris (0.036,-0.12,.…,0.323)
capital (0.102,0.671,.…,-0.101)
France(0.138,0.551,…,0.222)
有三个方面用途:

  1. 捕获实体的语义相似度Semantic similarity of entities
  2. 得到实体间的向量运算关系,类似还有Word2Vec里面提到的内容(男人-女人=国王-王后),但是这里学习了边的embedding,所以这里运算结果是得到边,也就是实体之间的关系。
    Relational inferences as vector algebra
    France-Paris = capital
    US-USD= currency
    Bach-German = nationality
  3. 能把结果应用到下游任务
    KG(knowledge graph) Completion知识图谱补全
    Relation extraction from text文本关系提取
    Question answering知识问答

下面来看knowledge graph的一个例子:
假如我们现在有如下三元组Triples
(beyonce_knowles, member_of, destinys_child)
(kelly_rowland, member_of, destinys_child)
(michelle_williams, member_of, destinys_child)
(destinys_child, start_date,1997)
(destinys_child, end_date,2005)
那么就可以构造下图的KG

Trans系列算法概述

这个算法的大概思想就是想把三元组(h,r,t)都映射到一个D维空间中,并使得三元组中的三个向量满足如下图所示的关系,就是
h⃗+r⃗=t⃗(1)\vec{h}+\vec{r}=\vec{t}\tag1h

+r

=
t

(1)
因此整个Trans系列的算法中的Translation就是指的从h通过r Translation到t

第九行是负采样;
第十二行是梯度下降更新loss

对于TransH而言,是将h映射到r的超平面上得到h⊥h_{\perp }h,然后t映射到r超平面上得到t⊥t_{\perp }t,最后满足:
h⊥+r=t⊥h_{\perp }+r=t_{\perp }h+r=t
这个方法是思想是:实体h与多个实体t之间的存在关系,那么实体h的embedding和实体t的embedding可以通过映射,表达多个不同的关系,因此这个模型的表达能力更强。
在TransR模型中,是将h和t映射到一个空间,r映射到另外一个空间,两个空间维度不一样,之前的算法都是映射到同一个空间,维度一样。
然后用MrM_rMr分别与h和t做运算(具体维度看总结表),可以把h和t映射到r的空间中得到h⊥h_{\perp }ht⊥t_{\perp }t,最后满足:
h⊥+r=t⊥h_{\perp }+r=t_{\perp }h+r=t

数据集简介

两个数据集:Wordnet、Freebase
Baselines:Unstructured(这个重点讲)、RESCAL、SE、SME、LSM
Unstructured这个重点讲下,因为其他方法和GNN相差较远,这个方法中认为r⃗=0\vec{r}=0r

=0,因此其采用的损失函数是:
h⃗+r⃗=t⃗→h⃗=t⃗\vec{h}+\vec{r}=\vec{t}\rightarrow \vec{h}=\vec{t}h

+
r

=
t

h

=
t


意思是h和t共现,那么希望他们两个的embedding越接近越好。


文中虽然只用了两个数据集,但是由于Freebase较大,所以对这个数据进行了处理,一个是精简版的15k个实体,一个是1M的实体。另外关于训练集、验证集、测试集的划分可以看上图。

研究成果

参数规模,即空间复杂度不大。

本文应用了多个任务:边的预测(Link Prediction)、案例分析(Case Study)、新关系预测(New Relationship)具体在精读部分再细讲。

研究意义

引用量2000+
启发了整个Trans系列知识表示学习,代表性工作有:transH,transR,transD
模型简单而有效,容易训练
学到了entity和relation的embedding表示
知识图谱上的经典工作,非常实用,还可以关注RGCN

摘要

1.使用低维向量表示三元组数据(知识图谱)的实体和关系;
We consider the problem of embedding entities and relationships of multirelational data in low-dimensional vector spaces.
2.易于训练,模型参数少(看表2),可以扩展到大的数据;
Our objective is to propose a canonical model which is easy to train, contains a reduced number of parameters and can scale up to very large databases.
3.模型的损失函数是基于实体和关系向量的计算(translations)(看公式1);
Hence, we propose TransE, a method which models relationships by interpreting them as translations operating on the low-dimensional embeddings of the entities.
4.通过边的预测等任务在两个数据集验证了模型的有效性。(SOTA)
Despite its simplicity, this assumption proves to be powerful since extensive experiments show that TransE significantly outperforms state-of-the-art methods in link prediction on two knowledge bases.

论文结构

  1. Introduction
  2. Translation-based model
  3. Related work(不必深究,相关工作与GNN关系不大,模型较老)
  4. Experiments
    4.1Data sets
    4.2Experimental setup
    4.3 Link prediction
    4.4 Learning to predict new relationships with few examples
  5. Conclusion and future work

论文精读

知识树

OpenKE是清华大学出品的开源库,该库实现了本课中提到的四种算法。

算法模型总览

算法系列图谱

讲解顺序应该是:EHRD

Notation

知识图谱三元组:(h,r/l,t),其中h表示head,t表示tail,r表示关系、l表示label,本节内容中二者等价。
[x]+=max(0,x)[x]_+=max(0,x)[x]+=max(0,x)
看过ReLU就知道啥意思,不解释。
margin-based loss的理解,这个具体在算法中介绍。
n=∣entities∣,m=∣relations∣n=|entities|,m=|relations|n=entitiesm=relations
n是实体数量即节点数量,m是关系数量,即边数量

细节一:TransE模型精讲

原文:
Given a training set SSS of triplets (h,l,t)(h,l, t)(h,l,t) composed of two entities h,t∈Eh, t ∈ Eh,tE (the set of entities) and a relationship l∈Ll ∈ LlL (the set of relationships), our model learns vector embeddings of the entities and the relationships. The embeddings take values in RkR^kRk (kkk is a model hyperparameter) and are denoted with the same letters, in boldface characters. The basic idea behind our model is that the functional relation induced by the lll-labeled edges corresponds to a translation of the embeddings, i.e. we want that h+l≈th + l ≈ th+lt when (h,l,t)(h, l, t)(h,l,t) holds (ttt should be a nearest neighbor of h+lh + lh+l), while h+lh + lh+l should be far away from t otherwise. Following an energy-based framework, the energy of a triplet is equal to d(h+l,t)\text{d}(h + l, t)d(h+l,t) for some dissimilarity measure ddd, which we take to be either the L1L_1L1 or the L2L_2L2-norm.
译文:
给定一个三元组训练集S=(h,l,t)S=(h,l, t)S=(h,l,t),其中h,t∈Eh, t ∈ Eh,tE代表实体集合, l∈Ll ∈ LlL代表关系集合,TransE模型可以学习到实体与关系的向量表示。这些向量均在RkR^kRk的向量空间中,维度kkk为超参数。TransE模型的基本思想是引入向量的translation来表示边,即h+l≈th + l ≈ th+lt,当h和t有关系l的时候,我们希望上式左右两边越接近越好,如果二者没有关系则希望左右两边越远越好。这里的远近使用d(h+l,t)\text{d}(h + l, t)d(h+l,t)来表示,d可以用L1L_1L1 或者 L2L_2L2-norm进行计算。相当于当h和t有关系l的时候,我们希望d=0,反之则d越大越好。
下面给出原文的损失函数:
L=∑(h,l,t)∈S∑(h′,l,t′)∈S(h,l,t)′[γ+d(h+l,t)−d(h′+l,t′)]+L=\sum_{(h,l, t)\in S}\sum_{(h',l, t')\in S'_{(h,l, t)}}[\gamma+\text{d}(h + l, t)-\text{d}(h' + l, t')]_+L=(h,l,t)S(h,l,t)S(h,l,t)[γ+d(h+l,t)d(h+l,t)]+
其中第一个连加代表正样本,第二个连加代表相应的负样本,因此正样本d(h+l,t)\text{d}(h + l, t)d(h+l,t)比负样本d(h′+l,t′)\text{d}(h' + l, t')d(h+l,t)小,那么整个表达式就是负值(不考虑γ\gammaγ)对其做[x]+[x]_+[x]+操作后,[d(h+l,t)−d(h′+l,t′)]+=0[\text{d}(h + l, t)-\text{d}(h' + l, t')]_+=0[d(h+l,t)d(h+l,t)]+=0,此时loss就是最小,因此训练的目标就是要使得正样本的距离相比于负样本的距离小即可。如果考虑γ>0\gamma>0γ>0(一般取值为1、2、10),那么训练的目标就要使得正样本的距离相比于负样本的距离小γ\gammaγγ\gammaγ就相当于一个SVM里面的Margin。
注意:同一个实体,无论其作为head或者作为tail,其embedding表示应该是一致的。
关于负样本(原文叫:corrupted triplet),文中给出的构造方法为,替换正样本中的hhh,换为h′h'h,或者替换正样本中的ttt,换为t′t't,(和word2vec、node2vec的负样本产生思路一致)即可:
S(h,l,t)′={(h′,l,t)∣h′∈E}∪(h,l,t′)∣t′∈E}S'_{(h,l, t)}=\{(h',l, t)|h'\in E\}\cup (h,l, t')|t'\in E\}S(h,l,t)={(h,l,t)hE}(h,l,t)tE}
下面将原文的算法重新表达一遍:
input Training set S={(h,l,t)}S = \{(h, l, t)\}S={(h,l,t)}, entities and rel. sets E and L, margin γ\gammaγ, embeddings dim. kkk.
初始化1-3

  1. lll做均匀分布的初始化:l←(−6k,6k)l\leftarrow(-\cfrac{6}{\sqrt{k}},\cfrac{6}{\sqrt{k}})l(k

    6
    ,k

    6
    )
  2. lll做归一化:l←l∥l∥l\leftarrow\cfrac{l}{\|l\|}lll
  3. 对实体e做均匀分布的初始化:e←(−6k,6k)e\leftarrow(-\cfrac{6}{\sqrt{k}},\cfrac{6}{\sqrt{k}})e(k 6,k

    6
    )
  4. 开始循环
  5. 由于在第12步中e会有更新,因此要重新做归一化:e←e∥e∥e\leftarrow\cfrac{e}{\|e\|}eee
  6. 假设minibatch大小为b,则取b个样本:Sbatch←sample(S,b)S_{batch}\leftarrow sample(S,b)Sbatchsample(S,b)
  7. 初始化TbatchT_{batch}Tbatch,这个才是正常进行训练的集合,里面要加入负样本,下面是一个加负样本的循环
  8. for (h,l,t)∈Sbatchdo\text{for } (h,l,t)\in S_{batch}\text{ do}for(h,l,t)Sbatchdo
  9. (h′,l,t′)←sample(S(h,l,t)′)(h',l,t')\leftarrow sample(S'_{(h,l,t)})(h,l,t)sample(S(h,l,t))//这里采样负样本
  10. 将负样本加入TbatchT_{batch}TbatchTbatch←Tbatch∪{((h,l,t),(h′,l,t′))}T_{batch}\leftarrow T_{batch}\cup\{((h,l,t),(h',l,t'))\}TbatchTbatch{((h,l,t),(h,l,t))}
  11. end for\text{end for}end for
  12. 更新向量表示:w.r.t.
    ∑((h,l,t),(h,l,t))∈Tbatch▽[γ+d(h+l,t)−d(h′+l,t′)]+\sum_{\left ({(h,l, t),(h,l, t)}\right )\in T_{batch}}\bigtriangledown [\gamma+\text{d}(h + l, t)-\text{d}(h' + l, t')]_+((h,l,t),(h,l,t))Tbatch[γ+d(h+l,t)d(h+l,t)]+
  13. 结束循环

负采样的trick

These metrics are indicative but can be flawed when some corrupted triplets end up being valid ones, from the training set for instance. In this case, those may be ranked above the test triplet, but this should not be counted as an error because both triplets are true. To avoid such a misleading behavior, we propose to remove from the list of corrupted triplets all the triplets that appear either in the training, validation or test set (except the test triplet of interest). This ensures that all corrupted triplets do not belong to the data set.
我们划分了训练集、验证集、测试集,在测试集负采样的时候,算法采样了一个它认为是负样本的三元组,这个三元组在测试集中不存在,但是在可能在训练集、验证集中这个三元组作为正样本出现过,这样进行计算结果就会出现偏差,因此算法提出一种filtered的策略,将所有数据集中出现过的正样本不出现在测试集的负样本列表中。在实验过程中也分成两组来分析,一种是使用filter,一种是不使用filter。

TransE模型的不足

这个算法存在的问题在于只能解决节点间关系为1对1的关系,对于下面:
1 to many,many to 1,many to many
的关系无法解决。
在TransH中对TransE模型的不足给出了解释:

1.对于对称有向网络,根据TransE模型的假设,应该有:
h+r−t=0,t+r−h=0h+r-t=0,t+r-h=0h+rt=0,t+rh=0
则可以得如下结论:r=0,h=tr=0,h=tr=0,h=t,意味着h和t两个实体的embedding一样,这样明显不对。
2.对于多对一的关系,多个hih_ihi和t都满足hi+r−t=0h_i+r-t=0hi+rt=0,则意味所有的与t有关系的hih_ihi都相等。反之多个tit_iti和h有关系则意味所有tit_iti都相等。相等意味embedding一样,不同的实体,一样的embedding,这样明显也不合理。

细节二:TransH模型精讲

To overcome the problems of TransE in modeling reflexive/one-to-many/many-to-one/many-to-many relations, we propose a model which enables an entity to have distributed representations when involved in different relations.
解决TransE存在的问题:1to many,many to 1,many to many
主要思路:entity在不同的关系上有不同的embedding
实现方式:不同的关系在hyperplane(超平面)的映射不一样

如下图所示:hhh是实体header在原始坐标系的向量,用黑色箭头表示,用红色虚线表示超平面,上面红色的点是h在超平面上的投影h⊥h_\perph,从线性代数上看h⊥h_\perph实际上就是hhh在超平面上以及超平面法向量wrw_rwr的两个分量,也就是说黑色箭头可以分解为蓝色和粉色箭头(从超平面平移过来),他们三个组成一个三角形,那么就是有:
蓝色向量+粉色向量=黑色向量蓝色向量+粉色向量=黑色向量+=
那么
粉色向量=黑色向量−蓝色向量粉色向量=黑色向量-蓝色向量=
粉色向量就是h⊥h_\perph,黑色向量就是hhh

蓝色向量实际是wr⊤hwrw_r^\top hw_rwrhwr,因为wrw_rwr刚才说了是法向量,而且是单位法向量(∣wr∣=1|w_r|=1wr=1),那么
wr⊤h=∣wr∣∣h∣cosθ=∣h∣cosθw_r^\top h=|w_r||h|cos\theta=|h|cos\thetawrh=wrhcosθ=hcosθ
上面这个公式就是蓝色箭头的长度,这是因为粉色和蓝色是直角关系,蓝色和黑色夹角是θ\thetaθ,然后∣h∣cosθ|h|cos\thetahcosθ再乘上法向量wrw_rwr,就为蓝色长度加上wrw_rwr的方向。所以蓝色向量表示为wr⊤hwrw_r^\top hw_rwrhwr。粉色向量就可以表示为:
h⊥=h−wr⊤hwrh_\perp=h-w_r^\top hw_rh=hwrhwr
对于实体ttt而言,当然相应的就有:
t⊥=t−wr⊤twrt_\perp=t-w_r^\top tw_rt=twrtwr
这里单位法向量wrw_rwr在计算t的时候不变,因为两个实体都是投影到相同的超平面上,因此二者计算过程中使用相同的法向量。
接下来就可以得到TransH算法中衡量三元组距离公式为:
fr(h,t)=∣∣h⊥+dr−t⊥∣∣22=∣∣(h−wr⊤hwr)+dr−(t−wr⊤twr)∣∣22\begin{aligned}f_r(h,t)&=||h_\perp+d_r-t_\perp||_2^2\\ &=||(h-w_r^\top hw_r)+d_r-(t-w_r^\top tw_r)||_2^2\end{aligned}fr(h,t)=h+drt22=(hwrhwr)+dr(twrtwr)22
损失函数为:
L=∑(h,r,t)∈Δ∑(h′,r′,t′)∈Δ(h,r,t)′[fr(h,t)+γ−fr′(h′,t′)]+L=\sum_{(h,r,t)\in\Delta}\sum_{(h',r',t')\in\Delta '_{(h,r,t)}}[f_r(h,t)+\gamma-f_{r'}(h',t')]_+L=(h,r,t)Δ(h,r,t)Δ(h,r,t)[fr(h,t)+γfr(h,t)]+
上式中,γ\gammaγ是margin,fr(h,t)f_r(h,t)fr(h,t)表示正样本(原文叫golden triplet),fr′(h′,t′)f_{r'}(h',t')fr(h,t)代表负样本。损失函数目标就不描述了,和TransE一样。但是由于加了一个超平面,法向量这些东西,因此还有几个额外的约束:
∀e∈E,∣∣e∣∣2≤1,//scale\forall e\in E,||e||_2\leq1,//scaleeE,e21,//scale
∀r∈R,∣wR⊤dr∣∣∣dr∣∣2≤ϵ,//二者正交\forall r\in R,\cfrac{|w_R^\top d_r|}{||d_r||_2}\leq\epsilon,//二者正交rR,dr2wRdrϵ,//
∀r∈R,∣∣wr∣∣2=1,//wr是单位法向量\forall r\in R,||w_r||_2=1,//w_r是单位法向量rR,wr2=1,//wr
带约束的损失函数是不好求的,作者给出了整合了约束条件的损失函数(可以参考数学基础的不等式约束约束优化):
L=∑(h,r,t)∈Δ∑(h′,r′,t′)∈Δ(h,r,t)′[fr(h,t)+γ−fr′(h′,t′)]++C{∑e∈E[∣∣e∣∣22−1]++∑r∈R[(wR⊤dr)2∣∣dr∣∣22−ϵ2]+}L=\sum_{(h,r,t)\in\Delta}\sum_{(h',r',t')\in\Delta '_{(h,r,t)}}[f_r(h,t)+\gamma-f_{r'}(h',t')]_+\\+C\left \{\sum_{e\in E}[||e||_2^2-1]_++\sum_{r\in R}[\cfrac{(w_R^\top d_r)^2}{||d_r||_2^2}-\epsilon^2]_+\right \}L=(h,r,t)Δ(h,r,t)Δ(h,r,t)[fr(h,t)+γfr(h,t)]++C{eE[e221]++rR[dr22(wRdr)2ϵ2]+}
这里还要提一个比较重要的trick:Reducing False Negative Labels
因为这个模型处理多对多的关系,因此原来在TransE的模型中采样负样本的方法有可能采样到正样本,因为原来TransE的模型中采样负样本的方法是固定h或t,然后修改另外一个实体,但是由于存在多对多关系,修改为另外一个实体t′t'th′h'h有可能还是与固定的h或t存在关系,即sample后的样本是正样本。
We tend to give more chance to replacing the head entity if the relation is one-to-many and give more chance to replacing the tail entity if the relation is many-to-one.
对于一对多或者多对一情况,那就只sample一的那一方。
论文中使用了tphtphtphhpthpthpt来表达实体间关系,tphtphtph表示the average number of tail entities per head entity;hpthpthpt表示the average number of head entities per tail entity。tph>1tph>1tph>1,代表一个head对应多个tail,同理hpt>1hpt>1hpt>1,代表一个tail对应多个head。然后替换(sample)h或者t的概率就可以这样(分母表示归一化):
tphtphtph越大替换head,替换概率为:tphtph+hpt\cfrac{tph}{tph+hpt}tph+hpttph
hpthpthpt越大替换tail,替换概率为:hpttph+hpt\cfrac{hpt}{tph+hpt}tph+hpthpt

细节三:TransR模型精讲

解决TransE/TransH存在的问题:relation与entity由于是不同类型的点,可能存在于不同的空间。映射到超平面仍然是在相同空间中。
Both TransE and TransH assume embeddings of entities and relations being in the same space RkR^kRk. But relations and entities are completely different objects, it may be not capable to represent them in a common semantic space.
主要思路:将entity映射到relation的空间上

实现方式:矩阵(matrix)的映射MrM_rMr(projection matrix)

上图是论文原图,我在relation空间中映射后的hrh_rhrtrt_rtr添加了蓝线和绿线,就相当于在右边的空间中做TransE。
明白了TransR模型思路后,可以知道映射到relation空间上的h和t可以表示为:
hr=hMr,tr=tMrh_r=hM_r,t_r=tM_rhr=hMr,tr=tMr
在relation空间上,计算距离的公式为:
fr(h,t)=∣∣hr+r−tr∣∣22f_r(h,t)=||h_r+r-t_r||_2^2fr(h,t)=hr+rtr22
损失函数就可以写出来(和TransE的一样样的):
L=∑(h,r,t)∈S∑(h′,r,t′)∈S′[fr(h,t)+γ−fr(h′,t′)]+L=\sum_{(h,r,t)\in S}\sum_{(h',r,t')\in S '}[f_r(h,t)+\gamma-f_{r}(h',t')]_+L=(h,r,t)S(h,r,t)S[fr(h,t)+γfr(h,t)]+
进一步还可以对TransR的关系进行聚类得到CTransR( cluster-based TransR )

CTransR

For example, the head-tail entities of the relation “location location contains” have many patterns such as country-city, country-university, continent-country and so on. Following the idea of piecewise linear regression (Ritzema and others 1994), we extend TransR by clustering diverse head-tail entity pairs into groups and learning distinct relation vectors for each group, named as cluster-based TransR (CTransR).
原文中提到的例子:国家-城市、国家-大学、洲-国家,这些实体之间的关系都是:地点-地点-包含关系。那么既然关系是可以分类的,那么论文中就用h-t来计算r,然后将r进行聚类,得到CTransR。
All entity pairs (h,t)(h, t)(h,t) are represented with their vector offsets (h−t)(h − t)(ht) for clustering, where hhh and ttt are obtained with TransE. Afterwards, we learn a separate relation vector rcr_crc for each cluster and matrix MrM_rMr for each relation, respectively. We define the projected vectors of entities as hr,c=hMrh_{r,c} = hM_rhr,c=hMr and tr,c=tMrt_{r,c} = tM_rtr,c=tMr, and the score function is defined as:
fr(h,t)=∣∣hr,c+rc−tr,c∣∣22+α∣∣rc−r∣∣22f_r(h,t)=||h_{r,c}+r_c-t_{r,c}||_2^2+\alpha||r_c-r||_2^2fr(h,t)=hr,c+rctr,c22+αrcr22

这里先用TransE训练得到实体embedding表示hhhttt,然后用聚类算法(kNN什么的都可以)对关系进行聚类得到rcr_crc,这里要注意,无论有多少类rcr_crc,投影矩阵MrM_rMr只有一个。上式中后面一项相当于一个正则,用来保证聚类后的关系rcr_crc和原来的关系rrr距离越小越好。
损失函数和TransR的一模一样,不写了。
负样本构造方法和TransH一样。
trick: To avoid overfitting, we initialize entity and relation embeddings with results of TransE, and initialize relation matrices as identity matrices

细节四:TransD模型精讲

解决TransR存在的问题:

  1. 同一个relation对应的eritity是同样的映射;
    (1) For a typical relation rrr, all entities share the same mapping matrix MrM_rMr. However, the entities linked by a relation always contains various types and attributes. For example, in triplet (friedrich burklein, nationality, germany), friedrich burklein and germany are typical different types of entities. These entities should be projected in different ways;
    这里原文给了一个例子,就是对于(人名,国籍,国名)这样的三元组,可以看到人名和国名是两个非常不一样的实体,因此适合映射到不同的空间中。
  2. 映射只由relation决定;
    (2) The projection operation is an interactive process between an entity and a relation, it is unreasonable that the mapping matrices are determined only by relations;
  3. matrix-vector的操作计算复杂度大。
    (3) Matrix-vector multiplication makes it has large amount of calculation, and when relation number is large, it also has much more parameters than TransE and TransH. As the complexity, TransR/C TransR is difficult to apply on largescale knowledge graphs.

主要思路:将MrM_rMr用projection vector替代,使得映射由实体和关系共同决定。
In TransD, we define two vectors for each entity and relation. The first vector represents the meaning of an entity or a relation, the other one (called projection vector) represents the way that how to project a entity embedding into a relation vector space and it will be used to construct mapping matrices. Therefore, every entity-relation pair has an unique mapping matrix.
优点:TransD has less parameters and has no matrix-vector multiplication operations, which makes it can be applied on large scale graphs.

TransD模型的映射矩阵为:
Mrh=rphp⊤+Im×nM_{rh}=r_ph_p^\top+I^{m\times n}Mrh=rphp+Im×n
Mrt=rptp⊤+Im×nM_{rt}=r_pt_p^\top+I^{m\times n}Mrt=rptp+Im×n
rpr_prp是列向量,hp,tph_p,t_php,tp也是列向量,然后hp⊤,tp⊤h_p^\top,t_p^\tophp,tp变成了行向量,列向量乘行向量变成了矩阵,这样的好处就是参数量大大减少了,原来矩阵参数m×nm\times nm×n,变成相乘的构造方式后就为:m+nm+nm+n
下面操作就和TransR一样了,用新定义的映射矩阵替换TransR中的MrM_rMr即可,因此映射操作为:
h⊥=Mrhh,t⊥=Mrtth_\perp=M_{rh}h,t_\perp=M_{rt}th=Mrhh,t=Mrtt
距离计算:
fr(h,t)=−∣∣h⊥+r−t⊥∣∣22f_r(h,t)=-||h_\perp+r-t_\perp||_2^2fr(h,t)=h+rt22
损失函数:
L=∑ε∈Δ∑ε′∈Δ′[γ+fr(ε′)−fr(ε)]+L=\sum_{\varepsilon \in\Delta}\sum_{\varepsilon' \in\Delta'}[\gamma+f_r(\varepsilon')-f_r(\varepsilon)]_+L=εΔεΔ[γ+fr(ε)fr(ε)]+

细节五:模型对比与总结

下面把四种方法的异同放到一块来看:

Method 实体表征 关系表征 距离函数fr(h,t)f_r(h,t)fr(h,t) 约束条件/正则
TransE h,t都是d维 r是d维 −∥h+r−t∥1/2-\|h+r-t\|_{1/2}h+rt1/2 ∥h∥2=1,∥t∥2=1\|h\|_2=1,\|t\|_2=1h2=1,t2=1
TransH h,t都是d维 r,wrw_rwr是d维 −∥(h−wr⊤hwr)+r−(t−wr⊤twr)∥22-\|(h-w^{\top}_r hw_r)+r-(t-w_r^{\top} tw_r)\|_2^2(hwrhwr)+r(twrtwr)22 ∥h∥2≤1,∥t∥2≤1\|h\|_2\leq1,\|t\|_2\leq1h21,t21
∣wr⊤r∣/∥r∥2≤ϵ\begin{vmatrix}w^{\top}_rr\end{vmatrix}/\|r\|_2\leq\epsilonwrr/r2ϵ
∥wr∥2=1\|w_r\|_2=1wr2=1
TransR h,t都是d维 r是k维,MrM_rMr是k×d维 ∥Mrh+r−Mrt∥22\|M_rh+r-M_rt\|_2^2Mrh+rMrt22 ∥h∥2≤1,∥t∥2≤1\|h\|_2\leq1,\|t\|_2\leq1h21,t21
∥r∥2≤1\|r\|_2\leq1r21
∥Mrh∥2≤1\|M_rh\|_2\leq1Mrh21
∥Mrt∥2≤1\|M_rt\|_2\leq1Mrt21
TransD h,t,wh,wtw_h,w_twh,wt都是d维 r,wrw_rwr是k维 −∥(wrwh⊤+I)h+r−(wrwt⊤+I)t∥22-\|(w_rw_h^{\top}+I)h+r-(w_rw_t^{\top}+I)t\|_2^2(wrwh+I)h+r(wrwt+I)t22 ∥h∥2≤1,∥t∥2≤1,∥r∥2≤1\|h\|_2\leq1,\|t\|_2\leq1,\|r\|_2\leq1h21,t21,r21
∥(wrwh⊤+I)h∥2≤1\|(w_rw_h^{\top}+I)h\|_2\leq1(wrwh+I)h21
∥(wrwt⊤+I)t∥2≤1\|(w_rw_t^{\top}+I)t\|_2\leq1(wrwt+I)t21

TransE 的损失函数中的1/2表示可以用L1也可以用L2loss(根据数据集用grid search)。
下面看下时间复杂度:

算法 frf_rfr空间复杂度(参数量) 整体时间复杂度
TransE O(Ned+Nrd)O(N_ed+N_rd)O(Ned+Nrd) O(Nt)O(N_t)O(Nt)
TransH O(Ned+2Nrd)O(N_ed+2N_rd)O(Ned+2Nrd) O(2dNt)O(2dN_t)O(2dNt)
TransR O(Ned+Nrdk+Nrk)O(N_ed+N_rdk+N_rk)O(Ned+Nrdk+Nrk) O(2dkNt)O(2dkN_t)O(2dkNt)
CTransR O(Ned+Nrdk+Nrck)O(N_ed+N_rdk+N_rck)O(Ned+Nrdk+Nrck) O(2dkNt)O(2dkN_t)O(2dkNt)
TransD O(2Ned+2Nrk)O(2N_ed+2N_rk)O(2Ned+2Nrk) O(2kNt)O(2kN_t)O(2kNt)

空间复杂度中,NeN_eNe表示节点数量,NrN_rNr表示边数量,d和k分布对应节点和边的维度,c是边聚类后的类别数量。
时间复杂度中,NtN_tNt表示三元组的个数。TransE中,本来单个frf_rfr的时间复杂度为O(d)O(d)O(d)(由于向量维度为d),但是这里不考虑维度,把这个复杂度视为O(1)O(1)O(1);TransH 中wr⊤hwrw^{\top}_r hw_rwrhwr时间复杂度为O(d)O(d)O(d);TransR中MrhM_rhMrh时间复杂度为O(d×k)O(d\times k)O(d×k);TransD要看原文公式18.19.,其复杂度是O(k)O(k)O(k)
TransR/CTransR 的空间/时间复杂度最高。

实验设置和结果分析

数据集

数据集有两个,一个是Wordnet,比较小,里面是词以及词的语法树作为关系。另外一个数据集是Freebase,这个数据集目前还在不断增加,论文发表时已有1.2亿个三元组,8千万个实体。由于该数据太大,作者对这个数据集进行了sample,这里要注意sample的方法,类似社交网络比较sparse的网络,如果随机sample就很容易出现非连通图,因此文中的sample方法也值得注意:
1.先从Freebase中选择实体,这些实体都要在Wikilinks数据集存在,且实体和关系要在Freebase出现频率大于100次,估计这个Wikilinks是一个更小的图数据集,且实体都比较真实,因此可保障不会出现孤立的节点;
2.将互为reverses的关系去掉,例如:’!/people/person/nationality’与’/people/person/nationality’,得到FB15k数据集。
3.将Freebase中实体出现频率前1亿排名的选出来,得到FB1M数据集。

Mean rank metric

TransE使用参考文献【3】的Mean rank metric,即:Learning Structured Embeddings of Knowledge Bases,原文:
We first assess the quality of our representations using the following ranking task: for all training and testing triplets (el.r,er)(e^l.r, e^r)(el.r,er),(1) we remove ele^lel,(2) we compute densities fkde((e,r,er))f_{kde}((e,r, e^r))fkde((e,r,er)) for all e∈Dee \in D_eeDe,(3) we sort values by decreasing order, and (4) we record the rank of the correct entity ele^lel. An identical process is repeated for predicting ere^rer. This setting somewhat corresponds to question answering.
对于三元组(el.r,er)(e^l.r, e^r)(el.r,er),将原来的ele^lel(就是head)去掉,然后用函数 fkde((e,r,er))f_{kde}((e,r, e^r))fkde((e,r,er))在所有的实体中算分数,然后排序,然后看原来ele^lel在排序中的次序,然后计分,越靠前分数越高。同样的方法可以计算tail:ere^rer

参数规模

可以看到,TransE的参数有两部分组成,一部分是和实体的个数和维度有关,一部分是和关系的数量和维度有关,由于Unstructured忽略关系实体,因此只有实体个数和维度一项。总体而言:TransE的参数规模(空间复杂度)是很有优势的。

超参数设置

For experiments with TransE, we selected the learning rate λλλ for the stochastic gradient descent (梯度下降方法SGD)among {0.001, 0.01, 0.1}(学习率有三种), the margin γγγ among {1, 2, 10} and the latent dimension kkk among {20, 50} on the validation set of each data set. The dissimilarity measure ddd was set either to the L1L_1L1 or L2L_2L2 distance according to validation performance as well. Optimal configurations were(最优配置应该是grid search出来的): k=20,λ=0.01,γ=2k = 20, λ = 0.01, γ = 2k=20,λ=0.01,γ=2, and d=L1d = L_1d=L1 on Wordnet; k=50,λ=0.01,γ=1k = 50, λ = 0.01, γ = 1k=50,λ=0.01,γ=1, and d=L1d = L_1d=L1 on FB15k; k=50,λ=0.01,γ=1,k = 50, λ = 0.01, γ = 1,k=50,λ=0.01,γ=1, and d=L2d = L_2d=L2 on FB1M. For all data sets, training time was limited to at most 1, 000 epochs over the training set. The best models were selected by early stopping(早停trick) using the mean predicted ranks on the validation sets (raw setting). An open-source implementation of TransE is available from the project webpage(已失效).

Link prediction

下面是实验结果,可以看到有三个数据集,每个数据集有两种衡量方法,一个是Mean rank,一个是HITS@10%,前者是希望真实值在预测排序列表中越靠前越好,所以是值越小越好;后者是预测排序中的命中百分比,因此是值越大越好。每种衡量方法又分原始方式和使用filtered的方式。下表中带【-】的意味着该模型无法训练这么大的数据量,也证明了TransE就像其摘要中说的一样,可以在大的数据集也可以适用。

多种关系的三元组的效果统计

这里的多种关系就是结点之间的1对1,1对多,多对1,多对多的关系。在对TransE模型进行精讲的时候就提过这个模型除了1对1的关系处理比较好外,其他关系是有点缺点的。这里只比较HITS@10%在FB15k上的效果(带filtered的trick)。可以看到,下面预测X对Y的关系时候(X是被预测的那个),如果X是多,那么效果就比较差(可以看到下面第三列效果较差),如果X是1,那么效果就比较好。

We obtained that FB15k has 26.2% of 1-TO-1 relationships, 22.7% of 1-TO-MANY, 28.3% of MANY-TO-1, and 22.8% of MANY-TO-MANY. 1对1的数据不多,因此对模型改进很有必要。

模型inference示例

输入head和relation,预测tail,下表中黑体是测试集中的数据,斜体是出现过在训练集中的数据。

例如,Lil Wayne这个实体,关系是born in ,预测结果是:New Orleans。

新关系预测

Learning to predict new relationships with few examples
这里Unstructed算法不考虑关系,这里预测关系中这个算法得到关系值就是0,是一个常数,所以这里是一条蓝色横线,然后左边是mean rank右边是 hits@10,随着数据量增加可以看到一个是下降,一个上升,都符合规律,但是可以看到TransE算法在10个点左右就基本得到一个比较好的结果了。

To that end, we randomly selected 40 relationships and split the data into two sets: a set (named FB15k-40rel) containing all triplets with these 40 relationships and another set (FB15k-rest) containing the rest. We made sure that both sets contained all entities. FB15k-rest has then been split into a training set of 353,788 triplets and a validation set of 53,266, and FB15k-40rel into a training set of 40,000 triplets (1,000 for each relationship) and a test set of 45,159.
这里只考虑新边(关系)不考虑新点(实体),做法是:随机选40条边,然后做两个数据集,一个数据集没有这40条边(旧时间点),一个数据集有这40条边(新时间点)。两个数据集都包含所有的entities(节点),不涉及新点的问题。旧时间点的数据集分成训练集和验证集,新时间点的数据集分成训练集和验证集。
Using these data sets, we conducted the following experiment: (1) models were trained and selected using FB15k-rest training and validation sets, (2) they were subsequently trained on the training set FB15k-40rel but only to learn the parameters related to the fresh 40 relationships, (3) they were evaluated in link prediction on the test set of FB15k-40rel (containing only relationships unseen during phase (1)). We repeated this procedure while using 0, 10, 100 and 1000 examples of each relationship in phase (2).
具体训练步骤如下:
1.在旧时间点的数据集上训练,得到所有点和边的embedding,更新模型参数;
2.将新时间点的数据集的训练集丢入步骤1的模型继续训练,更新模型参数;
3.将新时间点的数据集的测试集丢入步骤2的模型进行测试,记录的边的预测效果。
在步骤2中分别为边加入0,10,100,1000个三元组进行比较,得到上面的图。

论文总结

关键点
·知识图谱的理解
·三元组的表示方式
·负样本的构建(transH用的trick)
·损失函数的理解
·参数/时间复杂度分析
创新点
·transE基础模型
·transH开始解决一对多等问题
·transR和transD不同空间的映射
·transD映射矩阵由向量表示
·丰富的实验论证效果
启发点
·知识图谱中实体和关系的向量化表达
·transE、transH、transR、transD是如何发展的,什么样的motivation
·负样本构建、损失函数统一的框架
·trans系列模型的对比和总结
·Parameter space(参数空间)的理解
·参数空间复杂度分析、时间复杂度分析

复现

主要看TransE的代码,其他算法的在开源库也有,原理也一样,例如:负采样,margin based的损失函数等。

·Python 3.7
·torch 1.3.1
·numpy 1.18.1
·jupyter notebook
OpenKE-PyTorch
example目录下的

OpenKE\module\model下

开源库的安装(来源于官网):

数据集在benchmarks目录下面:

目录下面有各种关系的三元组:

对于训练和测试数据的说明(来自官网)

读取数据的py文件在data目录下:

负采样的py文件在:OpenKE\module\strategy
损失函数的py文件在:OpenKE\module\loss

训练和测试py在config文件夹下:

开源库的安装

官网的安装是linux环境的,windows环境参考这里:
https://blog.csdn.net/qq_38970189/article/details/109188376
https://blog.csdn.net/wangdong1106/article/details/109597447 (新版)
编译器下载要注意下载安装版,不要下载解压版
https://sourceforge.net/projects/mingw-w64/files/

在线安装有点慢。

base目录下的文件:
所有导出函数(不只是base.cpp,还有其它.h文件)都需要把extern "C"修改为extern “C” __declspec(dllexport)
setting.h中 #define INT long 修改为 typedef int INT; (最后有分号)。类似地修改 #define REAL float 为 typedef double REAL;
corrupt.h和test.h中添加一句 #include “iso646.h”
base.cpp的getBatch函数最后,添加一行return ((void*)0);

直接用MinGW编译dll报错。。。编译为.o没问题,先留坑。

TransE主要代码

主程序: train_transe_FB15K237

import openke
from openke.config import Trainer, Tester #训练与测试
from openke.module.model import TransE # 模型
from openke.module.loss import MarginLoss # 损失函数
from openke.module.strategy import NegativeSampling # 负采样
from openke.data import TrainDataLoader, TestDataLoader # 数据读取# 依赖的C++文件地址:
# https://github.com/thunlp/OpenKE/blob/OpenKE-PyTorch/openke/base/Base.cpp# dataloader for training
# torch.utils.data.DataLoader是torch中用来包装数据的工具,可以有效地迭代数据将自定义的Dataset根据batch
# size大小、是否shuffle等封装成一个Batch Size大小的Tensor,用于后面的训练
# 两个对torch的dataloader写得比较清楚的文章: https://blog.csdn.net/He3he3he/article/details/105441083
# https://zhuanlan.zhihu.com/p/30934236
# 加载训练数据集
train_dataloader = TrainDataLoader(# 数据集路径in_path = "./benchmarks/FB15K237_tiny/",# 每次训练100组三元组nbatches = 100,# CPU或者GPU的数量threads = 8,# 负采样模式sampling_mode = "normal",# TransH的负采样trick,根据概率来替换实体bern_flag = 1,# TransE中提到的负采样trick,是否使用filtered进行处理,保证负样本从未在测试或验证集中以正样本形式出现过。filter_flag = 1,# 使用替换实体方式生成的负样本数量neg_ent = 25,# 使用替换关系方式生成的负样本数量neg_rel = 0)# dataloader for test
# 加载测试数据集
test_dataloader = TestDataLoader("./benchmarks/FB15K237_tiny/", "link")# define the model
transe = TransE(# 实体数量/size,记为eent_tot = train_dataloader.get_ent_tot(),# 关系数量/size,记为rrel_tot = train_dataloader.get_rel_tot(),# 最后的表征维度,记为ddim = 200,# scoring function计算距离使用L1 norm,也可以用L2p_norm = 1, norm_flag = True)# define the loss function
model = NegativeSampling(model = transe, # 设置transe模型loss = MarginLoss(margin = 5.0), #设置margin,对应原文损失函数中的gammabatch_size = train_dataloader.get_batch_size()# 100
)# train the model
#开始模型训练,这里面的model是Negativesampling,class NegativesSampling里面定义了TransE model
#显卡支持则use_gpu设置为true,train_times应该设置为1000才正常,演示用5速度快
trainer = Trainer(model = model, data_loader = train_dataloader, train_times = 5, alpha = 1.0, use_gpu = False)
trainer.run()
transe.save_checkpoint('./checkpoint/transe.ckpt')# test the model
transe.load_checkpoint('./checkpoint/transe.ckpt')
tester = Tester(model = transe, data_loader = test_dataloader, use_gpu = False)
tester.run_link_prediction(type_constrain = False)

Trainer

# coding:utf-8
import torch
import torch.nn as nn
from torch.autograd import Variable
import torch.optim as optim
import os
import time
import sys
import datetime
import ctypes
import json
import numpy as np
import copy
from tqdm import tqdmclass Trainer(object):def __init__(self, model = None,data_loader = None,train_times = 1000,alpha = 0.5,use_gpu = True,opt_method = "sgd",save_steps = None,checkpoint_dir = None):self.work_threads = 8self.train_times = train_times# 默认使用SGDself.opt_method = opt_methodself.optimizer = None# 学习率衰减self.lr_decay = 0# 避免过拟合self.weight_decay = 0self.alpha = alphaself.model = modelself.data_loader = data_loaderself.use_gpu = use_gpuself.save_steps = save_stepsself.checkpoint_dir = checkpoint_dirdef train_one_step(self, data):self.optimizer.zero_grad()# 前向计算loss值,这里面的model是Negativesampling中定义的loss = self.model({'batch_h': self.to_var(data['batch_h'], self.use_gpu),'batch_t': self.to_var(data['batch_t'], self.use_gpu),'batch_r': self.to_var(data['batch_r'], self.use_gpu),'batch_y': self.to_var(data['batch_y'], self.use_gpu),'mode': data['mode']})# 反向更新参数loss.backward()self.optimizer.step()         return loss.item()def run(self):# 判断是否使用gpu还是cpuif self.use_gpu:self.model.cuda()# 定义优化器,有Adagrad、Adadelta、Adam等if self.optimizer != None:passelif self.opt_method == "Adagrad" or self.opt_method == "adagrad":self.optimizer = optim.Adagrad(self.model.parameters(),lr=self.alpha,lr_decay=self.lr_decay,weight_decay=self.weight_decay,)elif self.opt_method == "Adadelta" or self.opt_method == "adadelta":self.optimizer = optim.Adadelta(self.model.parameters(),lr=self.alpha,weight_decay=self.weight_decay,)elif self.opt_method == "Adam" or self.opt_method == "adam":self.optimizer = optim.Adam(self.model.parameters(),lr=self.alpha,weight_decay=self.weight_decay,)else:self.optimizer = optim.SGD(self.model.parameters(),lr = self.alpha,weight_decay=self.weight_decay,)print("Finish initializing...")training_range = tqdm(range(self.train_times))for epoch in training_range:res = 0.0# data loader是TrainDataLoader class ,里面存了训练集for data in self.data_loader:loss = self.train_one_step(data)res += losstraining_range.set_description("Epoch %d | loss: %f" % (epoch, res))if self.save_steps and self.checkpoint_dir and (epoch + 1) % self.save_steps == 0:print("Epoch %d has finished, saving..." % (epoch))self.model.save_checkpoint(os.path.join(self.checkpoint_dir + "-" + str(epoch) + ".ckpt"))#保存参数def set_model(self, model):self.model = modeldef to_var(self, x, use_gpu):if use_gpu:return Variable(torch.from_numpy(x).cuda())else:return Variable(torch.from_numpy(x))def set_use_gpu(self, use_gpu):self.use_gpu = use_gpudef set_alpha(self, alpha):self.alpha = alphadef set_lr_decay(self, lr_decay):self.lr_decay = lr_decaydef set_weight_decay(self, weight_decay):self.weight_decay = weight_decaydef set_opt_method(self, opt_method):self.opt_method = opt_methoddef set_train_times(self, train_times):self.train_times = train_timesdef set_save_steps(self, save_steps, checkpoint_dir = None):self.save_steps = save_stepsif not self.checkpoint_dir:self.set_checkpoint_dir(checkpoint_dir)def set_checkpoint_dir(self, checkpoint_dir):self.checkpoint_dir = checkpoint_dir

NegativeSampling

from .Strategy import Strategyclass NegativeSampling(Strategy):def __init__(self, model = None, loss = None, batch_size = 256, regul_rate = 0.0, l3_regul_rate = 0.0):super(NegativeSampling, self).__init__()self.model = modelself.loss = lossself.batch_size = batch_size# 默认为0,即不加正则化项self.regul_rate = regul_rateself.l3_regul_rate = l3_regul_rate# 在base.cpp中实现的score存储# https://github.com/thunlp/OpenKE/blob/OpenKE-PyTorch/openke/base/Base.cpp# getBatch函数中for (INT batch = lef; batch < rig; batch++)开始。# score是放在一维数组中的,存的顺序是[i,i+batch,i+2*batch,...]# 就是第一个batch位置是正样本([:batch_size]),后面的都是负样本([batch_size:])# 例如,batch_size为200,负样本数量是25,那么在score数组中,1-200是正样本,201-400是第一批负样本,401-600是第二批负样本# 以此类推,共有25批负样本,第一个正样本是1,其对应的负样本就是201,401,601...以此类推。# 当然每个样本是一个三元组,里面有两个实体和一个关系,因此,每个样本里面是3个分数。# 假设正样本用[i,j,k]表示,负样本size=4,用i1,i2,i3,i4,j1,j2,j3,j4,k1,k2,k3,k4表示,batch_size取3# 那么score数组为:(i,j,k,i1,j1,k1,i2,j2,k2,i3,j3,k3,i4,j4,k4)def _get_positive_score(self, score):positive_score = score[:self.batch_size]# 取score数组的1-batch_size位的元素,就是取出正样本(只有一个),按上例是[i,j,k]positive_score = positive_score.view(-1, self.batch_size).permute(1, 0)# permute进行转置,转置后是batch_size*1return positive_scoredef _get_negative_score(self, score):negative_score = score[self.batch_size:]# 取score数组的batch_size+1到最后一位的元素,就是取出所有负样本集合# 先按batch_size叠成矩阵(batch_size*3),接上面的例子:# [i1,j1,k1#  i2,j2,k2#  i3,j3,k3#  i4,j4,k4]# 然后再转置,得到batch_size*4,即batch_size*负样本数量negative_score = negative_score.view(-1, self.batch_size).permute(1, 0)return negative_scoredef forward(self, data):# 调用相应模型计算forward结果score = self.model(data)# 正样本分数p_score = self._get_positive_score(score)# 负样本分数n_score = self._get_negative_score(score)# 按原文公式计算损失值,是一个scalarloss_res = self.loss(p_score, n_score)# 加正则化项,具体正则化函数在TransE.py中if self.regul_rate != 0:loss_res += self.regul_rate * self.model.regularization(data)if self.l3_regul_rate != 0:loss_res += self.l3_regul_rate * self.model.l3_regularization()return loss_res

MarginLoss

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
import numpy as np
from .Loss import Lossclass MarginLoss(Loss):def __init__(self, adv_temperature = None, margin = 6.0):super(MarginLoss, self).__init__()# margin是超参数,不参与反向传播求导self.margin = nn.Parameter(torch.Tensor([margin]))self.margin.requires_grad = Falseif adv_temperature != None:self.adv_temperature = nn.Parameter(torch.Tensor([adv_temperature]))self.adv_temperature.requires_grad = Falseself.adv_flag = Trueelse:self.adv_flag = Falsedef get_weights(self, n_score):return F.softmax(-n_score * self.adv_temperature, dim = -1).detach()def forward(self, p_score, n_score):if self.adv_flag:return (self.get_weights(n_score) * torch.max(p_score - n_score, -self.margin)).sum(dim = -1).mean() + self.marginelse:# 对应论文中的loss function,原文公式1# 这里pscore size[batch,1],n_score[batch,negative sampling size];# 这里用了广播机制,因为第二个维度正样本是1,负样本是negative sampling size,要按列进行复制后计算,最后用mean取平均# 期望pscore<n_score# if pscore-n_score <=-self.margin,正负样本之差即足够小,至少要比margin小;loss=-self.margin+self.margin =0=>与公式一致# if pscore-n_score>-self.margin,正负样本之差比margin大;loss=p_score-n_score+self.margin>0=>与公式一致return (torch.max(p_score - n_score, -self.margin)).mean() + self.margindef predict(self, p_score, n_score):score = self.forward(p_score, n_score)return score.cpu().data.numpy()

TransE

import torch
import torch.nn as nn
import torch.nn.functional as F
from .Model import Modelclass TransE(Model):def __init__(self, ent_tot, rel_tot, dim = 100, p_norm = 1, norm_flag = True, margin = None, epsilon = None):super(TransE, self).__init__(ent_tot, rel_tot)# 表征维度默认100,调用使用200self.dim = dim# 初始化为Noneself.margin = margin# 初始化为Noneself.epsilon = epsilon# 默认使用L1self.norm_flag = norm_flagself.p_norm = p_norm# 最后实体embedding矩阵,大小为e*dself.ent_embeddings = nn.Embedding(self.ent_tot, self.dim)# 最后关系embedding矩阵,大小为r*dself.rel_embeddings = nn.Embedding(self.rel_tot, self.dim)# 默认使用xavier_uniform 初始化embedding矩阵,否则使用其他方式初始化embedding矩阵if margin == None or epsilon == None:nn.init.xavier_uniform_(self.ent_embeddings.weight.data)nn.init.xavier_uniform_(self.rel_embeddings.weight.data)else:self.embedding_range = nn.Parameter(torch.Tensor([(self.margin + self.epsilon) / self.dim]), requires_grad=False)nn.init.uniform_(tensor = self.ent_embeddings.weight.data, a = -self.embedding_range.item(), b = self.embedding_range.item())nn.init.uniform_(tensor = self.rel_embeddings.weight.data, a= -self.embedding_range.item(), b= self.embedding_range.item())if margin != None:self.margin = nn.Parameter(torch.Tensor([margin]))self.margin.requires_grad = Falseself.margin_flag = Trueelse:self.margin_flag = Falsedef _calc(self, h, t, r, mode):if self.norm_flag:# 按行去做L2的归一化,每一行是一个node的embedding vectorh = F.normalize(h, 2, -1)r = F.normalize(r, 2, -1)t = F.normalize(t, 2, -1)if mode != 'normal':h = h.view(-1, r.shape[0], h.shape[-1])t = t.view(-1, r.shape[0], t.shape[-1])r = r.view(-1, r.shape[0], r.shape[-1])# 计算scoring function:/h+r-t/_L1/L2if mode == 'head_batch':score = h + (r - t)else:score = (h + r) - t# 计算p-norm;flatten()将矩阵铺平score = torch.norm(score, self.p_norm, -1).flatten()return scoredef forward(self, data):batch_h = data['batch_h']#要处理的head的index集合,是一个数组batch_t = data['batch_t']#同上batch_r = data['batch_r']#同上mode = data['mode']# 得到index对应的矩阵:embedding矩阵# entities实体:head,tail;relation:关系h = self.ent_embeddings(batch_h)t = self.ent_embeddings(batch_t)r = self.rel_embeddings(batch_r)score = self._calc(h ,t, r, mode)if self.margin_flag:return self.margin - scoreelse:return scoredef regularization(self, data):batch_h = data['batch_h']batch_t = data['batch_t']batch_r = data['batch_r']h = self.ent_embeddings(batch_h)t = self.ent_embeddings(batch_t)r = self.rel_embeddings(batch_r)regul = (torch.mean(h ** 2) + torch.mean(t ** 2) + torch.mean(r ** 2)) / 3return reguldef predict(self, data):score = self.forward(data)if self.margin_flag:score = self.margin - scorereturn score.cpu().data.numpy()else:return score.cpu().data.numpy()

作业

【思考题】回顾scoring function的写法与论文中公式的对应。
【思考题】总结Trans系列算法的通用框架,如negative sampling相似的构建方式以及相似的loss function。
【代码实践】尝试为算法设置不同的参数,比如margin值、scoring function取L1/L2 norm的不同设置对模型效果的影响。
【代码实践】在OpenKE/examples/文件夹下面运行不同的Trans系列算法,比较不同算法的效果。
【总结】总结TransE、TransH、TransR、TransD的关键技术以及如何代码实现,结合代码验证算法的思想以及参数个数。

深度之眼Paper带读笔记GNN.05.TransE/H/R/D相关推荐

  1. GNN手写字体识别java_深度之眼Paper带读笔记GNN.09.GGNN

    文章目录 前言 本课程来自深度之眼,部分截图来自课程视频. 文章标题:Gated Graph Sequence Neural Networks 门控序列图神经网络(GGNN) 作者:Yujia Li∗ ...

  2. 深度之眼Paper带读笔记GNN.06.GAT

    文章目录 前言 导读 论文结构 学习目标 研究背景 图卷积 Notation 归纳式学习 空域与频域卷积 GAT模型多头注意力机制 意义 泛读 摘要 论文结构 精读 算法模型总览 GNN的结构 GAT ...

  3. 深度之眼Paper带读笔记GNN.09.GGNN

    文章目录 前言 论文结构 学习目标 泛读 研究背景 研究意义 摘要 章节 精读 细节一:GRU模型回顾 细节二:GGNN模型 Propagation Model output model 模型框架 G ...

  4. 深度之眼Paper带读笔记GNN.02.LINE

    文章目录 前言 论文结构 研究背景 应用 基本概念 基础知识补充 多类数据集 研究意义 泛读 摘要 论文标题 算法的比较 LINE算法详解 KL散度 交叉熵 细节一:1阶相似度推导 细节二:2阶相似度 ...

  5. 深度之眼Paper带读笔记目录

    文章目录 简介 图神经网络(已完结) NLP精读论文目录(已完结) NLP Baseline(已完结) CV目录(已太监) 简介 本次的Paper学习营分CV和NLP两个方向,每个方向又分精读.重点阅 ...

  6. 深度之眼Paper带读笔记NLP.2:word2vec.baseline.1

    文章目录 前言 论文储备知识 语言模型 基于专家语法规则的语言模型 统计语言模型 统计语言模型中的平滑操作 基于马尔科夫假设 语言模型评价指标:困惑度(Perplexity) 论文背景知识 词的表示方 ...

  7. 深度之眼Paper带读笔记NLP.5:transformer

    文章目录 前言 第一课:论文导读 序列模型简介 序列问题 序列模型 多到多的序列转换模型Sequence To Sequence Models 带有注意力的循环神经网络RNNs With Attent ...

  8. 深度之眼Paper带读笔记1:Deep learning

    文章目录 前言 作者介绍 论文意义和主要内容 基础知识 论文结构 1引言 DL的应用领域 2监督学习Supervised learning 3反向传播算法BP 4卷积神经网络CNN 5基于深度卷积神经 ...

  9. 深度之眼Paper带读笔记NLP.22:双向Attention

    文章目录 前言 第一课 论文导读 阅读理解简介 多种阅读理解任务 人工合成问答 完形填空 选择题 前期知识储备 第二课 论文精读 论文整体框架 对比模型 注意力机制 Match-LSTM(一种阅读理解 ...

最新文章

  1. 应届生失业率或继续上升?别怕,这份秋招指南请收好!
  2. 谷歌浏览器 广告屏蔽插件 ublock
  3. 【Java 并发编程】线程简介 ( 进程与线程 | 并发概念 | 线程间通信 | Java 并发 3 特性 )
  4. html常用标签详解4-列表标签
  5. 3.8 Softmax 回归-深度学习第二课《改善深层神经网络》-Stanford吴恩达教授
  6. 操作系统真实的虚拟内存是什么样的
  7. 多级缓存设计详解 | 给数据库减负,刻不容缓!
  8. Python之高等数学的符号求解
  9. 「SAP技术」SAP MM 启用了MPN物料管理的物料,物料主数据与源清单数据有啥不同?
  10. 【月伴流星】Windows7 SP1_x86/x64多合一安装版2019.08
  11. python股票量化交易从入门到实践df_Python股票量化交易从入门到实践/金融科技系列...
  12. vue结合高德地图V2.0(JSAPI key搭配代理服务器并携带安全密钥转发)
  13. BDP荧光染料BODIPY FL-PEG2-COOH/carboxylic acid/羧基羧酸,Ex/Em(nm)503/509
  14. mysql group 查询的替代_mysql group_concat替代或多行作为列
  15. 石头、纸、剪刀小游戏(剪刀石头布?)
  16. 通俗易懂讲讲手机通信芯片那些事儿
  17. 计算机考试的话语,考试加油鼓励的话 为考试加油的暖心句子
  18. 初中数学抽象教学的案例_初中数学教学案例及反思
  19. mysql数据库搭建动态网站_数据库和动态网页怎么建立联系
  20. MMKV使用及简单封装-kotlin

热门文章

  1. CloudEvents 入门文档
  2. Qt的内存释放策略(内存自动释放机制)
  3. 外研社写作阅读大赛整理
  4. 【招银网络科技java面试题目面试经验】-看准网
  5. MySQL学习四:MySQL双主双从
  6. 在线查看网页的源文件
  7. 第十四章 使用SQL Shell界面(三)
  8. 什么是短线,中线,长线
  9. 找一个有钱的男朋友是什么体验?
  10. android 来电压力测试,50次之后,来电无法唤醒屏幕