transe 知识谱,transE代码

1源代码本代码来源于github项目地址,项目实现了TransE算法。 结合项目代码,详细介绍了TransE算法的原理和实现。

2基本思想TransE是Bordes等人在2013年在NIPS上发表的文章中提出的算法。 其提出是为了解决多关系数据(multi-relational data )的处理问题。 目前有许多知识库数据,包括知识库、谷歌知识库和知识文库。

TransE的直观意义是TransE基于实体和关系的分散矢量表现,将各三元组实例(head,relation,tail )中的关系relation看作从实体head到实体tail的翻译,h

3处理流程的TransE算法分为表达向量的初始化(步骤1 (步骤3 )、批训练数据集的构建(步骤6 (步骤11 )、表达向量的更新)步骤12、步骤5 ) 3个部分

显示向量的初始化(步骤1 (步骤3 ) ),用k维的随机且均等的分布初始化各实体和各关系。

批训练数据集构建(step6-step11 )从训练集合中随机选择正采样(h、r、t ),基于正采样在正采样中的h、r或r

在更新显示矢量(步骤12、步骤5 )中,通过采用随机梯度方法来更新批训练数据集中的正采样(h、r、t )和负采样的矢量显示。

TranE直接对向量表示进行训练,每个实体(head或tail)对应一个k维向量,每个关系对应一个k维向量,所有的k维向量即为TransE模型的参数,需要训练的参数。

4代码实现项目使用FB15K进行训练演示,FB15K包含三种数据,分别是实体数据、关系数据、(h、t、r )数据。

实体数据:包含两列的实体2 id。 第一列由实体名、第二列由实体id、中央标签分隔。

/m/06rf 70/m/0 c 94fn1/m/016 ywr2/m/01yj L3关系数据: relation2ID由2列构成,第1列用关联名,第2列用关系id、中间标签分开。

/people/appointed _ role/appointment./people/appointment/appointed _ by0/location/statistical _ region/region TV/TV _ guest _ role/actor2/music/performance _ role contributor3(h,t,r )数据是第三列、第一列中的h实体名称和第二列中的t实体

/m/07pd _ j/m/02l7c8/film/film/genre/m/06 wxw/m/02 fqwt/location/location/time _ zones/m/04 fqn an football _ team/historical _ roster.position _ s/m/012201/m/0 ckrnn/film/music _ contributor/film (1) 初始化程序模块表示definit(DIM ) 3360 return uniform6/(dim * * 0.5 ) ) entity vectorlist={ } relation vectorlist={ } forention 首先对实体表示向量初始化,关系为向量初始化方法相同的n=0entity vector=[ ] whilenself.dim : # dim个具有均匀分布的随机数ram=init(self.dim ) # 表示生成的随机数entityvector.append ) ram )的n=1entity vector=norm (entity vector ) #是dim维向量entity vectorlist entity ) entity

样本和负样本合在一起,作为一条样本 def getSample(self, size): return sample(self.tripleList, size) def getCorruptedTriplet(self, triplet): ”’ training triplets with either the head or tail replaced by a random entity (but not both at the same time) :param triplet: :return corruptedTriplet: ”’ i = uniform(-1, 1) #随机选择,小于0改变正样本中的H实体,变为负样本,大于0改变T实体,变为负样本 if i < 0:#小于0,打坏三元组的第一项 while True: entityTemp = sample(self.entityList.keys(), 1)[0] if entityTemp != triplet[0]: break corruptedTriplet = (entityTemp, triplet[1], triplet[2]) else:#大于等于0,打坏三元组的第二项 while True: entityTemp = sample(self.entityList.keys(), 1)[0] if entityTemp != triplet[1]: break corruptedTriplet = (triplet[0], entityTemp, triplet[2]) return corruptedTripletSbatch = self.getSample(150)Tbatch = []#元组对(原三元组,打碎的三元组)的列表 :{((h,r,t),(h’,r,t’))}for sbatch in Sbatch: tripletWithCorruptedTriplet = (sbatch, self.getCorruptedTriplet(sbatch)) if(tripletWithCorruptedTriplet not in Tbatch): Tbatch.append(tripletWithCorruptedTriplet) (3)表示向量更新

下面对上述代码进行详解。
首先提取用于单次训练的正样本和负样本向量表示。感觉没必须进行深度拷贝,直接计算就行,有没有大神指点一下。
数据提取

//正样本向量表示和负样本向量表示提取,正样本和负样本中的关系对象是相同的headEntityVector = copyEntityList[tripletWithCorruptedTriplet[0][0]]#tripletWithCorruptedTriplet是原三元组和打碎的三元组的元组tupletailEntityVector = copyEntityList[tripletWithCorruptedTriplet[0][1]]relationVector = copyRelationList[tripletWithCorruptedTriplet[0][2]]headEntityVectorWithCorruptedTriplet = copyEntityList[tripletWithCorruptedTriplet[1][0]]tailEntityVectorWithCorruptedTriplet = copyEntityList[tripletWithCorruptedTriplet[1][1]]#tripletWithCorruptedTriplet是原三元组和打碎的三元组的元组tuple headEntityVectorBeforeBatch = self.entityList[tripletWithCorruptedTriplet[0][0]]tailEntityVectorBeforeBatch = self.entityList[tripletWithCorruptedTriplet[0][1]]relationVectorBeforeBatch = self.relationList[tripletWithCorruptedTriplet[0][2]]headEntityVectorWithCorruptedTripletBeforeBatch = self.entityList[tripletWithCorruptedTriplet[1][0]]tailEntityVectorWithCorruptedTripletBeforeBatch = self.entityList[tripletWithCorruptedTriplet[1][1]]

损失计算

//计算正负样本的L1或L2距离范数,然后计算合页损失函数(hinge loss function)if self.L1:distTriplet = distanceL1(headEntityVectorBeforeBatch, tailEntityVectorBeforeBatch, relationVectorBeforeBatch)distCorruptedTriplet = distanceL1(headEntityVectorWithCorruptedTripletBeforeBatch, tailEntityVectorWithCorruptedTripletBeforeBatch , relationVectorBeforeBatch)else:distTriplet = distanceL2(headEntityVectorBeforeBatch, tailEntityVectorBeforeBatch, relationVectorBeforeBatch)distCorruptedTriplet = distanceL2(headEntityVectorWithCorruptedTripletBeforeBatch, tailEntityVectorWithCorruptedTripletBeforeBatch , relationVectorBeforeBatch)eg = self.margin + distTriplet – distCorruptedTripletdef distanceL1(h, t ,r): #L1距离范数,向量每个原素绝对值的和 s = h + r – t sum = fabs(s).sum() return sum def distanceL2(h, t, r): #L2距离范数,向量每个元素平方的和 s = h + r – t sum = (s*s).sum() return sum

梯度计算

//计算合页损失函数和梯度,[function]+ 是一个取正值的函数if eg > 0: #如果大于0,进行处理,小于等于0不处理self.loss += eg if self.L1: #L1范数为每个向量元素的绝对值,如果向量元素大于0,其梯度为1,小于0,其梯度为-1。程序此处直接取梯度的负数,表示向量更新的时候直接加tempPositive = 2 * self.learingRate * (tailEntityVectorBeforeBatch – headEntityVectorBeforeBatch – relationVectorBeforeBatch)tempNegtative = 2 * self.learingRate * (tailEntityVectorWithCorruptedTripletBeforeBatch – headEntityVectorWithCorruptedTripletBeforeBatch -relationVectorBeforeBatch)tempPositiveL1 = [] tempNegtativeL1 = []for i in range(self.dim):if tempPositive[i] >= 0: #根据距离正负,得到向量表示各元素的梯度tempPositiveL1.append(1)else: tempPositiveL1.append(-1) if tempNegtative[i] >= 0: tempNegtativeL1.append(1) else: tempNegtativeL1.append(-1) tempPositive = array(tempPositiveL1) tempNegtative = array(tempNegtativeL1) else: #L2范数为每个向量元平方的和,提取直接为距离向量tempPositive = 2 * self.learingRate * (tailEntityVectorBeforeBatch – headEntityVectorBeforeBatch – relationVectorBeforeBatch)tempNegtative = 2 * self.learingRate * (tailEntityVectorWithCorruptedTripletBeforeBatch – headEntityVectorWithCorruptedTripletBeforeBatch – relationVectorBeforeBatch)

梯度下降

// 对正负样本相关的(h,t,r)表示向量进行梯度更新,由于梯度求取的时候直接取负,因此梯度更新的时候直接加(即加变减,减变加)headEntityVector = headEntityVector + tempPositivetailEntityVector = tailEntityVector – tempPositiverelationVector = relationVector + tempPositive – tempNegtativeheadEntityVectorWithCorruptedTriplet = headEntityVectorWithCorruptedTriplet – tempNegtativetailEntityVectorWithCorruptedTriplet = tailEntityVectorWithCorruptedTriplet + tempNegtative# 为了方便训练并避免过拟合,加上约束条件,进行归一化处理copyEntityList[tripletWithCorruptedTriplet[0][0]] = norm(headEntityVector)copyEntityList[tripletWithCorruptedTriplet[0][1]] = norm(tailEntityVector)copyRelationList[tripletWithCorruptedTriplet[0][2]] = norm(relationVector)copyEntityList[tripletWithCorruptedTriplet[1][0]] = norm(headEntityVectorWithCorruptedTriplet)copyEntityList[tripletWithCorruptedTriplet[1][1]] = norm(tailEntityVectorWithCorruptedTriplet)# 更新完后,写入原变量self.entityList = copyEntityListself.relationList = copyRelationList 5总结

TransE算法直接对每个实体、每个关系进行参数表示,抛开语义表示,根据实体关系间的三角向量关系约束,进行梯度优化,感觉存在参数过度,语义无关等问题。

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注