Je suis sur un projet utilisant des données d'accélération pour prédire certaines activités. Mais j'ai des problèmes sur le calcul des pertes. J'utilise CrossEntropyLoss
pour cela.
Les données sont utilisées pour cela comme ci-dessous J'utilise les 4 premières données de chaque ligne pour prédire l'index comme la dernière de chaque ligne.
1 84 84 81 4
81 85 85 80 1
81 82 84 80 1
1 85 84 2 0
81 85 82 80 1
81 82 84 80 1
81 25 84 80 5
Les messages d'erreur sont comme ci-dessous.
minoh@minoh-VirtualBox:~/cow$ python lec5.py
Traceback (most recent call last):
File "lec5.py", line 97, in <module>
train(Epoch)
File "lec5.py", line 74, in train
loss = criterion(y_pred, labels)
File "/home/minoh/anaconda3/lib/python3.6/site-packages/torch/nn/modules/module.py", line 357, in __call__
result = self.forward(*input, **kwargs)
File "/home/minoh/anaconda3/lib/python3.6/site-packages/torch/nn/modules/loss.py", line 679, in forward
self.ignore_index, self.reduce)
File "/home/minoh/anaconda3/lib/python3.6/site-packages/torch/nn/functional.py", line 1161, in cross_entropy
return nll_loss(log_softmax(input, 1), target, weight, size_average, ignore_index, reduce)
File "/home/minoh/anaconda3/lib/python3.6/site-packages/torch/nn/functional.py", line 1052, in nll_loss
return torch._C._nn.nll_loss(input, target, weight, size_average, ignore_index, reduce)
RuntimeError: multi-target not supported at /opt/conda/conda-bld/pytorch_1518243271935/work/torch/lib/THNN/generic/ClassNLLCriterion.c:22
Mon code est basé sur le pytorch de Sung Kim
import numpy as np
import torch
from torch.autograd import Variable
import torch.nn.functional as F
from torch.utils.data import Dataset, DataLoader
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
class CowDataset(Dataset):
def __init__(self):
xy_str = np.loadtxt('cow_test', delimiter = ' ', dtype = np.str)
xy = xy_str.astype(np.float32)
xy_int = xy_str.astype(np.int)
self.len = xy.shape[0]
self.x_data = torch.from_numpy(xy[:, 0:4])
self.y_data = torch.from_numpy(xy_int[:, [4]])
def __getitem__(self, index):
return self.x_data[index], self.y_data[index]
def __len__(self):
return self.len
dataset = CowDataset()
train_loader = DataLoader(dataset = dataset, batch_size = 32, shuffle = True)
class CowTestset(Dataset):
def __init__(self):
xy_str = np.loadtxt('cow_test2', delimiter = ' ', dtype =np.str)
xy = xy_str.astype(np.float32)
xy_int = xy_str.astype(np.int)
self.len = xy.shape[0]
self.x_data = torch.from_numpy(xy[:, 0:4])
self.y_data = torch.from_numpy(xy_int[:, [4]])
def __getitem__(self, index):
return self.x_data[index], self.y_data[index]
def __len__(self):
return self.len
testset = CowTestset()
test_loader = DataLoader(dataset = testset, batch_size = 32, shuffle = True)
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
self.l1 = torch.nn.Linear(4,5)
self.l2 = torch.nn.Linear(5,7)
self.l3 = torch.nn.Linear(7,6)
self.sigmoid = torch.nn.Sigmoid()
def forward(self, x):
out1 = self.sigmoid(self.l1(x))
out2 = self.sigmoid(self.l2(out1))
y_pred = self.sigmoid(self.l3(out2))
return y_pred
model = Model()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr = 0.1, momentum = 0.5)
def train(Epoch):
model.train()
for batch_idx, (inputs, labels) in enumerate(train_loader):
inputs, labels = Variable(inputs), Variable(labels)
optimizer.zero_grad()
y_pred = model(inputs)
loss = criterion(y_pred, labels)
loss.backward()
optimizer.step()
if batch_idx % 10 == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
Epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.data[0]))
def test():
model.eval()
test_loss = 0
correct = 0
for data, target in test_loader:
data, target = Variable(data, volatile = True), Variable(target)
print(target)
output = model(data)
test_loss += criterion(output, target).data[0]
pred = output.data.max(1, keepdim = True)[1]
correct += pred.eq(target.data.view_as(pred)).cpu().sum()
test_loss /= len(test_loader.dataset)
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(test_loss, correct, len(test_loader.dataset), 100.* correct / len(test_loader.dataset)))
for Epoch in range(1,7):
train(Epoch)
test()
D'accord. J'ai donc reproduit votre problème et après quelques recherches et lecture de l'API de CrossEntropyLoss()
, j'ai trouvé que c'est parce que vous avez une mauvaise dimension d'étiquette.
Documents officiels de CrossEntropyLoss ici. Et vous pouvez voir
Entrée: (N, C) où C = nombre de classes
Cible: (N) où chaque valeur est 0≤cibles [i] ≤C − 1
Alors qu'ici, dans votre fonction criterion()
, vous avez une entrée batchSize x 7
Et une étiquette batchSize x 1
. Le point déroutant est, disons que votre batchSize est 10, un tenseur 10x1 ne peut pas être considéré comme un tenseur de taille 10, ce à quoi la fonction de perte s'attend. Vous devez faire explicitement la conversion de taille.
Solution :
Ajoutez labels = labels.squeeze_()
avant d'appeler loss = criterion(y_pred, labels)
et faites la même chose dans votre code de test. La fonction squeeze_()
supprime les dimensions de taille 1 en place. Vous avez donc maintenant une étiquette de taille batchSize
-.