Ошибка пользовательской функции потерь: тензор не имеет grad_fn

#python #machine-learning #deep-learning #pytorch #recurrent-neural-network

#python #машинное обучение #глубокое обучение #pytorch #рекуррентная нейронная сеть

Вопрос:

Попытка использовать пользовательскую функцию потерь и получение ошибки ‘RuntimeError: элемент 0 тензоров не требует grad и не имеет grad_fn’. Ошибка возникает во время loss.backward()

Я знаю, что все вычисления должны выполняться в тензорах с ‘require_grad = True’ . У меня возникли проблемы с реализацией этого, поскольку мой код требует вложенного цикла for . Я полагаю, что это может быть цикл for. Есть ли способ создать пустой тензор и добавить его? Ниже приведен мой код.

 def Gaussian_Kernal(x, mu, sigma):
  p = (1./(math.sqrt(2. * math.pi * (sigma**2)))) * torch.exp((-1.) * (((Variable(x)**2) - mu)/(2. * (sigma**2))))
  return p

class MEE(torch.nn.Module):
  def __init__(self):
    super(MEE,self).__init__()

  def forward(self,output, target, mu, variance):

    error = torch.subtract(Variable(output),Variable(target))
  
    error_diff = []
    for i in range(0, error.size(0)):
      for j in range(0, error.size(0)):
        error_diff.append(error[i] - error[j])

    error_diff = torch.cat(error_diff)
    torch.tensor(error_diff,requires_grad=True)

    loss = (1./(target.size(0)**2)) * torch.sum(Gaussian_Kernal(Variable(error_diff), mu, variance*(2**0.5)))

    loss = Variable(loss)

    return loss
 

Ответ №1:

Пока вы работаете с тензорами и применяете функции PyTorch и базовые операторы, это должно работать. Поэтому нет необходимости переносить ваши переменные с torch.tensor помощью или Variable . Последнее устарело (я полагаю, начиная с версии 0.4).

API переменных устарел: переменные больше не нужны для использования autograd с тензорами. Autograd автоматически поддерживает тензоры с require_grad, установленным в True. Документы PyTorch

Я предполагаю output , что и target являются тензорами, а mu и variance являются реалами, а не тензорами? Тогда первым измерением output и target будет пакет.

 def Gaussian_Kernel(x, mu, sigma):
  p = (1./(math.sqrt(2. * math.pi * (sigma**2)))) * torch.exp((-1.) * (((x**2) - mu)/(2. * (sigma**2))))
  return p

class MEE(torch.nn.Module):
  def __init__(self):
    super(MEE, self).__init__()

  def forward(self, output, target, mu, variance):
    error = output - target

    error_diff = []
    for i in range(0, error.size(0)):
      for j in range(0, error.size(0)):
        error_diff.append(error[i] - error[j]) # Assuming that's the desired operation

    error_diff = torch.cat(error_diff)
    kernel = Gaussian_Kernel(error_diff, mu, variance*(2**0.5))
    loss = (1./(target.size(0)**2))*torch.sum(kernel)
    
    return loss
 

Комментарии:

1. ваши предположения верны. mu и дисперсия являются действительными. Первое измерение тензоров — это размер пакета. Я думаю, что проблема в списке error_diff. Я вычисляю разницу в ошибках для каждой точки пакета. Я думаю, что копирование из списка в тензор приводит к ошибке, но я не уверен. Есть ли способ выполнить эту операцию только с тензорами? Я не думаю, что это ошибка в моей сети, потому что простой MSELoss() работает хорошо.

2. Это должно быть error[i] - error[j] тогда. Я не думаю, что создание нового списка error_diff является проблемой, если вы создаете стек или впоследствии объединяете их в тензор. Он все еще не работает?

3. Он по-прежнему выдает ту же ошибку. Я сохранил ошибку [i] — ошибка [j] . torch.cat создает копию списка в виде тензора.

4. Я также могу поделиться им через colab, если это поможет

5. У меня это работает, обязательно удалите Variable обертывание x в вашей Gaussian_Kernel функции, я думаю, вы забыли его удалить.