Pytorch CrossEntropyLoss ожидал long, но получил float.

Вопрос или проблема

  1. Вы провели исследование перед тем, как задать вопрос?

Да. Я провел много поисков в интернете, и другие сталкивались с похожими проблемами. Их решением было использовать .float() при передаче в функцию потерь. Это не сработало для меня. Вместо этого, независимо от того, делаю ли я .type(float.long) и т.д., я по-прежнему получаю ту же ошибку. Я предполагаю, что это связано с тем, как настроена/выводится моя сеть. Но я честно не знаю точно.

  1. Что вы сделали, чтобы попытаться решить проблему?

Я переписал свой код, проверил свою методологию с коллегой и также занимался программированием с «резиновым уточкой» без успеха.

  1. на каком языке?

Python 3.7.5, PyTorch 1.3.1

  1. короткий и понятный код?

Я не знаю, как правильно делиться данными, но, коротко говоря, входные данные имеют 66 признаков в пределах [-1,1] (используя PCA для разложения изображения MNIST)

import torch
import torch.nn as nn
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.hidden = nn.Linear(66, 99)
        self.output = nn.Linear(99, 10)

    def forward(self, x):
        x = self.hidden(x)
        x = self.output(x)
        x = x.sigmoid()
        return x

custom_dataset = CustomDataset()
train_loader = torch.utils.data.DataLoader(dataset=custom_dataset.MNIST_train,
                                           batch_size=64,
                                           shuffle=True)  # выдает (sample[], targets[]) -> (64x66, 64x1)
test_loader = torch.utils.data.DataLoader(dataset=custom_dataset.MNIST_test,
                                           batch_size=64,
                                           shuffle=True)  # выдает (sample[], targets[]) -> (64x66, 64x1)

n, target_size, num_epoc, learning_rate = 66, 1, 100, 0.001
model = Net()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

for i in range(num_epoc):
    for x in train_loader:
        # запустите модель и соберите потерю
        y = model.forward(x[0].float())
        loss = criterion(y, x[1].float())

        # выполнение оптимизации
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    print(str(i) + ': ' + str(loss))
  1. какая ошибка возникает?

Программа выдает следующую ошибку:

 Traceback (most recent call last):
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2019.2\helpers\pydev\pydevd.py", line 2060, in <module>
    main()
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2019.2\helpers\pydev\pydevd.py", line 2054, in main
    globals = debugger.run(setup['file'], None, None, is_module)
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2019.2\helpers\pydev\pydevd.py", line 1405, in run
    return self._exec(is_module, entry_point_fn, module_name, file, globals, locals)
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2019.2\helpers\pydev\pydevd.py", line 1412, in _exec
    pydev_imports.execfile(file, globals, locals)  # выполнить скрипт
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2019.2\helpers\pydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "C:/Users/User/Desktop/paper_recreation/PCA_CNN/CNN_DEBUG.py", line 109, in <module>
    loss = criterion(y, x[1].float())
  File "C:\Users\User\Anaconda3\envs\torch\lib\site-packages\torch\nn\modules\module.py", line 541, in __call__
    result = self.forward(*input, **kwargs)
  File "C:\Users\User\Anaconda3\envs\torch\lib\site-packages\torch\nn\modules\loss.py", line 916, in forward
    ignore_index=self.ignore_index, reduction=self.reduction)
  File "C:\Users\User\Anaconda3\envs\torch\lib\site-packages\torch\nn\functional.py", line 2009, in cross_entropy
    return nll_loss(log_softmax(input, 1), target, weight, None, ignore_index, None, reduction)
  File "C:\Users\User\Anaconda3\envs\torch\lib\site-packages\torch\nn\functional.py", line 1838, in nll_loss
    ret = torch._C._nn.nll_loss(input, target, weight, _Reduction.get_enum(reduction), ignore_index)
RuntimeError: Expected object of scalar type Long but got scalar type Float for argument #2 'target' in call to _thnn_nll_loss_forward
  1. другие моменты, которые помогают прояснить мою общую проблему:

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

pred = model(test).argmax(dim=1, keepdim=True)

прогноз должен быть значением от 0 до 9

Похоже, вам нужно передать 1D LongTensor для цели. В вашем примере кода вы передали значение с плавающей запятой. Я изменил ваш пример кода, чтобы он работал с набором данных MNIST.

import torch
import torch.nn as nn

import os
from torchvision.datasets import MNIST
from torchvision import transforms

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.hidden = nn.Linear(784, 99)
        self.output = nn.Linear(99, 10)

    def forward(self, x):
        x = self.hidden(x.view(x.size(0), -1))
        x = self.output(x)
        x = x.sigmoid()
        return x

train_loader = torch.utils.data.DataLoader(dataset=MNIST(os.getcwd()
                                          , train=True
                                          , transform=transforms.ToTensor()
                                          , download=True),
                                       batch_size=1,
                                       shuffle=True) 

n, target_size, num_epoc, learning_rate = 66, 1, 100, 0.001
model = Net()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

target_value = torch.LongTensor([1])

for i in range(num_epoc):
    for x in train_loader:
        # запустите модель и соберите потерю
        y = model.forward(x[0].float())
#         loss = criterion(y, x[1].float())
        loss = criterion(y, target_value)
        print(loss)
        break
    break

С версии PyTorch 1.10, nn.CrossEntropy() поддерживает так называемые “мягкие” (использующие вероятностные) метки, единственное, о чем вы должны заботиться, это то, что Input и Target должны иметь одинаковый размер.

Ответ или решение

Ошибка "expected long but got float" при использовании функции потерь CrossEntropyLoss в PyTorch обычно связана с тем, что данные, передаваемые на вход этой функции, имеют неправильный тип. Давайте подробнее разберем, как исправить эту проблему, основываясь на вашем коде и контексте.

Проблема с типами данных

CrossEntropyLoss ожидает, что целевые метки (targets) будут целыми числами (долгими числами — torch.LongTensor), а не вещественными числами (например, torch.FloatTensor). Ваша ошибка заключается в том, что вы передаете значения с типом Float, тогда как для целевых меток требуется тип Long.

Вот строки кода, которые вызывают ошибку:

loss = criterion(y, x[1].float())

Здесь x[1] представляет собой ваши целевые метки. Если вы хотите передать их в CrossEntropyLoss, то необходимо изменить их тип на Long, а также убедиться, что у вас нет ненужных преобразований типа в вашем коде.

Корректное получение целевых меток

Вам необходимо убедиться, что выходные данные вашего дата-загрузчика (DataLoader) содержат целевые метки в правильном формате. Если вы используете CustomDataset, проверьте, чтобы целевые метки были переданы как torch.LongTensor. Например:

# Предположим, что x[1] — ваши целевые метки
# Убедитесь, что они имеют тип Long
loss = criterion(y, x[1].long().squeeze())

Также убедитесь, что вы правильно обрабатываете ваши целевые метки, включая возможные преобразования из одномерного массива или векторного представления, если это необходимо.

Правильная настройка нейронной сети

Кроме того, обратите внимание на выход из вашей нейронной сети. Ваша последняя операция sigmoid не нужна, так как CrossEntropyLoss ожидает логиты (непосредственные выходные значения перед активацией softmax). Вместо этого используйте log_softmax:

def forward(self, x):
    x = self.hidden(x)
    x = self.output(x)  # Удалите .sigmoid()
    return x  # Верните логиты, не применяя активацию

Общая структура кода

Вот как должен выглядеть некоторый переписанный код:

import torch
import torch.nn as nn

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.hidden = nn.Linear(66, 99)
        self.output = nn.Linear(99, 10)

    def forward(self, x):
        x = self.hidden(x)
        x = self.output(x)  # Никакого сигмоида
        return x  # Возвращаем логиты

# Пример загрузки данных с правильной обработкой target
for i in range(num_epoc):
    for x in train_loader:
        y = model(x[0].float())
        loss = criterion(y, x[1].long().squeeze())  # Корректная передача целевых меток
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        print(f'Epoch [{i}], Loss: {loss.item()}')

Заключение

Проблема, с которой вы столкнулись, является распространенной среди разработчиков, использующих Pytorch, и может решить разные аспекты настройки сети и подготовки данных. Убедитесь, что ваши целевые метки имеют правильный тип, и что выходные данные вашей модели соответствуют требованиям функции CrossEntropyLoss. Основное — это внимательно проверять, с какими типами данных вы работаете на каждом этапе вашего кода.

Оцените материал
Добавить комментарий

Капча загружается...