知识图谱补全技术——Recsal篇
文章目录
前言
随着知识图谱在搜索引擎、推荐系统等领域的广泛应用,如何补全图谱中的缺失信息成为一个重要的研究方向。知识补全的任务是根据已知的三元组(头实体-关系-尾实体)推断出未知的三元组,从而完善知识图谱。然而,知识图谱中的关系复杂多样,很多传统模型如 TransE 等只能处理简单的线性关系,对于多对多的复杂关系表现不佳。
为了解决这一问题,Rescal 模型被提出。与 TransE 等模型将关系表示为向量不同,Rescal 使用矩阵来表示关系,这使得它能够捕捉到更复杂的实体交互。通过张量分解技术,Rescal 能够在知识补全任务中取得更好的效果,尤其是在处理复杂关系时表现出色。
一、Rescal 模型的基本原理
1.模型的数学原理
在RESCAL模型中,假设知识图谱中的三元组表示为 (ℎ,𝑟,𝑡),其中 ℎ 是头实体,𝑟r是关系,𝑡 是尾实体。每个实体 𝑒𝑖会被嵌入到一个 𝑘维向量 𝑒𝑖中,每个关系 𝑟𝑗被表示为一个 𝑘×𝑘 维矩阵 𝑅𝑗 。给定三元组 (ℎ,𝑟,𝑡)(h,r,t),Rescal模型的打分函数可以表示为:
其中,𝑒ℎ和 𝑒𝑡分别是头实体和尾实体的向量表示,𝑅𝑟是关系的矩阵表示。打分函数用于评估三元组的可信度,得分越高,该三元组存在的可能性越大。
2.模型训练
RESCAL模型的目标是通过最小化所有已知三元组的损失函数来学习实体向量和关系矩阵。通常使用的损失函数是平方误差损失函数:
其中,𝑇表示知识图谱中的正样本三元组集合,负样本通过随机采样生成。
3.模型的正则化
由于关系矩阵 𝑅𝑟的参数量较大,Rescal 容易出现过拟合问题。为了解决这个问题,通常会对实体嵌入和关系矩阵进行正则化。常见的正则化方式是 L2 正则化:
其中:𝜆是正则化系数,控制正则化项的权重。∣∣ℎ∣∣2、∣∣𝑡∣∣2是实体嵌入的 L2 范数。∣∣𝑅𝑟∣∣2是关系矩阵的 L2 范数。
通过正则化,模型可以防止嵌入向量或矩阵的参数过大,进而减小过拟合风险。
4.模型的优缺点
优点:
关系的高阶表示:Rescal 使用矩阵表示关系,能够捕捉到实体之间更复杂的交互模式。
灵活性强:适用于多对多关系,例如社交网络中的“朋友”关系、书籍推荐中的“用户–喜欢–物品”等。
高效的知识补全:通过张量分解,Rescal 可以高效推断未知的三元组,进行知识补全。
缺点:
计算复杂度高:由于每个关系被表示为一个矩阵,Rescal 在计算上比其他向量模型(如 TransE)更为复杂,尤其在关系数目较多时,计算和存储成本较高。
容易过拟合:关系矩阵的参数量较大,因此容易出现过拟合,需要额外的正则化来缓解这一问题。
二、Rescal算法
1.准备好三元组数据集csv格式
csv文件内容三元组格式如图
2.安装必要的库
安装了以下Python包:
torch
pandas
scikit-learn
numpy
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)
# 创建实体和关系的索引映射
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)
.......
data_preprocessing.py 文件的主要作用是加载并预处理数据。主要流程包括:
CSV 文件读取:使用 pandas 读取三元组数据集。
实体和关系映射:通过为每个实体和关系分配唯一的 ID,将实体和关系转换为整数索引。
数据集划分:将数据集划分为训练集、验证集和测试集,使用 train_test_split 来完成这一过程。
转换为 PyTorch 张量:为了后续训练,数据被转换为 PyTorch 的 LongTensor,以方便模型使用。
model.py
import torch
import torch.nn as nn
class Rescal(nn.Module):
def __init__(self, num_entities, num_relations, embedding_dim):
super(Rescal, self).__init__()
self.embedding_dim = embedding_dim
self.entity_embeddings = nn.Embedding(num_entities, embedding_dim)
# 为每个关系初始化一个矩阵
self.relation_matrices = nn.ParameterList(
[nn.Parameter(torch.randn(embedding_dim, embedding_dim)) for _ in range(num_relations)]
)
# 初始化实体嵌入
self.entity_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) # 获取头实体的嵌入
t = self.entity_embeddings(tail) # 获取尾实体的嵌入
# 批量处理关系矩阵
r = torch.stack([self.relation_matrices[i] for i in relation])
# 计算得分 (h^T * R * t)
score = torch.sum(h.unsqueeze(1) @ r * t.unsqueeze(1), dim=[1, 2]) # 批量计算
return -score # 负号表示最小化得分
.......
model.py 文件主要负责 Rescal 模型的定义。这个模型是基于 PyTorch 实现的,核心内容包括:
实体嵌入:实体通过 nn.Embedding 表示,形状为 [num_entities, embedding_dim],其中每个实体都被嵌入到一个低维向量空间。
关系矩阵:每个关系都被表示为一个矩阵,形状为 [embedding_dim, embedding_dim]。这些矩阵通过 nn.ParameterList 进行存储。
得分函数:模型通过计算头实体、关系矩阵和尾实体的内积来计算三元组的得分
损失函数:使用对比损失(margin-based loss)来优化模型,区分真实的三元组和生成的负样本。
train.py
import torch
import torch.optim as optim
from model import Rescal # 替换为 Rescal 模型
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
# 创建Rescal模型和优化器
model = Rescal(num_entities, num_relations, embedding_dim)
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 训练模型
num_epochs = 200
for epoch in range(num_epochs):
model.train()
optimizer.zero_grad()
# 随机选择负样本
neg_head = torch.randint(0, num_entities, (len(train_triples),))
neg_tail = torch.randint(0, num_entities, (len(train_triples),))
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()
.......
train.py 文件负责模型的训练和评估。主要包括以下步骤:
加载数据:从 data_preprocessing.py 中加载并预处理后的数据。
初始化模型:使用 model.py 中定义的 Rescal 模型,初始化实体数目、关系数目和嵌入维度。
负样本生成:通过随机替换头实体或尾实体生成负样本,用于对比损失函数。
训练过程:通过 PyTorch 的优化器(例如 SGD)更新模型参数。在每个 epoch 中,计算正样本和负样本的得分,并根据损失函数调整模型参数。
模型保存:训练结束后,将训练好的模型保存为 .pth 文件,以便后续加载和使用。
运行结果如图:
completion.py
import torch
from model import Rescal
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
# 创建和加载Rescal模型
model = Rescal(num_entities, num_relations, embedding_dim)
model.load_state_dict(torch.load('rescal_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 + 1, largest=False) # 多取一个结果,以便过滤
topk_entities = [list(entity_to_id.keys())[idx.item()] for idx in topk_indices]
if head in topk_entities:
topk_entities.remove(head)
return topk_entities[:k]
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 + 1, largest=False)
topk_entities = [list(entity_to_id.keys())[idx.item()] for idx in topk_indices]
if tail in topk_entities:
topk_entities.remove(tail)
return topk_entities[:k]
def predict_relation(head, tail, k=5):
head_idx = torch.LongTensor([entity_to_id[head]])
tail_idx = torch.LongTensor([entity_to_id[tail]])
all_relations = torch.LongTensor(range(num_relations))
.......
completion.py 文件主要用于知识补全任务,即基于训练好的模型预测知识图谱中缺失的实体或关系。主要功能包括:
加载训练好的模型:从文件中加载保存的 Rescal 模型权重。
预测尾实体:给定头实体和关系,预测可能的尾实体。
预测头实体:给定关系和尾实体,预测可能的头实体。
运行结果如图:(数据保密,故作打码处理)
总结
Rescal 是一种强大的张量分解模型,通过将关系表示为矩阵,能够捕捉实体间的复杂关系,尤其在多对多映射的场景中表现出色。虽然它的计算和存储成本较高,但在知识补全任务中依然是一种有效的模型,适合处理大型知识图谱中的复杂关系模式。
代码购买链接:https://mbd.pub/o/bread/ZpuWkplr