Не удается найти операцию на месте, вызывающую «RuntimeError: одна из переменных, необходимых для вычисления градиента, была изменена операцией на месте:» - PullRequest
1 голос
/ 19 апреля 2020

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

Я получаю ошибку: "RuntimeError: одна из переменных, необходимых для вычисления градиента, имеет был изменен операцией на месте. "

Я просмотрел простой пример кода, документацию и множество сообщений на форуме по этой проблеме и не могу найти никаких операций на месте. Любая помощь будет принята с благодарностью!

Вот мой код:

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

torch.set_printoptions(precision=20, linewidth=180)

def jacobian(y, x, create_graph=False):
    jac = []
    flat_y = y.reshape(-1)     
    grad_y = torch.zeros_like(flat_y)     

    for i in range(len(flat_y)):         
        grad_y[i] = 1.
        grad_x, = torch.autograd.grad(flat_y, x, grad_y, retain_graph=True, create_graph=create_graph)
        jac.append(grad_x.reshape(x.shape))
        grad_y[i] = 0.
    return torch.stack(jac).reshape(y.shape + x.shape)           

def hessian(y, x):
    return jacobian(jacobian(y, x, create_graph=True), x)                                             

def f(x):                                                                                             
    return x * x

np.random.seed(435537698)

num_dims = 2
num_samples = 3

X = [np.random.uniform(size=num_dims) for i in range(num_samples)]
print('X: \n{}\n\n'.format(X))

mean = torch.Tensor(np.mean(X, axis=0))
mean.requires_grad = True
print('mean: \n{}\n\n'.format(mean))

cov = torch.Tensor(np.cov(X, rowvar=False))
print('cov: \n{}\n\n'.format(cov))

with autograd.detect_anomaly():
    hessian_matrices = hessian(f(mean), mean)
    print('hessian: \n{}\n\n'.format(hessian_matrices))

А вот вывод с трассировкой стека:

X: 
[array([0.81700949, 0.17141617]), array([0.53579366, 0.31141496]), array([0.49756485, 0.97495776])]


mean: 
tensor([0.61678934097290039062, 0.48592963814735412598], requires_grad=True)


cov: 
tensor([[ 0.03043144382536411285, -0.05357056483626365662],
        [-0.05357056483626365662,  0.18426130712032318115]])


---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-3-5a1c492d2873> in <module>()
     42 
     43 with autograd.detect_anomaly():
---> 44     hessian_matrices = hessian(f(mean), mean)
     45     print('hessian: \n{}\n\n'.format(hessian_matrices))

2 frames
<ipython-input-3-5a1c492d2873> in hessian(y, x)
     21 
     22 def hessian(y, x):
---> 23     return jacobian(jacobian(y, x, create_graph=True), x)
     24 
     25 def f(x):

<ipython-input-3-5a1c492d2873> in jacobian(y, x, create_graph)
     15     for i in range(len(flat_y)):
     16         grad_y[i] = 1.
---> 17         grad_x, = torch.autograd.grad(flat_y, x, grad_y, retain_graph=True, create_graph=create_graph)
     18         jac.append(grad_x.reshape(x.shape))
     19         grad_y[i] = 0.

/usr/local/lib/python3.6/dist-packages/torch/autograd/__init__.py in grad(outputs, inputs, grad_outputs, retain_graph, create_graph, only_inputs, allow_unused)
    155     return Variable._execution_engine.run_backward(
    156         outputs, grad_outputs, retain_graph, create_graph,
--> 157         inputs, allow_unused)
    158 
    159 

RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [2]] is at version 4; expected version 3 instead. Hint: the backtrace further above shows the operation that failed to compute its gradient. The variable in question was changed in there or anywhere later. Good luck!

1 Ответ

0 голосов
/ 20 апреля 2020

Я искренне думал, что это ошибка в PyTorch, но после публикации ошибки я получил хороший ответ от albanD. https://github.com/pytorch/pytorch/issues/36903#issuecomment -616671247 Он также указал, что https://discuss.pytorch.org/ доступен для вопросов.

Проблема возникает из-за того, что мы пересматриваем граф вычислений несколько раз и снова. Хотя то, что здесь происходит, мне не подходит ...

Редактирование на месте, на которое ссылается ваше сообщение об ошибке, является очевидным: grad_y[i] = 1. и grad_y[i] = 0.. Возобновление grad_y в вычислениях - это то, что вызывает проблемы. Переопределение jacobian(...), как показано ниже, работает для меня.

def jacobian(y, x, create_graph=False):
    jac = []
    flat_y = y.reshape(-1)
    for i in range(len(flat_y)):
        grad_y = torch.zeros_like(flat_y)
        grad_y[i] = 1.
        grad_x, = torch.autograd.grad(flat_y, x, grad_y, retain_graph=True, create_graph=create_graph)
        jac.append(grad_x.reshape(x.shape))
    return torch.stack(jac).reshape(y.shape + x.shape)

Альтернатива, которая работает, но больше похожа на черную магию c, для меня она оставляет jacobian(...) такой, какая она есть, и вместо этого переопределяет f(x) до

def f(x):
    return x * x * 1

Это тоже работает.

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