为什么不能对多标签使用交叉熵损失?

时间:2020-09-30 13:15:33

标签: python machine-learning nlp pytorch huggingface-transformers

我正在微调BERT模型以适应自然问题数据集中的长答案任务。我正在像SQuAD模型一样训练模型(预测开始和结束标记)。

我使用Huggingface和PyTorch。

因此目标和标签的形状/大小为 [batch,2] 。我的问题是我无法输入“多目标”,我认为这是指最后一个形状是 2

RuntimeError:/pytorch/aten/src/THCUNN/generic/ClassNLLCriterion.cu:18

不支持多目标

我应该选择另一个损失函数还是有另一种绕过此问题的方法?

我正在使用的这段代码:

        <InputText disabled="@componentStates[0]" @bind-Value="@someModel.value1" />
        <button @onclick="() => SwitchComponentDisabledState(0)">@SwitchToState(0)</button>
        <InputText disabled="@componentStates[1]" @bind-Value="@someModel.value" />
        <button @onclick="() => SwitchComponentDisabledState(1)">@SwitchToState(1)</button>

@code {

    bool[] componentStates = new bool[] { false, false };

    protected string SwitchToState(int compIndex) => componentStates[compIndex] ? "Enable" : "Disable";
    
    protected void SwitchComponentDisabledState(int componentIndex)=> componentStates[componentIndex] = !componentStates[componentIndex];

}


def loss_fn(preds, targets):
    return nn.CrossEntropyLoss()(preds,labels)

目标属性为: torch.int64 [3,2]

预测属性为: torch.float32 [3,2]

已解决-这是我的解决方法

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)

        # Concatenate into a "label"
        preds = torch.cat((start_logits, end_logits), -1)

        # Calculate loss
        loss = self.loss_fn(
            preds = preds, 
            labels = labels)

        return loss, preds

基本上,我正在分割logit(只是不附加它们)和标签。然后,我对它们两者进行交叉熵损失,最后取两者之间的平均损失。希望这能给您一个解决自己的问题的想法!

1 个答案:

答案 0 :(得分:2)

您不应为CrossEntropyLoss提供1-hot向量,而应直接给标签

目标:(N)其中每个值是0≤targets[i]≤C-1,或者在K维损失的情况下具有K≥1的(N,d_1,d_2,...,d_K)。

您可以查看文档来重现错误:

>>> 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:需要一维目标张量,不支持多目标

使用nn.BCELoss和logit作为输入,请参见以下示例: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>)