知识图谱补全技术-ConvE篇

知识图谱补全技术-ConvE篇



前言

ConvE(Convolutional Knowledge Graph Embedding)是一种用于知识图谱补全的模型,它通过卷积神经网络(CNN)来学习知识图谱中的实体和关系的嵌入表示,从而预测缺失的三元组。其主要思想是将传统的知识图谱嵌入方法与卷积神经网络相结合,以提高模型的表达能力和推理能力。


一、ConvE模型原理

ConvE 的核心思想是将实体和关系嵌入重塑为矩阵形式,通过卷积神经网络提取实体和关系之间的复杂交互特征,并通过全连接层将卷积后的特征映射回实体空间,进行尾实体的预测。

与以往的线性模型(如 TransE、DistMult)相比,ConvE 引入了非线性操作(卷积和激活函数),可以更好地捕捉实体和关系之间的复杂模式。这种卷积操作允许模型对局部交互进行更深入的分析,从而增强模型的表达能力。
模型原理图如下图:
在这里插入图片描述

1.模型架构与流程

1.1 实体和关系的嵌入表示

ConvE 模型的第一步是为每个实体和关系生成一个嵌入向量。假设知识图谱中有 N 个实体和 M 个关系,每个实体和关系通过嵌入矩阵映射到一个固定的低维向量空间。具体表示为:头实体 h 的嵌入表示为向量 ℎ∈𝑅𝑑 ,关系 r 的嵌入表示为向量 𝑟∈𝑅𝑑 ,尾实体 t 的嵌入表示为向量 𝑡∈𝑅𝑑,其中 𝑑 为嵌入的维度。

1.2 嵌入的重塑与卷积操作

在得到实体和关系的嵌入后,ConvE 模型通过以下方式进行卷积操作:

1.2.1 嵌入重塑(Reshaping):

ConvE 通过将实体和关系的嵌入向量重塑为矩阵,通常是将维度为 𝑑d的向量重塑为 𝑘×𝑘的矩阵形式。例如,一个维度为 100 的嵌入向量可以重塑为一个 10×10 的矩阵。重塑后的头实体嵌入 ℎ′ 和关系嵌入 𝑟′ 被拼接为一个 2𝑘×𝑘 的矩阵:
在这里插入图片描述
拼接后的矩阵包含了头实体和关系的嵌入信息。

1.2.2 卷积操作:

通过将拼接后的矩阵输入卷积神经网络,使用卷积核对局部区域进行感知和特征提取。卷积层可以通过局部的权重共享机制,捕捉头实体和关系之间的局部交互特征。这一步通过卷积层来学习实体和关系之间复杂的特征模式。

1.2.3 非线性激活:

卷积后的输出通常通过ReLU等非线性激活函数进行处理,使得模型能够捕捉到更多的非线性特征。

1.3 特征拉平与全连接层

卷积操作之后,生成的特征图通过拉平(flatten)操作被转换为一个一维向量。这个向量接着通过全连接层进行映射,输出一个固定维度的向量(通常与嵌入维度相同)。
这一层的输出向量可以看作是头实体和关系的卷积特征,它们被用于与知识图谱中所有实体进行相似度计算。

1.4 得分计算与尾实体预测

模型最后通过计算该特征向量与所有实体嵌入向量的点积,得到每个实体作为候选尾实体的得分。点积越大,表示该实体作为尾实体的可能性越高。
假设计算得分的函数为:
在这里插入图片描述
其中 f是卷积和全连接层后的输出向量,t 是候选尾实体的嵌入向量。最后通过对得分排序,选出得分最高的实体作为尾实体的预测结果。

2.损失函数与训练

ConvE模型通常使用负采样策略来生成负样本,并使用排名损失(Ranking Loss)或交叉熵损失(Cross-Entropy Loss)来优化模型。通过最小化正样本的得分与负样本的得分差异,模型能够学习到更准确的实体和关系嵌入。
典型的损失函数形式为:
在这里插入图片描述
其中,𝐷是训练数据集,𝐸是所有实体的集合。

3.ConvE的优缺点

优点:
非线性增强:与传统的线性模型(如 TransE、DistMult)相比,ConvE 通过卷积神经网络引入了非线性操作,增强了模型的表示能力,能够捕捉更加复杂的实体关系交互。
局部感知能力:卷积操作可以捕捉头实体和关系之间的局部特征,而不是简单地进行向量之间的乘积或加法,从而能更好地处理复杂关系。
参数高效:ConvE 使用了共享权重的卷积核,参数量相比一些全连接的嵌入方法更少,同时还能取得更好的表现。
缺点:
计算复杂度高:卷积操作和全连接层的加入使得模型的训练和推理时间相对较长,尤其是在处理大规模知识图谱时。
超参数敏感:ConvE 模型对卷积核大小、嵌入维度、dropout 比例等超参数比较敏感,模型性能依赖于精细的超参数调优。

二、ConvE算法

1.准备好三元组数据集csv格式

csv文件内容三元组格式如图
请添加图片描述

2.安装必要的库

安装了以下Python包:
torch
pandas
scikit-learn
numpy

3.运行步骤

确保所有文件在同一目录下;
编辑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文件中读取三元组数据。
为每个实体和关系创建唯一的ID映射(将字符串实体/关系映射为整数ID)。
将这些ID映射应用到数据集,转换为模型能够理解的数值型数据。
划分数据集为训练集、验证集和测试集,保证模型可以进行训练和评估。
最终输出PyTorch张量格式的数据,以便后续模型能够直接使用这些数据。

model.py

import torch
import torch.nn as nn
import torch.nn.functional as F


class ConvE(nn.Module):
    def __init__(self, num_entities, num_relations, embedding_dim, input_dim=(10, 10), dropout=0.3):
        super(ConvE, self).__init__()
        self.embedding_dim = embedding_dim
        self.entity_embeddings = nn.Embedding(num_entities, embedding_dim)
        self.relation_embeddings = nn.Embedding(num_relations, embedding_dim)

        # ConvE的特定卷积层和Dropout层
        self.input_dim = input_dim  # 输入维度,例如(10, 10)
        self.inp_drop = nn.Dropout(dropout)  # 输入的dropout
        self.hidden_drop = nn.Dropout(dropout)  # 隐藏层的dropout
        self.feature_map_drop = nn.Dropout2d(dropout)  # 卷积特征图的dropout

        # 定义卷积层:输入通道1,输出通道32,卷积核大小(3, 3)
        self.conv = nn.Conv2d(1, 32, (3, 3), stride=1, padding=1)

        # 计算卷积层输出的展平大小,确保与全连接层的输入维度匹配
        conv_output_width = input_dim[1] + embedding_dim // input_dim[0]  # 计算卷积后的宽度
        conv_output_height = input_dim[0]  # 高度保持不变
        conv_output_size = 32 * conv_output_height * conv_output_width  # 32个卷积输出通道,乘以输出的高度和宽度

        # 全连接层,输入大小是conv_output_size,输出大小是embedding_dim
        self.fc = nn.Linear(conv_output_size, embedding_dim)

        # 初始化实体和关系嵌入权重
        nn.init.xavier_uniform_(self.entity_embeddings.weight)
        nn.init.xavier_uniform_(self.relation_embeddings.weight)

    def forward(self, head, relation, tail=None):
        # 获取头实体和关系的嵌入
        h_emb = self.entity_embeddings(head)
        r_emb = self.relation_embeddings(relation)

        # 判断是否传入了所有实体(用于评估)或单个尾实体(用于训练)
        if tail is None:
            # 当没有传入 tail 时,假设传入的是所有实体,需扩展关系的维度以匹配实体数量
            if head.shape[0] > 1:  # 如果传入的是多个实体
                r_emb = r_emb.expand_as(h_emb)

        # 调整形状以适应卷积操作
        h_emb = h_emb.view(-1, 1, *self.input_dim)  # 将实体嵌入重塑为2D形状
        r_emb = r_emb.view(-1, 1, *self.input_dim)  # 将关系嵌入重塑为2D形状

      .......

model.py 文件的核心内容包括:
定义了实体和关系的嵌入层。
定义了2D卷积层,用来处理头实体和关系的拼接嵌入,提取局部特征。
使用全连接层将卷积后的输出映射回实体嵌入空间,进行相似度计算,输出预测分数。
使用矩阵乘法计算所有实体的得分,最后用于预测尾实体或头实体。

train.py

import torch
import torch.optim as optim
import torch.nn.functional as F  # 导入torch.nn.functional
import numpy as np
from model import ConvE
from data_preprocessing import load_and_preprocess_data

# 加载数据
file_path = '三元组数据集.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

# 创建 ConvE 模型和优化器
model = ConvE(num_entities, num_relations, embedding_dim)
optimizer = optim.Adam(model.parameters(), lr=0.001)


# 对比损失函数
def margin_ranking_loss(pos_score, neg_score, margin=1.0):
    return torch.mean(F.relu(neg_score - pos_score + margin))


# 训练模型
num_epochs = 1000
margin = 1.5  # 对比损失的 margin
for epoch in range(num_epochs):
    model.train()
    optimizer.zero_grad()

    # 随机选择负样本
    neg_tail = torch.randint(0, num_entities, (len(train_triples),))
    neg_triples = torch.stack((train_triples[:, 0], train_triples[:, 1], neg_tail), dim=1)

    # 计算正样本的得分
    pos_score = model(train_triples[:, 0], train_triples[:, 1])

    # 计算负样本的得分
    neg_score = model(neg_triples[:, 0], neg_triples[:, 1])

    # 获取正样本对应的尾实体得分
    pos_score = pos_score.gather(1, train_triples[:, 2].view(-1, 1)).squeeze()

    # 获取负样本对应的尾实体得分
    neg_score = neg_score.gather(1, neg_triples[:, 2].view(-1, 1)).squeeze()

    # 使用对比损失函数代替原有的损失函数
    loss = margin_ranking_loss(pos_score, neg_score, margin)
    loss.backward()
    optimizer.step()
        .......

train.py 文件负责模型的训练和评估。主要包括以下步骤:
定义模型和优化器,使用Adam优化算法。
随机生成负样本,用于与正样本进行对比,计算损失。
每轮训练过程中,通过正负样本的得分计算损失,并进行反向传播更新模型。
训练结束后,通过 evaluate_model 函数评估模型在测试集上的性能。
运行结果如图:
请添加图片描述

completion.py

import torch
from model import ConvE
from data_preprocessing import load_and_preprocess_data

# 加载数据和模型
file_path = '三元组数据集.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

# 创建和加载 ConvE 模型
model = ConvE(num_entities, num_relations, embedding_dim)
model.load_state_dict(torch.load('conve_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.arange(num_entities)

    scores = model(head_idx, relation_idx)
    _, topk_indices = torch.topk(scores, k + 1, largest=False)  # 多取一个结果,以便过滤
    topk_entities = [list(entity_to_id.keys())[int(idx)] for idx in topk_indices.view(-1).tolist()]
    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.arange(num_entities)

    scores = model(all_entities, relation_idx)
    _, topk_indices = torch.topk(scores, k + 1, largest=False)
        .......

completion.py 文件主要用于知识补全任务。
加载预训练的模型参数。
定义补全函数 predict_tail 和 predict_head,分别用于预测尾实体和头实体。
使用模型的输出分数,对所有实体进行排序,找到最匹配的头或尾实体。
运行结果如下图(数据保密,故作打码处理)
请添加图片描述

总结

ConvE通过卷积神经网络和非线性操作,有效增强了知识图谱中实体和关系嵌入的交互特性,提升了知识图谱补全任务的表现。相比于传统的线性模型,ConvE在捕捉复杂关系上的表现更优,但同时也需要较高的计算资源和超参数调优技巧。

代码购买链接:https://mbd.pub/o/bread/mbd-ZpuXkp9t

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值