使用torch如何对知识表示学习模型RotatE进行修改,使之输出自对抗负采样损失,而不保留实体关系嵌入向量
时间: 2024-01-12 20:02:28 浏览: 68
解决pytorch 交叉熵损失输出为负数的问题
在使用torch对知识表示学习模型RotatE进行修改,使之输出自对抗负采样损失而不保留实体关系嵌入向量时,可以遵循以下步骤:
1. 定义模型结构
首先,我们需要定义一个新的模型结构来实现这个任务。可以参考RotatE模型的代码来定义新的模型结构,需要将实体和关系嵌入向量的权重从模型中移除,并添加自对抗负采样损失函数。这里以在RotatE的基础上对模型进行修改为例:
```python
import torch
import torch.nn as nn
from torch.autograd import Variable
class RotatE_AutoNeg(nn.Module):
def __init__(self, nentity, nrelation, hidden_dim, gamma):
super(RotatE_AutoNeg, self).__init__()
self.nentity = nentity
self.nrelation = nrelation
self.hidden_dim = hidden_dim
self.gamma = gamma
self.embedding_range = nn.Parameter(
torch.Tensor([(self.gamma + 2.0) / (self.hidden_dim * 2)]),
requires_grad=False)
self.entity_emb = nn.Embedding(self.nentity, self.hidden_dim)
self.relation_emb = nn.Parameter(torch.Tensor(self.nrelation, self.hidden_dim))
nn.init.uniform_(
tensor=self.entity_emb.weight.data,
a=-self.embedding_range.item(),
b=self.embedding_range.item()
)
nn.init.uniform_(
tensor=self.relation_emb.data,
a=-self.embedding_range.item(),
b=self.embedding_range.item()
)
def _calc(self, h, t, r):
# Calculate rotated complex embeddings
re_head, im_head = torch.chunk(h, 2, dim=-1)
re_tail, im_tail = torch.chunk(t, 2, dim=-1)
re_relation, im_relation = torch.chunk(r, 2, dim=-1)
re_head = torch.unsqueeze(re_head, dim=-1)
im_head = torch.unsqueeze(im_head, dim=-1)
re_tail = torch.unsqueeze(re_tail, dim=-1)
im_tail = torch.unsqueeze(im_tail, dim=-1)
# Perform rotation
re_h = re_head * re_relation - im_head * im_relation
im_h = re_head * im_relation + im_head * re_relation
re_t = re_tail * re_relation + im_tail * im_relation
im_t = -re_tail * im_relation + im_tail * re_relation
# Concatenate real and imaginary part of embeddings
h = torch.cat([re_h, im_h], dim=-1)
t = torch.cat([re_t, im_t], dim=-1)
return h, t
def forward(self, pos_h, pos_t, pos_r, neg_h, neg_t, neg_r):
# Positive triple score
pos_h_emb = self.entity_emb(pos_h)
pos_t_emb = self.entity_emb(pos_t)
pos_r_emb = self.relation_emb(pos_r)
pos_h_emb, pos_t_emb = self._calc(pos_h_emb, pos_t_emb, pos_r_emb)
pos_score = torch.norm(pos_h_emb + pos_r_emb - pos_t_emb, p=2, dim=-1)
# Negative triple score
neg_h_emb = self.entity_emb(neg_h)
neg_t_emb = self.entity_emb(neg_t)
neg_r_emb = self.relation_emb(neg_r)
neg_h_emb, neg_t_emb = self._calc(neg_h_emb, neg_t_emb, neg_r_emb)
neg_score = torch.norm(neg_h_emb + neg_r_emb - neg_t_emb, p=2, dim=-1)
# Self-adversarial negative sampling loss
auto_neg_score = torch.norm(neg_h_emb + pos_r_emb - pos_t_emb, p=2, dim=-1)
return pos_score, neg_score, auto_neg_score
```
2. 定义损失函数
接下来,我们需要定义损失函数。这里使用自对抗负采样损失函数,需要计算正样本和自动生成的负样本之间的相似度,并将其作为损失函数的一部分。具体实现可以参考以下代码:
```python
criterion = nn.MarginRankingLoss(margin=1.0)
pos_score, neg_score, auto_neg_score = model(pos_h, pos_t, pos_r, neg_h, neg_t, neg_r)
auto_neg_target = Variable(torch.Tensor([-1])).cuda()
loss = criterion(pos_score - neg_score, auto_neg_score, auto_neg_target)
```
这里使用了MarginRankingLoss作为损失函数,其中pos_score-neg_score表示正样本和负样本之间的相似度,auto_neg_score是自动生成的负样本和正样本之间的相似度,auto_neg_target是一个固定值-1,表示自动生成的负样本要与正样本距离更远。
3. 训练模型
最后,我们需要训练模型,更新模型参数。可以使用Adam等优化器来更新模型参数,具体实现可以参考以下代码:
```python
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
for epoch in range(100):
for pos_h, pos_t, pos_r, neg_h, neg_t, neg_r in dataloader:
pos_h = pos_h.cuda()
pos_t = pos_t.cuda()
pos_r = pos_r.cuda()
neg_h = neg_h.cuda()
neg_t = neg_t.cuda()
neg_r = neg_r.cuda()
optimizer.zero_grad()
pos_score, neg_score, auto_neg_score = model(pos_h, pos_t, pos_r, neg_h, neg_t, neg_r)
auto_neg_target = Variable(torch.Tensor([-1])).cuda()
loss = criterion(pos_score - neg_score, auto_neg_score, auto_neg_target)
loss.backward()
optimizer.step()
print('Epoch %d, loss %.4f' % (epoch, loss.item()))
```
这里使用了Adam优化器来更新模型参数,每个epoch遍历一次数据集,计算损失函数并进行反向传播和优化。
这样就完成了使用torch对知识表示学习模型RotatE进行修改,使之输出自对抗负采样损失而不保留实体关系嵌入向量的过程。
阅读全文