Почему производная от f (x) по 'x' 'x', а не по 1 в pytorch? - PullRequest
4 голосов
/ 10 апреля 2019

Я пытаюсь полностью понять автоградность pytorch, и я наткнулся на это: let f (x) = x, из базовых математических вычислений мы знаем, что f '(x) = 1, однако, когда я делаю это упражнение в pytorch, я получаю что f '(x) = x.

z = torch.linspace(-1, 1, steps=5, requires_grad=True)
y = z
y.backward(z)
print("Z tensor is: {} \n Gradient of y with respect to z is: {}".format(z, z.grad))

Я ожидал бы получить тензор размера 5, полный 1, но вместо этого я получу:

Z tensor is: tensor([-1.0000, -0.5000,  0.0000,  0.5000,  1.0000], requires_grad=True) 
 Gradient of y with respect to z is: tensor([-1.0000, -0.5000,  0.0000,  0.5000,  1.0000])

Почему это поведение pytorch?

Ответы [ 2 ]

2 голосов
/ 10 апреля 2019

Прежде всего, учитывая z = torch.linspace(-1, 1, steps=5, requires_grad=True) и y = z, функция является вектор-функцией, поэтому производная от y по z не так проста, как 1, но является матрицей Якоби.На самом деле в вашем случае z = [z1, z2, z3, z4, z5]T, верхний регистр T означает, что z - это вектор строки.Вот что говорит официальный документ:

enter image description here

Во-вторых, обратите внимание, что официальный документ говорит: Теперь в этом случае y больше не является скаляром,torch.autograd не может вычислить полный якобиан напрямую, но если мы просто хотим получить вектор-якобиан, просто передайте вектор назад в качестве аргумента link .В этом случае x.grad - это не фактическое значение градиента (матрица), а вектор-якобианское произведение .

РЕДАКТИРОВАТЬ: x.grad является фактическим градиентом, если ваш вывод y равенскалярСмотрите пример здесь:

z = torch.linspace(-1, 1, steps=5, requires_grad=True)
y = torch.sum(z)
y.backward()
z.grad 

Это выдаст:

tensor([1., 1., 1., 1., 1.])

Как видите, это градиент.Обратите внимание, единственное отличие состоит в том, что y является скалярным значением здесь, а векторным значением в вашем примере. grad может быть неявно создан только для скалярных выходных данных

Вам может быть интересно, что если градиент не является константой, например, зависит от ввода z, как в этом случае

z = torch.linspace(-1, 1, steps=5, requires_grad=True)
y = torch.sum(torch.pow(z,2))
y.backward()
z.grad

Вывод:

tensor([-2., -1.,  0.,  1.,  2.])

Это то же самое, что и

z = torch.linspace(-1, 1, steps=5, requires_grad=True)
y = torch.sum(torch.pow(z,2))
y.backward(torch.tensor(1.))
z.grad

Учебное пособие по блицу довольно короткое, поэтому его довольно сложно понять для начинающих.

0 голосов
/ 10 апреля 2019

После обсуждения с коллегой он обнаружил, что метод backward () фактически умножает градиент, вычисленный в z, на сам z.Это имеет смысл для приложений нейронной сети.Вот короткий фрагмент кода, чтобы понять это:

z = torch.linspace(1, 5, steps=5, requires_grad=True)
y = torch.pow(z,2)
y.backward(z)
print("Z tensor is: {} \n Gradient of y with respect to z is: {}".format(z, z.grad/z))

Вывод:

Z tensor is: tensor([1., 2., 3., 4., 5.], requires_grad=True) 
 Gradient of y with respect to z is: tensor([ 2.,  4.,  6.,  8., 10.], grad_fn=<DivBackward0>)

В этом случае вы можете видеть, что z.grad, деленное на z, является действительныможидаемый градиент z, который будет 2 * z.

...