我在 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 autograd 系统计算等价于 Jacobian 积。
如果你有一个函数,就像我们做的那样:
y=3*a + 2*b*b + torch.log(c)
Jacobian 将是 [3, 4*b, 1/c]。但是,这个Jacobian 并不是 PyTorch 计算某个点的梯度的方式。
PyTorch 使用前向传递和backward mode automatic differentiation (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 在计算前向传播中的梯度时会创建一个动态计算图。这看起来很像一棵树。
所以你经常会听到这棵树的叶子是输入张量,而根是输出张量 .
梯度是通过从根到叶跟踪图并使用链式法则乘以每个梯度来计算的。这种乘法发生在反向传播中。
前段时间我创建了PyTorch Automatic Differentiation tutorial,您可能会检查有趣的解释有关 AD 的所有微小细节。