我正在对BERT模型进行微调,用于Natural Questions数据集中的长答案任务。我的训练方式与SQuAD模型类似(预测开始和结束标记)。
我使用的是Huggingface和PyTorch。
因此,目标和标签的形状/大小为[batch, 2]。我的问题是我无法输入“多目标”,我认为这是指最后的形状是2。
RuntimeError: multi-target not supported at /pytorch/aten/src/THCUNN/generic/ClassNLLCriterion.cu:18
我应该选择另一个损失函数,还是有其他方法可以绕过这个问题?
我使用的代码如下:
def loss_fn(preds, targets): return nn.CrossEntropyLoss()(preds,labels)
class DecoderModel(nn.Module): def __init__(self, model_args, encoder_config, loss_fn): super(DecoderModel, self).__init__() # ... def forward(self, pooled_output, labels): pooled_output = self.dropout(pooled_output) logits = self.linear(pooled_output) start_logits, end_logits = logits.split(1, dim = -1) start_logit = torch.squeeze(start_logits, axis=-1) end_logit = torch.squeeze(end_logits, axis=-1) # 拼接成“标签” preds = torch.cat((start_logits, end_logits), -1) # 计算损失 loss = self.loss_fn( preds = preds, labels = labels) return loss, preds
目标的属性是:torch.int64 & [3,2]
预测的属性是:torch.float32 & [3,2]
已解决 – 这是我的解决方案
def loss_fn(preds:list, labels): start_token_labels, end_token_labels = labels.split(1, dim = -1) start_token_labels = start_token_labels.squeeze(-1) end_token_labels = end_token_labels.squeeze(-1) print('*'*50) print(preds[0].shape) # preds [0] 和 [1] 具有相同的形状和数据类型 print(preds[0].dtype) # preds [0] 和 [1] 具有相同的形状和数据类型 print(start_token_labels.shape) # labels [0] 和 [1] 具有相同的形状和数据类型 print(start_token_labels.dtype) # labels [0] 和 [1] 具有相同的形状和数据类型 start_loss = nn.CrossEntropyLoss()(preds[0], start_token_labels) end_loss = nn.CrossEntropyLoss()(preds[1], end_token_labels) avg_loss = (start_loss + end_loss) / 2 return avg_loss
基本上,我是分开处理logits(不拼接它们)和标签。然后对它们都进行交叉熵损失计算,最后取两个损失的平均值。希望这能给你解决自己问题的一些启示!
回答:
你不应该将1-hot向量传递给CrossEntropyLoss
,而是直接传递标签
目标: (N) 其中每个值为 0≤targets[i]≤C−1 ,或者在K维损失的情况下为 (N, d_1, d_2, …, d_K) 且 K≥1 。
你可以通过查看文档来重现你的错误:
>>> loss = nn.CrossEntropyLoss()>>> input = torch.randn(3, 5, requires_grad=True)>>> target = torch.empty(3, dtype=torch.long).random_(5)>>> output = loss(input, target)>>> output.backward()
但是如果你将target
改为target = torch.empty((3, 5), dtype=torch.long).random_(5)
,你会得到错误:
RuntimeError: 1D target tensor expected, multi-target not supported
改用nn.BCELoss
,并将logits作为输入,查看这个例子:https://discuss.pytorch.org/t/multi-label-classification-in-pytorch/905/41
>>> nn.BCELoss()(torch.softmax(input, axis=1), torch.softmax(target.float(), axis=1))>>> tensor(0.6376, grad_fn=<BinaryCrossEntropyBackward>)