知识图谱补全技术——TransE篇
前言
在自然语言处理和机器学习领域,知识图谱是一种非常重要的数据结构。它通过节点表示实体,边表示实体间的关系,构建了一个复杂的网络结构,在图谱中,如何有效地表示实体和关系是一个关键问题。知识图谱补全技术提供了一种解决方案,它通过预测和填补知识图谱中的缺失三元组,增强了数据的完整性和实用性。它利用嵌入模型和图神经网络等先进的机器学习技术,广泛应用于搜索引擎、推荐系统和智能问答系统等领域,极大地提升了这些系统的性能和用户体验。
TransE模型是知识图谱补全模型中的经典方法之一,它通过一种简单而有效的方式学习实体和关系的向量表示。本文将介绍模型如何对知识图谱数据进行预处理,如何使用Python和PyTorch实现TransE模型的训练和评估。
一、TransE模型原理
TransE(Translating Embeddings for Modeling Multi-relational Data)是Bordes等人在2013年提出的一种知识图谱嵌入方法。它的主要思想是将知识图谱中的实体和关系映射到一个低维向量空间中,并使用简单的线性变换来表示实体之间的关系。
1.知识图谱表示:
知识图谱由三元组(head, relation, tail)表示,通常写作(h, r, t),其中h是头实体,r是关系,t是尾实体。例如,(北京, 位于, 中国)
2.嵌入向量:
在TransE中,每个实体和关系都会被嵌入到一个低维向量空间中。具体来说,每个实体h和t被映射为向量ℎ和𝑡,每个关系r被映射为向量𝑟。
3.线性变换:
TransE的核心思想是,如果(h, r, t)是一个有效的三元组,那么头实体的向量加上关系的向量应该接近尾实体的向量,即:
ℎ+𝑟≈𝑡
4.评分函数
为了衡量一个三元组的有效性,TransE定义了一个评分函数,根据向量之间的距离来评估:
其中,∥⋅∥ 2表示L2范数(欧几里得距离)。
5.训练目标
训练的目标是使真实的三元组(h, r, t)的评分函数值尽可能小,同时使负样本的评分函数值尽可能大。负样本通常通过随机替换头实体或尾实体来生成。
损失函数通常使用基于排名的损失函数,如Margin Ranking Loss:
其中γ是一个超参数,表示正负样本之间的间隔,
6.TransE的优点
简单直观:TransE模型结构简单,易于理解和实现。
高效:由于使用的是线性变换,计算效率较高,适合大规模知识图谱的嵌入学习。
7.TransE的局限性
关系复杂性:TransE对一些复杂关系(如一对多、多对一、多对多)处理较差,因为它假设所有的关系都是简单的线性变换。
低维空间表示:有时单纯的低维向量表示可能无法捕捉到所有实体和关系之间的复杂关联。
8.总结
TransE通过将知识图谱中的实体和关系嵌入到低维向量空间,并使用简单的线性变换来表示实体之间的关系,提供了一种有效的方法来处理知识图谱嵌入任务。虽然它在处理复杂关系上存在一定的局限性,但其简单性和高效性使其成为知识图谱嵌入的一个重要基准方法。
二、TranE算法
1.准备好三元组数据集csv格式
csv文件内容三元组格式如图
2.安装必要的库
安装了以下Python包:
pandas
scikit-learn
torch
3.运行步骤
确保所有文件在同一目录下;
编辑data_preprocessing.py、train.py和completion.py中的文件路径,确保使用正确的数据文件路径;
运行data_preprocessing.py检查数据列名是否正确;
运行train.py训练模型;
运行completion.py进行知识补全。
4.部分代码展示
data_preprocessing.py
import pandas as pd
from sklearn.model_selection import train_test_split
import torch
def load_and_preprocess_data(file_path):
# 加载数据
data = pd.read_csv(file_path)
# 打印列名以检查实际列名
print("Columns in CSV file:", data.columns)
# 创建实体和关系的索引映射
entities = pd.concat([data['头实体'], data['尾实体']]).unique()
relations = data['关系'].unique()
entity_to_id = {entity: idx for idx, entity in enumerate(entities)}
relation_to_id = {relation: idx for idx, relation in enumerate(relations)}
# 将实体和关系映射为索引
data['头实体'] = data['头实体'].map(entity_to_id)
data['关系'] = data['关系'].map(relation_to_id)
data['尾实体'] = data['尾实体'].map(entity_to_id)
# 划分训练集、验证集和测试集
train_data, test_data = train_test_split(data, test_size=0.2, random_state=42)
train_data, valid_data = train_test_split(train_data, test_size=0.2, random_state=42)
# 转换为PyTorch张量
train_triples = torch.LongTensor(train_data.values)
valid_triples = torch.LongTensor(valid_data.values)
test_triples = torch.LongTensor(test_data.values)
return train_triples, valid_triples, test_triples, entity_to_id, relation_to_id
.......
代码解释:加载和预处理数据:读取CSV文件中的三元组数据,并将实体和关系映射为唯一的整数索引。然后,将数据集划分为训练集、验证集和测试集,并转换为PyTorch张量。
model.py
import torch
import torch.nn as nn
class TransE(nn.Module):
def __init__(self, num_entities, num_relations, embedding_dim, margin=1.0):
super(TransE, self).__init__()
self.embedding_dim = embedding_dim
self.margin = margin
self.entity_embeddings = nn.Embedding(num_entities, embedding_dim)
self.relation_embeddings = nn.Embedding(num_relations, embedding_dim)
self.entity_embeddings.weight.data.uniform_(-6 / embedding_dim**0.5, 6 / embedding_dim**0.5)
self.relation_embeddings.weight.data.uniform_(-6 / embedding_dim**0.5, 6 / embedding_dim**0.5)
def forward(self, head, relation, tail):
h = self.entity_embeddings(head)
r = self.relation_embeddings(relation)
t = self.entity_embeddings(tail)
score = torch.norm(h + r - t, p=1, dim=1)
return score
.......
代码解释:定义TransE模型:该模块定义了TransE模型的结构,包括实体和关系的嵌入矩阵、前向传播方法和损失函数。
train.py
import torch
import torch.optim as optim
import numpy as np
from model import TransE # 请确保 model.py 文件在同一目录下
from data_preprocessing import load_and_preprocess_data # 请确保 data_preprocessing.py 文件在同一目录下
# 加载数据
file_path = 'path/to/your/3_三元组数据集.csv' # 替换为你的文件路径
train_triples, valid_triples, test_triples, entity_to_id, relation_to_id = load_and_preprocess_data(file_path)
# 初始化模型参数
num_entities = len(entity_to_id)
num_relations = len(relation_to_id)
embedding_dim = 100
margin = 1.0
# 创建模型和优化器
model = TransE(num_entities, num_relations, embedding_dim, margin)
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
model.train()
optimizer.zero_grad()
# 随机选择负样本
neg_head = torch.randint(0, num_entities, (train_triples.size(0),))
neg_tail = torch.randint(0, num_entities, (train_triples.size(0),))
neg_triples = torch.stack((neg_head, train_triples[:, 1], neg_tail), dim=1)
# 计算正样本和负样本的分数
pos_score = model(train_triples[:, 0], train_triples[:, 1], train_triples[:, 2])
neg_score = model(neg_triples[:, 0], neg_triples[:, 1], neg_triples[:, 2])
# 计算损失并更新模型参数
loss = model.loss(pos_score, neg_score)
loss.backward()
optimizer.step()
if (epoch + 1) % 10 == 0:
print(f"Epoch {epoch + 1}, Loss: {loss.item()}")
# 保存模型
torch.save(model.state_dict(), 'saved_model.pth')
# 评估模型
def evaluate_model(model, data, k_values=[1, 3, 10]):
mean_rank = 0
hits_at_k = {k: 0 for k in k_values}
total_triples = data.shape[0]
for i in range(total_triples):
head, relation, tail = data[i]
head_idx = torch.LongTensor([head])
relation_idx = torch.LongTensor([relation])
tail_idx = torch.LongTensor([tail])
.......
代码解释:训练TransE模型:读取数据,初始化模型和优化器,进行模型训练,并保存训练好的模型。同时定义了评估函数,用于在测试集上评估模型性能。
运行结果如图:
completion.py
import torch
from model import TransE
from data_preprocessing import load_and_preprocess_data
# 加载数据和模型
file_path = 'path/to/your/3_三元组数据集.csv' # 替换为你的文件路径
train_triples, valid_triples, test_triples, entity_to_id, relation_to_id = load_and_preprocess_data(file_path)
# 初始化模型参数
num_entities = len(entity_to_id)
num_relations = len(relation_to_id)
embedding_dim = 100
margin = 1.0
# 创建和加载模型
model = TransE(num_entities, num_relations, embedding_dim, margin)
model.load_state_dict(torch.load('saved_model.pth')) # 使用实际的模型路径
model.eval()
# 知识补全函数
def predict_tail(head, relation, k=5):
head_idx = torch.LongTensor([entity_to_id[head]])
relation_idx = torch.LongTensor([relation_to_id[relation]])
all_entities = torch.LongTensor(range(num_entities))
scores = model(head_idx, relation_idx, all_entities)
_, topk_indices = torch.topk(scores, k, largest=False)
return [list(entity_to_id.keys())[idx.item()] for idx in topk_indices]
def predict_head(tail, relation, k=5):
tail_idx = torch.LongTensor([entity_to_id[tail]])
relation_idx = torch.LongTensor([relation_to_id[relation]])
all_entities = torch.LongTensor(range(num_entities))
scores = model(all_entities, relation_idx, tail_idx)
_, topk_indices = torch.topk(scores, k, largest=False)
return [list(entity_to_id.keys())[idx.item()] for idx in topk_indices]
.......
代码解释:知识补全和预测:加载预训练模型,并使用模型进行知识补全,预测给定头实体和关系的尾实体,或给定尾实体和关系的头实体。
运行结果如图:(数据保密,故作打码处理)
总结
TransE模型通过将知识图谱中的实体和关系嵌入到低维向量空间,并使用简单的线性变换来表示实体之间的关系,提供了一种有效的知识图谱嵌入方法。虽然在处理复杂关系方面存在一定局限,但其简单性和高效性使其成为知识图谱嵌入的一个重要基准方法。
代码购买链接:https://mbd.pub/o/bread/ZpaUlJZx,包调试成功。