PyTorch中的向后功能

Eli*_*lin 3 machine-learning gradient-descent pytorch autograd

我对pytorch的向后功能有些疑问,我认为我没有得到正确的输出

import numpy as np
import torch
from torch.autograd import Variable
a = Variable(torch.FloatTensor([[1,2,3],[4,5,6]]), requires_grad=True) 
out = a * a
out.backward(a)
print(a.grad)
Run Code Online (Sandbox Code Playgroud)

输出是

tensor([[ 2.,  8., 18.],
        [32., 50., 72.]])
Run Code Online (Sandbox Code Playgroud)

也许是 2*a*a

但我认为输出应该是

tensor([[ 2.,  4., 6.],
        [8., 10., 12.]])
Run Code Online (Sandbox Code Playgroud)

2*a. 原因 d(x^2)/dx=2x

Sha*_*hai 5

请仔细阅读文档backward()以更好地理解它。

默认情况下,pytorch期望backward()为网络的最后一个输出-损失函数调用。损失函数始终输出标量,因此,所有其他变量/参数的标量损失的梯度都得到了很好的定义(使用链式法则)。
因此,默认情况下,backwards()在标量张量上调用它并且不期望任何参数。
例如:

a = torch.tensor([[1,2,3],[4,5,6]], dtype=torch.float, requires_grad=True)
for i in range(2):
  for j in range(3):
    out = a[i,j] * a[i,j]
    out.backward()
print(a.grad)
Run Code Online (Sandbox Code Playgroud)

产量

tensor([[ 2.,  4.,  6.],
        [ 8., 10., 12.]])
Run Code Online (Sandbox Code Playgroud)

如预期:d(a^2)/da = 2a

但是,当您调用backwards2×3 out张量(不再是标量函数)时,您期望a.grad是什么?实际上,您实际上需要一个2×3×2×3的输出:(d out[i,j] / d a[k,l]!)
Pytorch不支持此非标量函数派生类。
取而代之的是,pytorch假设out只是一个中间张量,并且在“上游”某处存在通过链式规则提供的标量损失函数d loss/ d out[i,j]。此“上游”梯度的大小为2×3,这实际上是您backward在此情况下提供的参数:out.backward(g)where g_ij = d loss/ d out_ij
然后通过链式规则计算梯度。d loss / d a[i,j] = (d loss/d out[i,j]) * (d out[i,j] / d a[i,j])
由于您提供a了“上游”梯度,

a.grad[i,j] = 2 * a[i,j] * a[i,j]
Run Code Online (Sandbox Code Playgroud)

如果要提供“上游”渐变,则全部渐变

tensor([[ 2.,  4.,  6.],
        [ 8., 10., 12.]])
Run Code Online (Sandbox Code Playgroud)

产量

tensor([[ 2.,  4.,  6.],
        [ 8., 10., 12.]])
Run Code Online (Sandbox Code Playgroud)

如预期的那样。

这都是连锁法则。

  • 当您说梯度是通过链式法则计算时,您忘记了矩阵乘法。所以它不仅仅是 (d loss/d out[i,j]) * (d out[i,j] / da[i,j]),而是实际上 sum_{k,l} (d loss/d out[ k,l]) * (d out[k,l] / da[i,j])。 (2认同)