Browse Source

implement bpr and bpr_max loss

RNN
mohamad maheri 2 years ago
parent
commit
dca86acb3a
2 changed files with 61 additions and 20 deletions
  1. 49
    12
      models.py
  2. 12
    8
      trainer.py

+ 49
- 12
models.py View File



return x.view(size[0], 1, 1, self.out_size) return x.view(size[0], 1, 1, self.out_size)



class EmbeddingLearner(nn.Module): class EmbeddingLearner(nn.Module):
def __init__(self): def __init__(self):
super(EmbeddingLearner, self).__init__() super(EmbeddingLearner, self).__init__()
n_score = score[:, pos_num:] n_score = score[:, pos_num:]
return p_score, n_score return p_score, n_score


def bpr_loss(p_scores, n_values):
p1 = p_scores[:,0,None]
p2 = p_scores[:,1,None]
def bpr_loss(p_scores, n_values,device):
ratio = int(n_values.shape[1] / p_scores.shape[1])
temp_pvalues = torch.tensor([]).cuda(device=device)
for i in range(p_scores.shape[1]):
temp_pvalues = torch.cat((temp_pvalues, p_scores[:, i, None].expand(-1, ratio)), dim=1)

d = torch.sub(temp_pvalues,n_values)
t = F.logsigmoid(d)
loss = -1 * (1.0/n_values.shape[1]) * t.sum(dim=1)
loss = loss.sum(dim=0)
return loss

def bpr_max_loss(p_scores, n_values,device):
s = F.softmax(n_values,dim=1)
ratio = int(n_values.shape[1] / p_scores.shape[1])
temp_pvalues = torch.tensor([]).cuda(device=device)
for i in range(p_scores.shape[1]):
temp_pvalues = torch.cat((temp_pvalues,p_scores[:,i,None].expand(-1,ratio)),dim=1)

d = torch.sigmoid(torch.sub(temp_pvalues,n_values))
t = torch.mul(s,d)
loss = -1 * torch.log(t.sum(dim=1))
loss = loss.sum()
return loss

def top_loss(p_scores, n_values):
p1 = p_scores[:, 0, None]
p2 = p_scores[:, 1, None]


num_neg = n_values.shape[1] num_neg = n_values.shape[1]
half_index = int(num_neg/2)
half_index = int(num_neg / 2)

d1 = torch.sub(p1, n_values[:, 0:half_index])
d2 = torch.sub(p2, n_values[:, half_index:])
# print("d1 shape:",d1.shape)


d1 = torch.sub(p1,n_values[:,0:half_index])
d2 = torch.sub(p2,n_values[:,half_index:])
# print("add shape:",torch.cat((d1,d2),dim=1).shape)
t1 = torch.sigmoid(torch.cat((d1,d2),dim=1))
# print("t1 shape:",t1.shape)
t2 = torch.sigmoid(torch.pow(n_values,2))
# print("t2 shape:",t2.shape)


t = F.logsigmoid(torch.add(d1,d2))
t3 = torch.add(t1,t2)
# print("t3 shape:",t3.shape)


loss = (-1) * t.sum() / n_values.shape[1]
loss = t3.sum()
# print(loss.shape)
# loss /= (n_values.shape[1] * p_scores.shape[0])
loss /= n_values.shape[1]
return loss return loss



class MetaTL(nn.Module): class MetaTL(nn.Module):
def __init__(self, itemnum, parameter): def __init__(self, itemnum, parameter):
super(MetaTL, self).__init__() super(MetaTL, self).__init__()
num_hidden2=200, out_size=100, dropout_p=0) num_hidden2=200, out_size=100, dropout_p=0)


self.embedding_learner = EmbeddingLearner() self.embedding_learner = EmbeddingLearner()
self.loss_func = nn.MarginRankingLoss(self.margin)
# self.loss_func = nn.MarginRankingLoss(self.margin)
self.loss_func = bpr_loss


self.rel_q_sharing = dict() self.rel_q_sharing = dict()




# sorted,indecies = torch.sort(n_score, descending=True,dim=1) # sorted,indecies = torch.sort(n_score, descending=True,dim=1)
# n_values = sorted[:,0:p_score.shape[1]] # n_values = sorted[:,0:p_score.shape[1]]
n_values = n_score
loss = bpr_loss(p_score,n_values)

# loss = self.loss_func(p_score, n_values, y) # loss = self.loss_func(p_score, n_values, y)
loss = self.loss_func(p_score,n_score,device=self.device)
loss.backward(retain_graph=True) loss.backward(retain_graph=True)


grad_meta = rel.grad grad_meta = rel.grad

+ 12
- 8
trainer.py View File



self.optimizer = torch.optim.Adam(self.MetaTL.parameters(), self.learning_rate) self.optimizer = torch.optim.Adam(self.MetaTL.parameters(), self.learning_rate)


def rank_predict(self, data, x, ranks): def rank_predict(self, data, x, ranks):
# query_idx is the idx of positive score # query_idx is the idx of positive score
query_idx = x.shape[0] - 1 query_idx = x.shape[0] - 1
self.optimizer.zero_grad() self.optimizer.zero_grad()
p_score, n_score = self.MetaTL(task, iseval, curr_rel) p_score, n_score = self.MetaTL(task, iseval, curr_rel)
y = torch.Tensor([1]).to(self.device) y = torch.Tensor([1]).to(self.device)
loss = self.MetaTL.loss_func(p_score, n_score, y)
loss = self.MetaTL.loss_func(p_score, n_score,self.device)
loss.backward() loss.backward()
self.optimizer.step() self.optimizer.step()
elif curr_rel != '': elif curr_rel != '':
p_score, n_score = self.MetaTL(task, iseval, curr_rel) p_score, n_score = self.MetaTL(task, iseval, curr_rel)
y = torch.Tensor([1]).to(self.device) y = torch.Tensor([1]).to(self.device)
loss = self.MetaTL.loss_func(p_score, n_score, y)
loss = self.MetaTL.loss_func(p_score, n_score,self.device)
return loss, p_score, n_score return loss, p_score, n_score


def train(self): def train(self):
# sample one batch from data_loader # sample one batch from data_loader
train_task, curr_rel = self.train_data_loader.next_batch() train_task, curr_rel = self.train_data_loader.next_batch()
loss, _, _ = self.do_one_step(train_task, iseval=False, curr_rel=curr_rel) loss, _, _ = self.do_one_step(train_task, iseval=False, curr_rel=curr_rel)
# print the loss on specific epoch
# if e % self.print_epoch == 0:
# loss_num = loss.item()
# print("Epoch: {}\tLoss: {:.4f}".format(e, loss_num))

# do evaluation on specific epoch # do evaluation on specific epoch
if e % self.eval_epoch == 0 and e != 0: if e % self.eval_epoch == 0 and e != 0:
loss_num = loss.item()
print("Epoch: {}\tLoss: {:.4f}".format(e, loss_num))

print('Epoch {} Validating...'.format(e)) print('Epoch {} Validating...'.format(e))
valid_data = self.eval(istest=False, epoch=e) valid_data = self.eval(istest=False, epoch=e)




t = 0 t = 0
temp = dict() temp = dict()
total_loss = 0
while True: while True:
# sample all the eval tasks # sample all the eval tasks
eval_task, curr_rel = data_loader.next_one_on_eval() eval_task, curr_rel = data_loader.next_one_on_eval()
break break
t += 1 t += 1


_, p_score, n_score = self.do_one_step(eval_task, iseval=True, curr_rel=curr_rel)
loss, p_score, n_score = self.do_one_step(eval_task, iseval=True, curr_rel=curr_rel)
total_loss += loss


x = torch.cat([n_score, p_score], 1).squeeze() x = torch.cat([n_score, p_score], 1).squeeze()




if istest: if istest:
print("TEST: \t test_loss: ",total_loss.item())
print("TEST: \tMRR: {:.3f}\tNDCG@10: {:.3f}\tNDCG@5: {:.3f}\tNDCG@1: {:.3f}\tHits@10: {:.3f}\tHits@5: {:.3f}\tHits@1: {:.3f}\r".format( print("TEST: \tMRR: {:.3f}\tNDCG@10: {:.3f}\tNDCG@5: {:.3f}\tNDCG@1: {:.3f}\tHits@10: {:.3f}\tHits@5: {:.3f}\tHits@1: {:.3f}\r".format(
temp['MRR'], temp['NDCG@10'], temp['NDCG@5'], temp['NDCG@1'], temp['Hits@10'], temp['Hits@5'], temp['Hits@1']),"\n") temp['MRR'], temp['NDCG@10'], temp['NDCG@5'], temp['NDCG@1'], temp['Hits@10'], temp['Hits@5'], temp['Hits@1']),"\n")
with open('results.txt', 'a') as f: with open('results.txt', 'a') as f:
f.writelines("TEST: \tMRR: {:.3f}\tNDCG@10: {:.3f}\tNDCG@5: {:.3f}\tNDCG@1: {:.3f}\tHits@10: {:.3f}\tHits@5: {:.3f}\tHits@1: {:.3f}\r\n\n".format( f.writelines("TEST: \tMRR: {:.3f}\tNDCG@10: {:.3f}\tNDCG@5: {:.3f}\tNDCG@1: {:.3f}\tHits@10: {:.3f}\tHits@5: {:.3f}\tHits@1: {:.3f}\r\n\n".format(
temp['MRR'], temp['NDCG@10'], temp['NDCG@5'], temp['NDCG@1'], temp['Hits@10'], temp['Hits@5'], temp['Hits@1'])) temp['MRR'], temp['NDCG@10'], temp['NDCG@5'], temp['NDCG@1'], temp['Hits@10'], temp['Hits@5'], temp['Hits@1']))
else: else:
print("VALID: \t validation_loss: ", total_loss.item())
print("VALID: \tMRR: {:.3f}\tNDCG@10: {:.3f}\tNDCG@5: {:.3f}\tNDCG@1: {:.3f}\tHits@10: {:.3f}\tHits@5: {:.3f}\tHits@1: {:.3f}\r".format( print("VALID: \tMRR: {:.3f}\tNDCG@10: {:.3f}\tNDCG@5: {:.3f}\tNDCG@1: {:.3f}\tHits@10: {:.3f}\tHits@5: {:.3f}\tHits@1: {:.3f}\r".format(
temp['MRR'], temp['NDCG@10'], temp['NDCG@5'], temp['NDCG@1'], temp['Hits@10'], temp['Hits@5'], temp['Hits@1'])) temp['MRR'], temp['NDCG@10'], temp['NDCG@5'], temp['NDCG@1'], temp['Hits@10'], temp['Hits@5'], temp['Hits@1']))
with open("results.txt",'a') as f: with open("results.txt",'a') as f:

Loading…
Cancel
Save