uns*_*ium 13 gradient backpropagation gradient-descent pytorch autograd
假设我有自定义损失函数,并且我想在神经网络的帮助下拟合某些微分方程的解。因此,在每次前向传递中,我都会计算神经网络的输出,然后通过采用 MSE 和我想要拟合感知器的预期方程来计算损失。
现在我的疑问是:我应该使用grad(loss)反向loss.backward()传播来计算和更新我的梯度吗?
我知道,在使用 loss.backward() 时,我必须用 Variable 包装我的张量,并且必须为我想要获取损失梯度的变量设置 require_grad = True 。
所以我的问题是:
grad(loss)还需要任何此类显式参数来识别梯度计算的变量?如果您能解释这两种方法的实际含义,那就更好了,因为每当我试图在网上找到它时,我都会被很多与我的项目不太相关的东西轰炸。
Iva*_*van 18
太长了;两者是执行梯度计算的两个不同接口:torch.autograd.gradis 是不可变的,而torch.autograd.backwardis 是。
该torch.autograd模块是PyTorch的自动微分包。如文档中所述,只需对代码库进行最小的更改即可使用:
\n\n您只需要声明
\nTensor应使用关键字计算梯度的 srequires_grad=True。
torch.autograd提供梯度计算的两个主要函数是torch.autograd.backward和torch.autograd.grad:
torch.autograd.backward(来源) | torch.autograd.grad(来源) | |
|---|---|---|
| 描述 | 计算给定张量相对于图 leaves的梯度总和。 | 计算并返回输出相对于输入的梯度总和。 |
| 标头 | torch.autograd.backward( tensors, grad_tensors=None, retain_graph=None, create_graph=False, grad_variables=None, inputs=None) | torch.autograd.grad( outputs, inputs, grad_outputs=None, retain_graph=None, create_graph=False, only_inputs=True, allow_unused=False) |
| 参数 | - tensors\xe2\x80\x93 将计算导数的张量。- grad_tensors\xe2\x80\x93 雅可比向量乘积中的“向量”,通常是对应张量的每个元素的梯度。- retain_graph\xe2\x80\x93 如果False,则用于计算梯度的图将被释放。[...] - inputs\xe2\x80\x93 输入梯度将被累积到 中.grad。所有其他张量将被忽略。如果未提供,梯度将累积到所有使用的叶张量中[...]。 | - outputs\xe2\x80\x93 微分函数的输出。- inputs\xe2\x80\x93 输入梯度将被返回(并且不累积到.grad)。- grad_tensors\xe2\x80\x93 雅可比向量乘积中的“向量”,通常是对应张量的每个元素的梯度。- retain_graph\xe2\x80\x93 如果False,则用于计算梯度的图将被释放。[...]。 |
就高级用法而言,您可以将其视为torch.autograd.grad不可变函数。正如上面的文档表中提到的,它不会累积属性上的梯度grad,而是返回计算的偏导数。相反,torch.autograd.backward可以通过更新grad叶节点的属性来改变张量,该函数不会返回任何值。换句话说,当计算大量参数的梯度时,后者更适合。
接下来,我们将采用两个输入(x1和 ,x2),用它们计算张量y,然后计算结果对两个输入(即 dL/dx1和 )的偏导数dL/dx2:
>>> x1 = torch.rand(1, requires_grad=True)\n>>> x2 = torch.rand(1, requires_grad=True)\n>>> x1, x2\n(tensor(0.3939, grad_fn=<UnbindBackward>),\n tensor(0.7965, grad_fn=<UnbindBackward>))\nRun Code Online (Sandbox Code Playgroud)\n推理:
\n>>> y = x1**2 + 5*x2\n>>> y\ntensor(4.1377, grad_fn=<AddBackward0>)\nRun Code Online (Sandbox Code Playgroud)\n由于y是使用需要梯度的张量(即with requires_grad=True)计算的 - *在torch.no_grad上下文之外。它将grad_fn附加一个功能。此回调用于反向传播到计算图上以计算前面张量节点的梯度。
torch.autograd.grad:
这里我们提供torch.ones_like(y)为grad_outputs.
>>> torch.autograd.grad(y, (x1, x2), torch.ones_like(y))\n(tensor(0.7879), tensor(5.))\nRun Code Online (Sandbox Code Playgroud)\n上面的输出是一个元组,包含分别按出现顺序提供的输入的两个偏导数,即 dL/dx1和dL/dx2。
这对应于以下计算:
\n# dL/dx1 = dL/dy * dy/dx1 = grad_outputs @ 2*x1\n# dL/dx2 = dL/dy * dy/dx2 = grad_outputs @ 5\nRun Code Online (Sandbox Code Playgroud)\ntorch.autograd.backward:相反,它将通过更新grad用于计算输出张量且需要梯度的张量来改变提供的张量。它相当于torch.Tensor.backwardAPI。在这里,我们通过再次定义x1、x2、来完成相同的示例y。我们称之为backward:
>>> # y.backward(torch.ones_like(y))\n>>> torch.autograd.backward(y, torch.ones_like(y))\nNone\nRun Code Online (Sandbox Code Playgroud)\nx1.grad然后您可以检索和上的梯度x2.grad:
>>> x1.grad, x2.grad\n(tensor(0.7879), tensor(5.))\nRun Code Online (Sandbox Code Playgroud)\n结论:两者执行相同的操作。它们是与库交互autograd并执行梯度计算的两个不同接口。后者torch.autograd.backward(相当于torch.Tensor.backward)通常用于神经网络训练循环中,以计算模型每个参数的损失的偏导数。
您可以torch.autograd.grad通过阅读我所做的其他答案来了解有关工作原理的更多信息:Meaning of grad_outputs in PyTorch\'s torch.autograd.grad。
除了伊万的回答之外,torch.autograd.grad不累积梯度.grad可以避免多线程场景中的竞争情况。
引用 PyTorch 文档https://pytorch.org/docs/stable/notes/autograd.html#non-determinism
如果您在多个线程上同时调用backward(),但具有共享输入(即Hogwild CPU 训练)。由于参数在线程之间自动共享,因此跨线程的向后调用时梯度累积可能会变得不确定,因为两个向后调用可能会访问并尝试累积相同的 .grad 属性。这在技术上是不安全的,可能会导致赛车状况,结果可能无法使用。
但是,如果您使用多线程方法来驱动整个训练过程但使用共享参数,则这是预期的模式,使用多线程的用户应该牢记线程模型并应该期望这种情况发生。用户可以使用函数式 API torch.autograd.grad() 来计算梯度而不是 back() 以避免不确定性。
| 归档时间: |
|
| 查看次数: |
7599 次 |
| 最近记录: |