Pytorch LSTM: целевое измерение при расчете перекрестных энтропийных потерь - PullRequest
0 голосов
/ 24 ноября 2018

Я пытался получить LSTM (за LSTM следовал линейный слой в пользовательской модели), работая в Pytorch, но получал следующую ошибку при расчете потерь:

Assertion cur_target >= 0 && cur_target < n_classes' failed.

Я определил функцию потерь с помощью:

criterion = nn.CrossEntropyLoss()

, а затем вызвал с помощью

loss += criterion(output, target)

Я дал цель с размерами [sequence_length, number_of_classes], и выводразмеры [sequence_length, 1, number_of_classes].

Примеры, за которыми я следовал, казалось, делали то же самое, но это отличалось на документах Pytorch о кросс-энтропийной потере.

В документах говорится, что цель должна иметь размерность (N), где каждое значение равно 0 ≤ target [i] ≤ C − 1, а C - количество классов.Я изменил цель, чтобы быть в этой форме, но теперь я получаю сообщение об ошибке (длина последовательности составляет 75, и есть 55 классов):

Expected target size (75, 55), got torch.Size([75])

Я пытался найти решения дляобе ошибки, но все еще не могут заставить это работать должным образом.Я запутался относительно правильных размеров цели, а также фактического значения первой ошибки (различные поиски дали очень разные значения для ошибки, ни одно из исправлений не сработало).

Спасибо

1 Ответ

0 голосов
/ 24 ноября 2018

Вы можете использовать squeeze() для своего output тензора, это возвращает тензор со всеми удаленными размерами размера 1.

Этот короткий код использует формы, которые вы упомянули в своем вопросе:

sequence_length   = 75
number_of_classes = 55
# creates random tensor of your output shape
output = torch.rand(sequence_length, 1, number_of_classes)
# creates tensor with random targets
target = torch.randint(55, (75,)).long()

# define loss function and calculate loss
criterion = nn.CrossEntropyLoss()
loss = criterion(output, target)
print(loss)

Результатом является ошибка, которую вы описали:

ValueError: Expected target size (75, 55), got torch.Size([75])

Таким образом, использование squeeze() для вашего output тензора решает вашу проблему, приводя ее к правильной форме.

Пример с исправленной формой:

sequence_length   = 75
number_of_classes = 55
# creates random tensor of your output shape
output = torch.rand(sequence_length, 1, number_of_classes)
# creates tensor with random targets
target = torch.randint(55, (75,)).long()

# define loss function and calculate loss
criterion = nn.CrossEntropyLoss()

# apply squeeze() on output tensor to change shape form [75, 1, 55] to [75, 55]
loss = criterion(output.squeeze(), target)
print(loss)

Вывод:

tensor(4.0442)

Использование squeeze() изменяет форму тензора с [75, 1, 55] на [75, 55] так, чтобы выводилсяи целевая форма соответствует!

Вы также можете использовать другие методы для изменения вашего тензора, просто важно иметь форму [sequence_length, number_of_classes] вместо [sequence_length, 1, number_of_classes].

Ваши цели должны быть LongTensorсоответственнотензор типа torch.long, содержащий классы.Форма здесь [sequence_length].

Редактировать:
Пример фигур из приведенного выше примера при переходе к функции кросс-энтропии:

Выходы:torch.Size([75, 55])
Цели: torch.Size([75])


Вот более общий пример того, как должны выглядеть результаты и цели для CE.В этом случае мы предполагаем, что у нас есть 5 различных целевых классов, есть три примера для последовательностей длиной 1, 2 и 3:

# init CE Loss function
criterion = nn.CrossEntropyLoss()

# sequence of length 1
output = torch.rand(1, 5)
# in this case the 1th class is our target, index of 1th class is 0
target = torch.LongTensor([0])
loss = criterion(output, target)
print('Sequence of length 1:')
print('Output:', output, 'shape:', output.shape)
print('Target:', target, 'shape:', target.shape)
print('Loss:', loss)

# sequence of length 2
output = torch.rand(2, 5)
# targets are here 1th class for the first element and 2th class for the second element
target = torch.LongTensor([0, 1])
loss = criterion(output, target)
print('\nSequence of length 2:')
print('Output:', output, 'shape:', output.shape)
print('Target:', target, 'shape:', target.shape)
print('Loss:', loss)

# sequence of length 3
output = torch.rand(3, 5)
# targets here 1th class, 2th class and 2th class again for the last element of the sequence
target = torch.LongTensor([0, 1, 1])
loss = criterion(output, target)
print('\nSequence of length 3:')
print('Output:', output, 'shape:', output.shape)
print('Target:', target, 'shape:', target.shape)
print('Loss:', loss)

Вывод:

Sequence of length 1:
Output: tensor([[ 0.1956,  0.0395,  0.6564,  0.4000,  0.2875]]) shape: torch.Size([1, 5])
Target: tensor([ 0]) shape: torch.Size([1])
Loss: tensor(1.7516)

Sequence of length 2:
Output: tensor([[ 0.9905,  0.2267,  0.7583,  0.4865,  0.3220],
        [ 0.8073,  0.1803,  0.5290,  0.3179,  0.2746]]) shape: torch.Size([2, 5])
Target: tensor([ 0,  1]) shape: torch.Size([2])
Loss: tensor(1.5469)

Sequence of length 3:
Output: tensor([[ 0.8497,  0.2728,  0.3329,  0.2278,  0.1459],
        [ 0.4899,  0.2487,  0.4730,  0.9970,  0.1350],
        [ 0.0869,  0.9306,  0.1526,  0.2206,  0.6328]]) shape: torch.Size([3, 5])
Target: tensor([ 0,  1,  1]) shape: torch.Size([3])
Loss: tensor(1.3918)

Надеюсь, это поможет!

...