Ответ 1
Оригинальный код, которого я больше не нашел на сайте PyTorch.
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(x.grad)
Проблема с кодом выше - нет функции для расчета градиентов. Это означает, что мы не знаем, сколько параметров (аргументов принимает функция) и размерность параметров.
Чтобы полностью понять это, я создал несколько примеров, близких к оригиналу:
Example 1:
a = torch.tensor([1.0, 2.0, 3.0], requires_grad = True)
b = torch.tensor([3.0, 4.0, 5.0], requires_grad = True)
c = torch.tensor([6.0, 7.0, 8.0], requires_grad = True)
y=3*a + 2*b*b + torch.log(c)
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients,retain_graph=True)
print(a.grad) # tensor([3.0000e-01, 3.0000e+00, 3.0000e-04])
print(b.grad) # tensor([1.2000e+00, 1.6000e+01, 2.0000e-03])
print(c.grad) # tensor([1.6667e-02, 1.4286e-01, 1.2500e-05])
Как вы можете видеть, я предположил, что в первом примере наша функция - y=3*a + 2*b*b + torch.log(c)
, а параметры - тензоры с тремя элементами внутри.
Но есть и другой вариант:
Example 2:
import torch
a = torch.tensor(1.0, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(1.0, requires_grad = True)
y=3*a + 2*b*b + torch.log(c)
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(a.grad) # tensor(3.3003)
print(b.grad) # tensor(4.4004)
print(c.grad) # tensor(1.1001)
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
является аккумулятором.
Следующий пример даст идентичные результаты.
Example 3:
a = torch.tensor(1.0, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(1.0, requires_grad = True)
y=3*a + 2*b*b + torch.log(c)
gradients = torch.FloatTensor([0.1])
y.backward(gradients,retain_graph=True)
gradients = torch.FloatTensor([1.0])
y.backward(gradients,retain_graph=True)
gradients = torch.FloatTensor([0.0001])
y.backward(gradients)
print(a.grad) # tensor(3.3003)
print(b.grad) # tensor(4.4004)
print(c.grad) # tensor(1.1001)
Как вы можете слышать, расчет системы Autograd PyTorch эквивалентен продукту Якобиана.
Если у вас есть функция, как у нас:
y=3*a + 2*b*b + torch.log(c)
Якобиан будет [3, 4*b, 1/c]
. Однако этот якобианский совсем не так, как PyTorch делает вещи для вычисления градиентов в определенной точке.
Для предыдущей функции PyTorch будет делать, например, δy/δb
, для b=1
и b=1+ε
, где ε мало. Так что тут нет ничего похожего на символическую математику.
Если вы не используете градиенты в y.backward()
:
Example 4
a = torch.tensor(0.1, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(0.1, requires_grad = True)
y=3*a + 2*b*b + torch.log(c)
y.backward()
print(a.grad) # tensor(3.)
print(b.grad) # tensor(4.)
print(c.grad) # tensor(10.)
Вы просто получите результат в определенный момент, основываясь на том, как изначально были установлены ваши тензоры a
, b
, c
.
Будьте внимательны при инициализации своих a
, b
, c
:
Example 5:
a = torch.empty(1, requires_grad = True, pin_memory=True)
b = torch.empty(1, requires_grad = True, pin_memory=True)
c = torch.empty(1, requires_grad = True, pin_memory=True)
y=3*a + 2*b*b + torch.log(c)
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(a.grad) # tensor([3.3003])
print(b.grad) # tensor([0.])
print(c.grad) # tensor([inf])
Если вы используете torch.empty()
и не используете pin_memory=True
, вы можете каждый раз получать разные результаты.
Кроме того, градиенты нот похожи на аккумуляторы, поэтому обнуляйте их при необходимости.
Example 6:
a = torch.tensor(1.0, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(1.0, requires_grad = True)
y=3*a + 2*b*b + torch.log(c)
y.backward(retain_graph=True)
y.backward()
print(a.grad) # tensor(6.)
print(b.grad) # tensor(8.)
print(c.grad) # tensor(2.)
Наконец, я просто хотел сформулировать некоторые термины, которые использует PyTorch:
PyTorch создает динамический вычислительный граф при расчете градиентов. Это очень похоже на дерево.
Таким образом, вы часто будете слышать, что листья этого дерева являются входными тензорами, а корень - выходным тензором.
Градиенты рассчитываются путем трассировки графа от корня до листа и умножения каждого градиента на пути с использованием правила цепочки.