невозможно найти операцию на месте: одна из переменных, необходимых для вычисления градиента, была изменена с помощью операции на месте - PullRequest
0 голосов
/ 09 декабря 2018

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

Я не могу найти операцию inplace в своем коде, поэтому я не знаю, какую строку исправить.

* Ошибка возникает в последней строке: loss3.backward ()

            inputs_reg = Variable(data, requires_grad=True)
            output_reg = self.model.forward(inputs_reg)

            num_classes = output.size()[1]
            jacobian_list = []
            grad_output = torch.zeros(*output_reg.size())

            if inputs_reg.is_cuda:
                grad_output = grad_output.cuda()
                jacobian_list = jacobian.cuda()

            for i in range(10):

                zero_gradients(inputs_reg)
                grad_output.zero_()
                grad_output[:, i] = 1
                jacobian_list.append(torch.autograd.grad(outputs=output_reg,
                                                  inputs=inputs_reg,
                                                  grad_outputs=grad_output,
                                                  only_inputs=True,
                                                  retain_graph=True,
                                                  create_graph=True)[0])


            jacobian = torch.stack(jacobian_list, dim=0)
            loss3 = jacobian.norm()
            loss3.backward()

Ответы [ 3 ]

0 голосов
/ 09 декабря 2018

Спасибо!Я заменил проблемный код операции на месте в grad_output на:

            inputs_reg = Variable(data, requires_grad=True)
            output_reg = self.model.forward(inputs_reg)
            num_classes = output.size()[1]

            jacobian_list = []
            grad_output = torch.zeros(*output_reg.size())

            if inputs_reg.is_cuda:
                grad_output = grad_output.cuda()

            for i in range(5):
                zero_gradients(inputs_reg)

                grad_output_curr = grad_output.clone()
                grad_output_curr[:, i] = 1
                jacobian_list.append(torch.autograd.grad(outputs=output_reg,
                                                         inputs=inputs_reg,
                                                         grad_outputs=grad_output_curr,
                                                         only_inputs=True,
                                                         retain_graph=True,
                                                         create_graph=True)[0])

            jacobian = torch.stack(jacobian_list, dim=0)
            loss3 = jacobian.norm()
            loss3.backward()
0 голосов
/ 19 февраля 2019

Вы можете использовать функцию set_detect_anomaly , доступную в пакете autograd, чтобы точно определить, какая строка ответственна за ошибку.

Вот ссылка , которая описывает ту же проблему и решение с использованием вышеупомянутой функции.

0 голосов
/ 09 декабря 2018

grad_output.zero_() на месте и grad_output[:, i-1] = 0.На месте означает «изменить тензор вместо того, чтобы возвращать новый, к которому применены модификации».Примером решения, которое не на месте, является torch.where.Пример использования для обнуления 1-го столбца

import torch
t = torch.randn(3, 3)
ixs = torch.arange(3, dtype=torch.int64)
zeroed = torch.where(ixs[None, :] == 1, torch.tensor(0.), t)

zeroed
tensor([[-0.6616,  0.0000,  0.7329],
        [ 0.8961,  0.0000, -0.1978],
        [ 0.0798,  0.0000, -1.2041]])

t
tensor([[-0.6616, -1.6422,  0.7329],
        [ 0.8961, -0.9623, -0.1978],
        [ 0.0798, -0.7733, -1.2041]])

Обратите внимание, как t сохраняет значения, которые были у него ранее, а zeroed имеет значения, которые вы хотите.

...