【问题标题】:Pytorch cross entropy input dimensionsPytorch 交叉熵输入维度
【发布时间】:2020-07-16 01:43:01
【问题描述】:

我正在尝试使用 Huggingface 的 BertModel 和 Pytorch 开发一个二元分类器。 分类器模块是这样的:

class SSTClassifierModel(nn.Module):

  def __init__(self, num_classes = 2, hidden_size = 768):
    super(SSTClassifierModel, self).__init__()
    self.number_of_classes = num_classes
    self.dropout = nn.Dropout(0.01)
    self.hidden_size = hidden_size
    self.bert = BertModel.from_pretrained('bert-base-uncased')
    self.classifier = nn.Linear(hidden_size, num_classes)

  def forward(self, input_ids, att_masks,token_type_ids,  labels):
    _, embedding = self.bert(input_ids, token_type_ids, att_masks)
    output = self.classifier(self.dropout(embedding))
    return output

我训练模型的方式如下:

loss_function = BCELoss()
model.train()
for epoch in range(NO_OF_EPOCHS):
  for step, batch in enumerate(train_dataloader):
        input_ids = batch[0].to(device)
        input_mask = batch[1].to(device)
        token_type_ids = batch[2].to(device)
        labels = batch[3].to(device)
        # assuming batch size = 3, labels is something like:
        # tensor([[0],[1],[1]])
        model.zero_grad()        
        model_output = model(input_ids,  
                             input_mask, 
                             token_type_ids,
                             labels)
        # model output is something like: (with batch size = 3) 
        # tensor([[ 0.3566, -0.0333],
                 #[ 0.1154,  0.2842],
                 #[-0.0016,  0.3767]], grad_fn=<AddmmBackward>)

        loss = loss_function(model_output.view(-1,2) , labels.view(-1))

我正在做.view()s 因为Huggingface 的BertForSequenceClassification here 的源代码使用完全相同的方法来计算损失。但我得到这个错误:

/usr/local/lib/python3.6/dist-packages/torch/nn/functional.py in binary_cross_entropy(input, target, weight, size_average, reduce, reduction)
   2068     if input.numel() != target.numel():
   2069         raise ValueError("Target and input must have the same number of elements. target nelement ({}) "
-> 2070                          "!= input nelement ({})".format(target.numel(), input.numel()))
   2071 
   2072     if weight is not None:

ValueError: Target and input must have the same number of elements. target nelement (3) != input nelement (6)

我的标签有问题吗?还是我模型的输出?我真的被困在这里了。 Pytorch 的 BCELoss 的文档说:

输入:(N,∗) 其中 ∗ 表示任意数量的附加维度
目标:(N,∗),与输入的形状相同

我应该如何使我的标签与模型输出的形状相同?我觉得我错过了一些巨大的东西,但我找不到它。

【问题讨论】:

    标签: python pytorch python-3.7 cross-entropy huggingface-transformers


    【解决方案1】:

    几个观察:

    • 您引用的代码使用CrossEntropyLoss,但您使用的是BCELoss
    • CrossEntropyLoss 采用预测 logits(大小:(N,D))和目标标签(大小:(N,)),而 BCELoss 采用 p(y=1|x)(大小:(N,))和目标标签(size: (N,)) 因为 p(y=0|x) 可以从 p(y=1|x) 计算得到
    • CrossEntropyLoss 期望 logits,即 BCELoss 期望概率值

    解决方案:

    由于您传递了 (N,2) 张量,因此会出错。你只需要传递p(y=1|x),因此你可以这样做

    loss = loss_function(model_output.view(-1,2)[:,1] , labels.view(-1))

    上面我假设第二个值是 p(y=1|x)。

    一种更简洁的方法是让模型只输出一个值,即 p(y=1|x) 并将其传递给损失函数。从代码看来,您传递的是 logit 值而不是概率值,因此如果您想使用 BCELoss,您可能还需要计算 sigmoid (model_output),或者您也可以使用 BCEWithLogitsLoss

    另一种选择是将损失更改为CrossEntropyLoss,这也应该适用,因为它也适用于二进制标签。

    【讨论】:

    • 哦!谢谢你。两者都解决了我的问题。除了我的模型的输出不是 p(y=1|x) 和 p(y=0|x) 之外,我应该为此使用 softmax!
    • 是的,抱歉,我意识到有点晚了。我更新了答案以反映所有三种情况——使用 CE、BCE 和 BCElogits 损失
    猜你喜欢
    • 2020-08-13
    • 1970-01-01
    • 2020-12-18
    • 2021-08-25
    • 2021-10-24
    • 1970-01-01
    • 2021-06-06
    • 2019-08-08
    • 2018-04-14
    相关资源
    最近更新 更多