P.A*_*oor 0 python cross-entropy pytorch python-3.7 huggingface-transformers
我正在尝试使用 Huggingface 的 BertModel 和 Pytorch 开发一个二元分类器。\n分类器模块是这样的:
\n\nclass SSTClassifierModel(nn.Module):\n\n def __init__(self, num_classes = 2, hidden_size = 768):\n super(SSTClassifierModel, self).__init__()\n self.number_of_classes = num_classes\n self.dropout = nn.Dropout(0.01)\n self.hidden_size = hidden_size\n self.bert = BertModel.from_pretrained(\'bert-base-uncased\')\n self.classifier = nn.Linear(hidden_size, num_classes)\n\n def forward(self, input_ids, att_masks,token_type_ids, labels):\n _, embedding = self.bert(input_ids, token_type_ids, att_masks)\n output = self.classifier(self.dropout(embedding))\n return output\n
Run Code Online (Sandbox Code Playgroud)\n\n我训练模型的方式如下:
\n\nloss_function = BCELoss()\nmodel.train()\nfor epoch in range(NO_OF_EPOCHS):\n for step, batch in enumerate(train_dataloader):\n input_ids = batch[0].to(device)\n input_mask = batch[1].to(device)\n token_type_ids = batch[2].to(device)\n labels = batch[3].to(device)\n # assuming batch size = 3, labels is something like:\n # tensor([[0],[1],[1]])\n model.zero_grad() \n model_output = model(input_ids, \n input_mask, \n token_type_ids,\n labels)\n # model output is something like: (with batch size = 3) \n # tensor([[ 0.3566, -0.0333],\n #[ 0.1154, 0.2842],\n #[-0.0016, 0.3767]], grad_fn=<AddmmBackward>)\n\n loss = loss_function(model_output.view(-1,2) , labels.view(-1))\n
Run Code Online (Sandbox Code Playgroud)\n\n我之所以这样做是因为这里的.view()
Huggingface 源代码使用完全相同的方式来计算损失。但我收到这个错误:BertForSequenceClassification
/usr/local/lib/python3.6/dist-packages/torch/nn/functional.py in binary_cross_entropy(input, target, weight, size_average, reduce, reduction)\n 2068 if input.numel() != target.numel():\n 2069 raise ValueError("Target and input must have the same number of elements. target nelement ({}) "\n-> 2070 "!= input nelement ({})".format(target.numel(), input.numel()))\n 2071 \n 2072 if weight is not None:\n\nValueError: Target and input must have the same number of elements. target nelement (3) != input nelement (6)\n
Run Code Online (Sandbox Code Playgroud)\n\n我的标签有问题吗?或者我的模型的输出?我真的被困在这里了。Pytorch 的 BCELoss 文档说:
\n\n输入:(N,\xe2\x88\x97),其中 \xe2\x88\x97 表示任意数量的附加维度
\n目标:(N,\xe2\x88\x97),与输入相同的形状
我应该如何使标签与模型输出的形状相同?我觉得我错过了一些巨大的东西,但我找不到它。
\n一些观察:
CrossEntropyLoss
但您正在使用BCELoss
.CrossEntropyLoss
采用预测逻辑(大小:(N,D))和目标标签(大小:(N,)),而BCELoss
采用 p(y = 1 | x)(大小:(N,))和目标标签(大小:(N,) )) 因为 p(y=0|x) 可以根据 p(y=1|x) 计算CrossEntropyLoss
期望 logits ie 而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 值而不是概率值,因此您可能还需要计算sigmoid (model_output)
是否要使用BCELoss
或可以使用BCEWithLogitsLoss
。
另一种选择是将损失更改为CrossEntropyLoss
也应该有效,因为它也适用于二进制标签。