python - Pytorch 交叉熵输入维度
问题描述
我正在尝试使用 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()
是因为 Huggingface 的源代码在BertForSequenceClassification
这里使用完全相同的方式来计算损失。但我得到这个错误:
/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,∗),与输入的形状相同
我应该如何使我的标签与模型输出的形状相同?我觉得我错过了一些巨大的东西,但我找不到它。
解决方案
几点观察:
- 您引用的代码使用
CrossEntropyLoss
但您正在使用BCELoss
. CrossEntropyLoss
采用预测 logits (size: (N,D)) 和目标标签 (size: (N,)) 而BCELoss
采用 p(y=1|x) (size: (N,)) 和目标标签 (size: (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
应该也可以工作,因为它也可以用于二进制标签。
推荐阅读
- javascript - 如何测试是否在componentDidMount内部调用了方法?
- python - ValueError:无法为具有形状“z”的张量“y”提供形状“x”的值
- javascript - 我的谷歌云功能存在承诺问题
- dynamic - 如何根据表单字段动态过滤 PXSelect 属性
- javascript - 为嵌套数组中的值过滤数组数组
- postgresql - PostgreSQL 查询未在应用服务器关闭时终止
- angular - 路由到下一页时上一页图像清除延迟(Ionic 4)
- ruby-on-rails - 如何在引导模式中创建和编辑书评
- node.js - 如何从 Azure Key Vault 节点检索机密
- dart - Flutter Text To Speech:随后用不同的 SpeechRates 说出几个字符串