PyTorch autograd - неявно можно создавать grad только для скалярных выходных данных - PullRequest
0 голосов
/ 13 сентября 2018

Я использую инструмент autograd в PyTorch и попал в ситуацию, когда мне нужно получить доступ к значениям в 1D-тензоре с помощью целочисленного индекса.Примерно так:

def basic_fun(x_cloned):
    res = []
    for i in range(len(x)):
        res.append(x_cloned[i] * x_cloned[i])
    print(res)
    return Variable(torch.FloatTensor(res))


def get_grad(inp, grad_var):
    A = basic_fun(inp)
    A.backward()
    return grad_var.grad


x = Variable(torch.FloatTensor([1, 2, 3, 4, 5]), requires_grad=True)
x_cloned = x.clone()
print(get_grad(x_cloned, x))

Я получаю следующее сообщение об ошибке:

[tensor(1., grad_fn=<ThMulBackward>), tensor(4., grad_fn=<ThMulBackward>), tensor(9., grad_fn=<ThMulBackward>), tensor(16., grad_fn=<ThMulBackward>), tensor(25., grad_fn=<ThMulBackward>)]
Traceback (most recent call last):
  File "/home/mhy/projects/pytorch-optim/predict.py", line 74, in <module>
    print(get_grad(x_cloned, x))
  File "/home/mhy/projects/pytorch-optim/predict.py", line 68, in get_grad
    A.backward()
  File "/home/mhy/.local/lib/python3.5/site-packages/torch/tensor.py", line 93, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
  File "/home/mhy/.local/lib/python3.5/site-packages/torch/autograd/__init__.py", line 90, in backward
    allow_unreachable=True)  # allow_unreachable flag
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

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

Я ценю вашу помощь с этим подходом или если есть лучший способ избежать потери истории градиента и все же индексировать через 1D-тензор с помощью requires_grad=True!

** Edit (15 сентября): **

res - список нульмерных тензоров, содержащих квадратные значения от 1 до 5. Чтобы объединить в один тензор, содержащий [1.0, 4.0, ..., 25.0], я изменилreturn Variable(torch.FloatTensor(res)) до torch.stack(res, dim=0), который выдает tensor([ 1., 4., 9., 16., 25.], grad_fn=<StackBackward>).

Однако я получаю эту новую ошибку, вызванную строкой A.backward().

Traceback (most recent call last):
  File "<project_path>/playground.py", line 22, in <module>
    print(get_grad(x_cloned, x))
  File "<project_path>/playground.py", line 16, in get_grad
    A.backward()
  File "/home/mhy/.local/lib/python3.5/site-packages/torch/tensor.py", line 93, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
  File "/home/mhy/.local/lib/python3.5/site-packages/torch/autograd/__init__.py", line 84, in backward
    grad_tensors = _make_grads(tensors, grad_tensors)
  File "/home/mhy/.local/lib/python3.5/site-packages/torch/autograd/__init__.py", line 28, in _make_grads
    raise RuntimeError("grad can be implicitly created only for scalar outputs")
RuntimeError: grad can be implicitly created only for scalar outputs

Ответы [ 2 ]

0 голосов
/ 15 сентября 2018

Я изменил свой basic_fun на следующий, что решило мою проблему:

def basic_fun(x_cloned):
    res = torch.FloatTensor([0])
    for i in range(len(x)):
        res += x_cloned[i] * x_cloned[i]
    return res

Эта версия возвращает скалярное значение.

0 голосов
/ 15 сентября 2018

в функции basic_fun переменная res уже является переменной torch-autograd-Variable, которую вам не нужно преобразовывать снова.ИМХО

def basic_fun(x_cloned):
    res = []
    for i in range(len(x)):
        res.append(x_cloned[i] * x_cloned[i])
    print(res)
    #return Variable(torch.FloatTensor(res))
    return res[0]

def get_grad(inp, grad_var):
    A = basic_fun(inp)
    A.backward()
    return grad_var.grad


x = Variable(torch.FloatTensor([1, 2, 3, 4, 5]), requires_grad=True)
x_cloned = x.clone()
print(get_grad(x_cloned, x))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...