在pytorch中,后向方法的第一个参数(渐变)是什么?

时间:2017-08-23 10:45:09

标签: machine-learning pytorch

我们在pytorch文档中有以下代码:

x = torch.randn(3)
x = Variable(x, requires_grad=True)

y = x * 2
while y.data.norm() < 1000:
    y = y * 2

gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)

我们传递给后向方法的渐变参数究竟是什么?基于我们初始化它的内容?

1 个答案:

答案 0 :(得分:1)

要完全回答您的问题,需要更长时间的解释来解释Backprop或更基本的chain rule工作原理的详细信息。

简短的程序化答案是Variable的向后函数计算附加到Variable的计算图中所有变量的梯度。 (澄清一下:如果你有a = b + c,那么计算图(递归地)首先指向b,然后指向c,然后指向如何计算,等等)并累积存储(总和)这些变量的.grad属性中的这些渐变。然后,当您调用opt.step(),即优化程序的一个步骤时,它会将该渐变的一小部分添加到这些变量的值中。

也就是说,从概念上看它有两个答案:如果你想训练一个机器学习模型,你通常想要有一些关于某些损失函数的梯度。在这种情况下,计算的梯度将使得在应用阶梯函数时总损失(标量值)将减小。在这种特殊情况下,我们希望将梯度计算为特定值,即单位长度步长(以便学习率将计算我们想要的梯度的分数)。这意味着如果您有一个损失功能,并且拨打loss.backward(),则会计算与loss.backward(torch.FloatTensor([1.]))相同的费用。

虽然这是DNN中backprop的常见用例,但它只是函数一般区分的一个特例。更一般地,符号微分包(在这种情况下是autograd,作为pytorch的一部分)可用于计算计算图的早期部分的梯度,相对于任何子图的根处的任何梯度选择。这是关键字参数gradient有用的时候,因为你可以在那里提供这个“根级”渐变,即使对于非标量函数也是如此!

为了说明,这是一个小例子:

a = nn.Parameter(torch.FloatTensor([[1, 1], [2, 2]]))
b = nn.Parameter(torch.FloatTensor([[1, 2], [1, 2]]))
c = torch.sum(a - b)
c.backward(None)  # could be c.backward(torch.FloatTensor([1.])) for the same result
print(a.grad, b.grad) 

打印:

Variable containing:
 1  1
 1  1
[torch.FloatTensor of size 2x2]
 Variable containing:
-1 -1
-1 -1
[torch.FloatTensor of size 2x2]

虽然

a = nn.Parameter(torch.FloatTensor([[1, 1], [2, 2]]))
b = nn.Parameter(torch.FloatTensor([[1, 2], [1, 2]]))
c = torch.sum(a - b)
c.backward(torch.FloatTensor([[1, 2], [3, 4]]))
print(a.grad, b.grad)

打印:

Variable containing:
 1  2
 3  4
[torch.FloatTensor of size 2x2]
 Variable containing:
-1 -2
-3 -4
[torch.FloatTensor of size 2x2]

a = nn.Parameter(torch.FloatTensor([[0, 0], [2, 2]]))
b = nn.Parameter(torch.FloatTensor([[1, 2], [1, 2]]))
c = torch.matmul(a, b)
c.backward(torch.FloatTensor([[1, 1], [1, 1]]))  # we compute w.r.t. a non-scalar variable, so the gradient supplied cannot be scalar, either!
print(a.grad, b.grad)

打印

Variable containing:
 3  3
 3  3
[torch.FloatTensor of size 2x2]
 Variable containing:
 2  2
 2  2
[torch.FloatTensor of size 2x2]

a = nn.Parameter(torch.FloatTensor([[0, 0], [2, 2]]))
b = nn.Parameter(torch.FloatTensor([[1, 2], [1, 2]]))
c = torch.matmul(a, b)
c.backward(torch.FloatTensor([[1, 2], [3, 4]]))  # we compute w.r.t. a non-scalar variable, so the gradient supplied cannot be scalar, either!
print(a.grad, b.grad)

打印:

Variable containing:
  5   5
 11  11
[torch.FloatTensor of size 2x2]
 Variable containing:
 6  8
 6  8
[torch.FloatTensor of size 2x2]