Как исправить ошибку измерения в функции потерь / softmax? - PullRequest
1 голос
/ 30 апреля 2020

Я реализую регрессию logisti c в PyTorch для XOR (я не ожидаю, что она будет работать хорошо, это просто демонстрация). По какой-то причине я получаю сообщение об ошибке «IndexError: Размер вне диапазона (ожидается, что он находится в диапазоне [-1, 0], но получил 1)». Мне не ясно, откуда это происходит. Ошибка указывает на log_softmax во время обучения.

import torch.nn as nn
import torch.nn.functional as F

class LogisticRegression(nn.Module):
  # input_size: Dimensionality of input feature vector.
  # num_classes: The number of classes in the classification problem.
  def __init__(self, input_size, num_classes):
    # Always call the superclass (nn.Module) constructor first!
    super(LogisticRegression, self).__init__()
    # Set up the linear transform
    self.linear = nn.Linear(input_size, num_classes)

  # Forward's sole argument is the input.
  # input is of shape (batch_size, input_size)
  def forward(self, x):
    # Apply the linear transform.
    # out is of shape (batch_size, num_classes)
    out = self.linear(x)
    # Softmax the out tensor to get a log-probability distribution
    # over classes for each example.
    out_distribution = F.softmax(out, dim=-1)
    return out_distribution


# Binary classifiation
num_outputs = 1
num_input_features = 2

# Create the logistic regression model
logreg_clf = LogisticRegression(num_input_features, num_outputs)

print(logreg_clf)


lr_rate = 0.001

X = torch.Tensor([[0,0],[0,1], [1,0], [1,1]])
Y = torch.Tensor([0,1,1,0]).view(-1,1) #view is similar to numpy.reshape()

# Run the forward pass of the logistic regression model
sample_output = logreg_clf(X) #completely random at the moment
print(X)

loss_function = nn.CrossEntropyLoss() # computes softmax and then the cross entropy
optimizer = torch.optim.SGD(logreg_clf.parameters(), lr=lr_rate)



from torch.autograd import Variable
#training loop: 

epochs = 201 #how many times we go through the training set
steps = X.size(0) #steps = 4; we have 4 training examples

for i in range(epochs):
    for j in range(steps):
        #sample from the training set: 
        data_point = np.random.randint(X.size(0))
        x_var = Variable(X[data_point], requires_grad=False)
        y_var = Variable(Y[data_point], requires_grad=False)

        optimizer.zero_grad() # zero the gradient buffers
        y_hat = logreg_clf(x_var) #get the output from the model
        loss = loss_function.forward(y_hat, y_var) #calculate the loss
        loss.backward() #backprop
        optimizer.step() #does the update

    if i % 500 == 0:
        print ("Epoch: {0}, Loss: {1}, ".format(i, loss.data.numpy()))

1 Ответ

1 голос
/ 01 мая 2020

Прежде всего, вы выполняете задачу двоичной классификации. Таким образом, количество выходных объектов должно быть 2; т.е. num_outputs = 1.

Во-вторых, как было объявлено в документации nn.CrossEntropyLoss(), метод .forward принимает два тензора, как показано ниже:

  • Input: (N, C) где C - количество классов (в вашем случае это 2).
  • Target: (N)

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

Примечание: Кроме того, вам не нужно использовать .Softmax() до nn.CrossEntropyLoss() модуля, так как этот класс включает в себя nn.LogSoftmax.

Я изменил Ваш код, как показано ниже, это рабочий пример вашего фрагмента:

import torch.nn as nn
import torch.nn.functional as F
import numpy as np
import torch

class LogisticRegression(nn.Module):
  # input_size: Dimensionality of input feature vector.
  # num_classes: The number of classes in the classification problem.
  def __init__(self, input_size, num_classes):
    # Always call the superclass (nn.Module) constructor first!
    super(LogisticRegression, self).__init__()
    # Set up the linear transform
    self.linear = nn.Linear(input_size, num_classes)

  # Forward's sole argument is the input.
  # input is of shape (batch_size, input_size)
  def forward(self, x):
    # Apply the linear transform.
    # out is of shape (batch_size, num_classes)
    out = self.linear(x)
    # Softmax the out tensor to get a log-probability distribution
    # over classes for each example.
    return out


# Binary classifiation
num_outputs = 2
num_input_features = 2

# Create the logistic regression model
logreg_clf = LogisticRegression(num_input_features, num_outputs)

print(logreg_clf)


lr_rate = 0.001

X = torch.Tensor([[0,0],[0,1], [1,0], [1,1]])
Y = torch.Tensor([0,1,1,0]).view(-1,1) #view is similar to numpy.reshape()

# Run the forward pass of the logistic regression model
sample_output = logreg_clf(X) #completely random at the moment
print(X)

loss_function = nn.CrossEntropyLoss() # computes softmax and then the cross entropy
optimizer = torch.optim.SGD(logreg_clf.parameters(), lr=lr_rate)



from torch.autograd import Variable
#training loop:

epochs = 201 #how many times we go through the training set
steps = X.size(0) #steps = 4; we have 4 training examples

for i in range(epochs):
    for j in range(steps):
        #sample from the training set:
        data_point = np.random.randint(X.size(0))
        x_var = Variable(X[data_point], requires_grad=False).unsqueeze(0)
        y_var = Variable(Y[data_point], requires_grad=False).long()

        optimizer.zero_grad() # zero the gradient buffers
        y_hat = logreg_clf(x_var) #get the output from the model
        loss = loss_function(y_hat, y_var) #calculate the loss
        loss.backward() #backprop
        optimizer.step() #does the update

    if i % 500 == 0:
        print ("Epoch: {0}, Loss: {1}, ".format(i, loss.data.numpy()))

Обновление

Чтобы получить прогнозируемые метки классов, которые могут быть 0 или 1:

pred = np.argmax(y_hat.detach().numpy, axis=0)

Что касается функции .detach(), numpy ожидает, что тензор / массив отделятся от графика вычислений; т. е. тензор не должен иметь require_grad=True, а метод отсоединения поможет вам.

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