原代码
import torch
import torch.nn.functional as F
from torch import nn
logloss = nn.BCEWithLogitsLoss()
def cosine_loss(a, v, y):
d = nn.functional.cosine_similarity(a, v)
loss = logloss(d.unsqueeze(1), y)
return loss
手动调整了loss的计算方式
def weighted_logloss(pred, target, pos_weight=1.01, neg_weight=0.99):
pos_mask = (target == 1).float()
neg_mask = (target == 0).float()
pos_loss = -pos_mask * torch.log(pred) * pos_weight
neg_loss = -neg_mask * torch.log(1 - pred) * neg_weight
return pos_loss + neg_loss
def cosine_loss(a, v, y, pos_weight=1.01, neg_weight=0.99):
d = F.cosine_similarity(a, v)
d = d.unsqueeze(1)
loss = weighted_logloss(d, y, pos_weight, neg_weight)
return loss
报错
RuntimeError: grad can be implicitly created only for scalar outputs
原因
第一个 cosine_loss 函数
- cosine_similarity(a, v) 计算得到一个形状为 [batch_size] 的张量 d。
- d.unsqueeze(1) 将 d 的形状从 [batch_size] 变为 [batch_size, 1]。
- logloss(d.unsqueeze(1), y) 使用二值交叉熵损失(带logits)来计算损失,这个损失的形状是一个标量,即 [1]。
- 返回的 loss 是一个标量。
第二个 cosine_loss 函数
- cosine_similarity(a, v) 计算得到一个形状为 [batch_size] 的张量 d。
- d.unsqueeze(1) 将 d 的形状从 [batch_size] 变为 [batch_size, 1]。
- weighted_logloss(d, y, pos_weight, neg_weight) 计算损失,这个损失的形状为 [batch_size, 1]。
- 返回的 loss 的形状为 [batch_size, 1]。
解决方式
在第二个损失函数返回时使用.mean()使其变成标量
def cosine_loss(a, v, y, pos_weight=1.01, neg_weight=0.99):
d = F.cosine_similarity(a, v)
d = d.unsqueeze(1)
loss = weighted_logloss(d, y, pos_weight, neg_weight)
return loss.mean()