Исходный код я больше не нашел на сайте PyTorch.
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(x.grad)
Проблема с приведенным выше кодом: нет функции, основанной на том, что вычислять градиенты. Это означает, что мы не знаем, сколько параметров (аргументов принимает функция) и размерность параметров.
Чтобы полностью понять это, я создал пример, близкий к оригиналу:
Пример 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)
это тензоры с тремя элементами внутри.
Вы можете думать так, как gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
будто это аккумулятор.
Как вы, возможно, слышали, расчет системы автограда PyTorch эквивалентен произведению Якоби.
Если у вас есть функция, как у нас:
y=3*a + 2*b*b + torch.log(c)
Якобианец был бы [3, 4*b, 1/c]
. Однако этот якобиан - это не то, как PyTorch вычисляет градиенты в определенной точке.
PyTorch использует в тандеме прямой проход и режим автоматического дифференцирования (AD) в обратном режиме .
Здесь нет символической математики и числового дифференцирования.
Численное дифференцирование должно быть вычислено δy/δb
для b=1
и b=1+ε
где ε мало.
Если вы не используете градиенты в y.backward()
:
Пример 2
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
:
Пример 3:
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
вас могут быть разные результаты каждый раз.
Кроме того, градиенты нот похожи на аккумуляторы, поэтому при необходимости обнуляйте их.
Пример 4:
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 создает динамический вычислительный график при вычислении градиентов в прямом проходе. Это очень похоже на дерево.
Поэтому вы часто слышите, что листья этого дерева являются входными тензорами, а корень - выходными тензорами .
Градиенты вычисляются путем отслеживания графика от корня к листу и умножения каждого градиента способом с использованием правила цепочки . Это умножение происходит при обратном проходе.