为什么不能在多标签分类中使用交叉熵损失?

我正在对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>)

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注