简单实现几篇知识图谱嵌入(Knowledge Graph Embedding,KGE)模型 |
您所在的位置:网站首页 › transe代码 › 简单实现几篇知识图谱嵌入(Knowledge Graph Embedding,KGE)模型 |
关于知识图谱嵌入的理论介绍: 简要总结一篇关于知识图谱嵌入的综述 KGE的诸多方法KGE就是将实体和关系嵌入到低维向量空间中,同时保留KG的结构和语义信息 现有的KGE方法可以划分为三类: 基于翻译距离的(translational distance based)基于语义匹配的(semantic matching based)基于神经网络的(neural network based)下面我们来实现几个最经典的KGE模型:基于翻译距离的模型TransE、基于语义匹配的模型RESCAL和DistMult, TransE该模型将关系看作头实体到尾实体的翻译。 TransE受到word2vec的启发,如果你已经训练好了词向量,那么针对三个单词:国家country、城市city,首都captial-of,就会有如下关系: V c o u n t r y − V c i t y V_{country}-V_{city} Vcountry−Vcity得到的向量与 V c a p t i a l − o f V_{captial-of} Vcaptial−of这个向量就很相近。TransE也认为,在KG的embedding空间中,也一定存在这种关系,即两个实体的嵌入向量的差值(或者其它操作)就代表这两个实体之间的关系。 因为关系和实体都被表示为向量,所以另一种数学化的说法就是在向量(vector)空间中,TransE将关系看作是头实体到尾实体的平移操作,即: v h + v r ≈ v t v_h+v_r\approx v_t vh+vr≈vt 数学定义中: 平移前点的坐标+平移向量的坐标=平移后点的坐标 所以我们称之为平移 TransE的得分函数就是向量之间的欧氏距离的相反数: S c o r e ( h , r , t ) = − ∣ ∣ v h + v r − v t ∣ ∣ 2 2 Score(h,r,t)=-||v_h+v_r-v_t||_2^2 Score(h,r,t)=−∣∣vh+vr−vt∣∣22 损失函数定义为: m a x ( 0 , γ − S c o r e ( h , r , t ) + S c o r e ( h ′ , r , t ′ ) ) max(0,\gamma-Score(h,r,t)+Score(h',r,t')) max(0,γ−Score(h,r,t)+Score(h′,r,t′)) 也就是在embedding space中,正例三元组的得分要比负例三元组的得分高出 γ \gamma γ,又由于得分函数表示为距离的相反数,所以得分高代表距离近。即:正例三元组的距离要比负例三元组的距离小至少 γ \gamma γ长度的距离。 RESCAL该模型的得分函数定义为: S c o r e ( h , r , t ) = v h T M r v t Score(h,r,t)=v_h^TM_rv_t Score(h,r,t)=vhTMrvt 其中 v h ∈ R d , v t ∈ R d , M r ∈ R d × d v_h\in R^d,v_t\in R^d,M_r\in R^{d\times d} vh∈Rd,vt∈Rd,Mr∈Rd×d v h , v t v_h,v_t vh,vt都是从实体embedding矩阵(记为 E E E)中的取出(根据实体id获取)的vector, E E E的形状是(num_entities,d)。 M r M_r Mr是整个关系tensor(三维的)中的根据关系id获取的matrix(二维的)。整个关系tensor记为 R R R,形状是(num_relations,d,d),所以 M r M_r Mr的shape是( d , d d,d d,d)。 DistMultDistMult是RESCAL的简化。具体来说就是RESCAL中每一个head和tail实体之间的关系r是用一个matrix表示。而DistMult中则用一个vector表示两个实体间的关系。 所以得分函数是三个vector之间的内积: < v h , v r , v t > v h , v r , v t ∈ R d v_h,v_r,v_t\in R^d vh,vr,vt∈Rd 代码实现 获取数据我们使用FB15K知识库 下载解压: 592213个三元组的划分情况是: 数据集划分三元组数量训练集483142验证集50000测试集59017 实现实现代码需要说明的一点是,下面的代码采用Binary Cross Entropy loss作为损失函数,即输入是头实体和关系的id,经过模型之后,输出一个向量,长度是num_entities,也就是所有实体的数量。 这个向量的每一个值都进行sigmoid运算,此时这个向量的第i个位置的值代表模型预测第i个实体是尾实体的概率 标签是尾实体的id,即告诉模型第几个位置的实体才是真正的尾实体,需要增加这个位置的概率,降低其余位置的概率。 也就是说达到了:要求正例三元组的得分大于负例三元组的得分。 导包 import numpy as np import torch import torch.nn as nn import torch.nn.functional as F import time from collections import defaultdict import argparse from tqdm import tqdm import os 处理数据 加载数据 def load_data(data_dir,data_type): with open("%s%s.txt" % (data_dir, data_type), "r") as f: data = f.read().strip().split("\n") data = [i.split('\t') for i in data] print(len(data),data_type) return data train_data=load_data(data_dir='/mnt/cfs/speech/nlp/work/xhsun/KGQA/Trans/FB15k/',data_type='freebase_mtr100_mte100-train') valid_data=load_data(data_dir='/mnt/cfs/speech/nlp/work/xhsun/KGQA/Trans/FB15k/',data_type='freebase_mtr100_mte100-valid') test_data=load_data(data_dir='/mnt/cfs/speech/nlp/work/xhsun/KGQA/Trans/FB15k/',data_type='freebase_mtr100_mte100-test') data=train_data+valid_data+test_data print(len(data)) 统计所有的头实体、尾实体以及 关系: entities = sorted(list(set([d[0] for d in data]+[d[2] for d in data]))) print(len(entities)) relations = sorted(list(set([d[1] for d in data]))) print(len(relations))即14951个实体,1345个关系 构造entity2id和relation2id的字典映射 entity_idxs={entities[i]:i for i in range(len(entities))} relation_idxs={relations[i]:i for i in range(len(relations))}构造实体到id,关系到id的映射,这一步是NLP中必做的一步,因为我们要根据输入的实体,找到对应的id,进而找到对应的embedding 生成训练数据 train_data_idxs=[[entity_idxs[triplet[0]],relation_idxs[triplet[1]],entity_idxs[triplet[2]]] for triplet in train_data]以前4个三元组为例 输入的是头实体和关系的id,输出的标签是尾实体的id。 需要注意的是,同一组头实体和关系,会有很多个尾实体存在的。 以第一个三元组为例: 即,(3920,791,9220)是一个三元组,也就是输入数据的一个样本。(3920,791,3799)也是一个三元组。所以标签有两个1。
假设模型已经训练好了,下面来测试模型 加载测试数据 test_data_idxs=[[entity_idxs[triplet[0]],relation_idxs[triplet[1]],entity_idxs[triplet[2]]] for triplet in test_data] test_er_vocab=defaultdict(list) for triplet in test_data_idxs: test_er_vocab[(triplet[0],triplet[1])].append(triplet[2]) test_batch_inputs=test_data_idxs[:3] test_batch_inputs=np.array(test_batch_inputs) test_batch_inputs
测试评估阶段与训练阶段不同。 我们以测试数据中第一个样本为例,输入的头实体id是2431,关系id是89,尾实体id是5452,也就是(2431,89,5452)这么一个三元组,我们希望的是模型预测第5452个实体作为尾实体的概率越大越好。但是给定头实体2431和关系89,可不是只有一个三元组的 MeanRank: 模型输出的probabilities的长度是num_entities,我们将probabilities降序排列,即分数高的排在前面。mean rank中的rank指的就是:模型对于当前三元组尾实体在所有实体中的分数排名。 所以这个数值越低越好,因为越低,表明排名越靠前。 Hit@1,3,10: @就是英文的at。hit at 1指的就是将尾实体排在第一位的次数/测试集合大小,hit at 3和git at 10同理。显然这个数值越高越好。越高说明每一个三元组的尾实体都被模型排名的非常靠前。 sort_scores,sort_idxs=torch.sort(probabilities,dim=1,descending=True) ranks=[] hits=[[] for _ in range(10)] for i in range(len(test_batch_inputs)): rank=np.where(sort_idxs[i].numpy()==tail_idx[i].item())[0][0]+1 ranks.append(rank) for hits_level in range(1,11): if rank |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |