Входные размеры кросс-энтропии Pytorch

Я пытаюсь разработать двоичный классификатор с помощью BertModel и Pytorch от Huggingface. Модуль классификатора выглядит примерно так:

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 здесь который использует точно такой же способ для вычисления потерь. Но я получаю такую ​​ошибку:

/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)

Что-то не так с моими этикетками? или результат моей модели? Я действительно застрял здесь. В документации для BCELoss Pytorch говорится:

Входные данные: (N, *), где * означает любое количество дополнительных измерений
Цель: (N, *), та же форма, что и входные

Как мне сделать мои метки той же формы, что и выходная модель? Я чувствую, что мне не хватает чего-то огромного, но я не могу этого найти.


person P.Alipoor    schedule 03.04.2020    source источник


Ответы (1)


Несколько наблюдений:

  • Код, на который вы ссылаетесь, использует CrossEntropyLoss, но вы используете BCELoss.
  • CrossEntropyLoss принимает логиты прогнозирования (размер: (N, D)) и целевые метки (размер: (N,)), тогда как BCELoss принимает p (y = 1 | x) (размер: (N,)) и целевые метки (размер: ( N,)), поскольку p (y = 0 | x) может быть вычислено из p (y = 1 | x)
  • CrossEntropyLoss ожидает логитов, то есть 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), и передать его функции потерь. Из кода видно, что вы передаете логит-значения, а не значения вероятности, поэтому вам также может потребоваться вычислить sigmoid (model_output), если вы хотите использовать BCELoss, или, в качестве альтернативы, вы можете использовать BCEWithLogitsLoss.

Другой альтернативой является изменение потерь на CrossEntropyLoss, что тоже должно работать, поскольку оно может работать и для двоичных меток.

person Umang Gupta    schedule 03.04.2020
comment
Ой! Спасибо. Оба решили мою проблему. За исключением того, что результат моей модели не p (y = 1 | x) и p (y = 0 | x), и я должен использовать для этого softmax! - person P.Alipoor; 03.04.2020
comment
Да извините, я понял немного поздно. Я обновил ответ, чтобы отразить все три сценария --- с использованием CE, BCE и BCE logits потери - person Umang Gupta; 03.04.2020