openKE-Transe

本文介绍了一个基于PyTorch实现的TransE模型,用于知识图谱中的实体和关系嵌入,包括模型结构、初始化、计算得分以及正则化项的处理。模型支持不同模式下的计算,并可选择是否使用margin约束在损失函数中.
摘要由CSDN通过智能技术生成
import torch
import torch.nn as nn
import torch.nn.functional as F
from .Model import Model

class TransE(Model):

	def __init__(self, ent_tot, rel_tot, dim=100, p_norm=1, norm_flag=True, margin=None, epsilon=None):
		super(TransE, self).__init__(ent_tot, rel_tot)  # 调用父类的初始化方法,ent_tot表示实体的总数,rel_tot表示关系的总数

		# ent_tot代表实体的总数,rel_tot代表关系的总数。
		self.dim = dim  # 实体和关系的嵌入维度,默认为100
		self.margin = margin  # 损失函数的边界,默认为None
		self.epsilon = epsilon  # 嵌入的范围,默认为None
		self.norm_flag = norm_flag  # 是否对嵌入进行归一化,默认为True
		self.p_norm = p_norm  # 范数的大小,默认为1

		self.ent_embeddings = nn.Embedding(self.ent_tot, self.dim)  # 创建一个实体嵌入的Embedding层,大小为(ent_tot, dim)
		self.rel_embeddings = nn.Embedding(self.rel_tot, self.dim)  # 创建一个关系嵌入的Embedding层,大小为(rel_tot, dim)

		if margin == None or epsilon == None:  # 如果边界或范围为None
			nn.init.xavier_uniform_(self.ent_embeddings.weight.data)  # 初始化实体嵌入的权重矩阵
			nn.init.xavier_uniform_(self.rel_embeddings.weight.data)  # 初始化关系嵌入的权重矩阵
		else:  # 如果边界和范围都不为None
			self.embedding_range = nn.Parameter(
				torch.Tensor([(self.margin + self.epsilon) / self.dim]), requires_grad=False
			)  # 创建一个参数embedding_range,用于限制嵌入的范围
			nn.init.uniform_(
				tensor=self.ent_embeddings.weight.data,
				a=-self.embedding_range.item(),
				b=self.embedding_range.item()
			)  # 初始化实体嵌入的权重矩阵,范围为[-embedding_range.item(), embedding_range.item()]
			nn.init.uniform_(
				tensor=self.rel_embeddings.weight.data,
				a=-self.embedding_range.item(),
				b=self.embedding_range.item()
			)  # 初始化关系嵌入的权重矩阵,范围为[-embedding_range.item(), embedding_range.item()]

		if margin != None:  # 如果边界不为None
			self.margin = nn.Parameter(torch.Tensor([margin]))  # 创建一个参数margin,用于限制损失函数的边界
			self.margin.requires_grad = False  # 设置margin参数不需要梯度计算
			self.margin_flag = True  # 设置margin_flag为True,表示使用了margin边界
		else:  # 如果边界为None
			self.margin_flag = False  # 设置margin_flag为False,表示没有使用margin边界

	def _calc(self, h, t, r, mode):
		if self.norm_flag:  # 如果需要对嵌入进行归一化
			h = F.normalize(h, 2, -1)  # 对实体嵌入h进行L2范数归一化
			r = F.normalize(r, 2, -1)  # 对关系嵌入r进行L2范数归一化
			t = F.normalize(t, 2, -1)  # 对实体嵌入t进行L2范数归一化
		if mode != 'normal':  # 如果不是normal模式
			h = h.view(-1, r.shape[0], h.shape[-1])  # 将实体嵌入h调整为(batch_size, relation_count, embedding_dim)的形状
			t = t.view(-1, r.shape[0], t.shape[-1])  # 将实体嵌入t调整为(batch_size, relation_count, embedding_dim)的形状
			r = r.view(-1, r.shape[0], r.shape[-1])  # 将关系嵌入r调整为(batch_size, relation_count, embedding_dim)的形状
		if mode == 'head_batch':  # 如果是head_batch模式
			score = h + (r - t)  # 计算得分,对应于公式h + (r - t)
		else:  # 如果是其他模式(关系批量或normal)
			score = (h + r) - t  # 计算得分,对应于公式(h + r) - t
		score = torch.norm(score, self.p_norm, -1).flatten()  # 计算得分的Lp范数,并展平为一维向量
		return score  # 返回计算得分结果

	def forward(self, data):
		batch_h = data['batch_h']  # 从输入数据中获取batch中的头实体索引,batch_h是一个张量
		batch_t = data['batch_t']  # 从输入数据中获取batch中的尾实体索引,batch_t是一个张量
		batch_r = data['batch_r']  # 从输入数据中获取batch中的关系索引,batch_r是一个张量
		mode = data['mode']  # 从输入数据中获取计算模式,mode是一个字符串,可能的取值为'head_batch'、'tail_batch'或'normal'
		h = self.ent_embeddings(batch_h)  # 获取batch中头实体的嵌入向量h
		t = self.ent_embeddings(batch_t)  # 获取batch中尾实体的嵌入向量t
		r = self.rel_embeddings(batch_r)  # 获取batch中关系的嵌入向量r
		score = self._calc(h, t, r, mode)  # 调用_calc方法计算得分,根据不同的模式计算不同的得分
		if self.margin_flag:  # 如果使用了边界
			return self.margin - score  # 返回边界减去得分作为最终的损失值
		else:  # 如果没有使用边界
			return score  # 返回得分作为最终的损失值

	def regularization(self, data):
		batch_h = data['batch_h']  # 从输入数据中获取batch中的头实体索引,batch_h是一个张量
		batch_t = data['batch_t']  # 从输入数据中获取batch中的尾实体索引,batch_t是一个张量
		batch_r = data['batch_r']  # 从输入数据中获取batch中的关系索引,batch_r是一个张量
		h = self.ent_embeddings(batch_h)  # 获取batch中头实体的嵌入向量h
		t = self.ent_embeddings(batch_t)  # 获取batch中尾实体的嵌入向量t
		r = self.rel_embeddings(batch_r)  # 获取batch中关系的嵌入向量r
		regul = (torch.mean(h ** 2) +  # 计算头实体嵌入的L2范数的平均值
				 torch.mean(t ** 2) +  # 计算尾实体嵌入的L2范数的平均值
				 torch.mean(r ** 2)) / 3  # 计算关系嵌入的L2范数的平均值,然后取三者的平均值作为正则化项
		return regul  # 返回正则化项


	def predict(self, data):  #测试,不用管
		score = self.forward(data)  # 调用forward方法预测得分
		if self.margin_flag:  # 如果使用了边界
			score = self.margin - score  # 计算边界减去得分作为最终得分
			return score.cpu().data.numpy()  # 将最终得分转换为numpy数组并返回
		else:  # 如果没有使用边界
			return score.cpu().data.numpy()  # 将得分转换为numpy数组并返回

《新概念51单片机C语言教程:入门、提高、开发、拓展》从实际应用入手,以实验过程和实验现象为主导,循序渐进地讲述51单片机C语言编程方法以及51单片机的硬件结构和功能应用。全书共分5篇,分别为入门篇、内外部资源操作篇、提高篇、实战篇和拓展篇。《新概念51单片机C语言教程:入门、提高、开发、拓展》内容丰富,实用性强,书中大部分内容均来自科研工作及教学实践,许多C语言代码可以直接应用到工程项目中。《新概念51单片机C语言教程》配套光盘提供13讲近30学时的教学视频和《新概念51单片机C语言教程》实例代码,可使读者更快更好地掌握单片机知识和应用技能。《新概念51单片机C语言教程》作者还可提供与《新概念51单片机C语言教程:入门、提高、开发、拓展》配套的单片机实验板。   《新概念51单片机C语言教程:入门、提高、开发、拓展》可作为大学本、专科单片机课程教材,适合于51单片机的初学者和使用51单片机从事项目开发的技术人员,也可供从事自动控制、智能仪器仪表、电力电子、机电一体化等专业的技术人员参考。 《新概念51单片机C语言教程:入门、提高、开发、拓展》组织:   全书分为勾5篇,入门篇、内外部资源操作篇、提高篇、实战篇和拓展篇   特别按照初学者所遇到的问题和需求路径安排全书内容   以应用需求为主线,搭建了单片机技术上下游的知识体系   从实际工程应用入手,通过实验过程和现象讲解单片机原理,可读性好   内容源于大量科研和教学实践,许多C语言代码可直接应用到工程项目中,实用性强   配套学习光盘,并可提供学习用实验板,可以边学边练学习资源:   读者对象:   高校电子信息类和机电类专业本/专科师生   高校大学生创新基地师生   51单片机C语言编程初学者   计算机、自动控制、智能仪器仪表、电力电子、机电一体化技术人员
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小蜗子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值