目录

简介 ||张量 ||Autograd ||建筑模型 ||TensorBoard 支持 ||训练模型 ||模型理解

Autograd 的基础知识

创建时间: 2021年11月30日 |上次更新时间:2024 年 2 月 26 日 |上次验证: Nov 05, 2024

请跟随下面的视频或在 youtube 上观看。

PyTorch 的 Autograd 功能是使 PyTorch 灵活且 快速构建机器学习项目。它允许快速和 在复杂计算中轻松计算多个偏导数(也称为梯度)。此操作是 基于反向传播的神经网络学习。

autograd 的强大之处在于它跟踪你的 计算,这意味着如果您的模型具有 决策分支,或直到运行时才知道长度的循环, 计算仍然会被正确跟踪,你会得到正确的 gradients 来驱动学习。这一点,再加上您的 模型是用 Python 构建的,比框架提供更大的灵活性 依赖于对结构更严格的模型的静态分析 计算梯度。

我们需要 Autograd 做什么?

机器学习模型是一个具有输入和输出的函数。为 在本次讨论中,我们将输入视为一个 i 维向量 \(\vec{x}\),元素为 \(x_{i}\)。然后我们可以表示 model, M 作为输入的向量值函数:\(\vec{y} = \vec{M}(\vec{x})\) 的(我们将 M 的输出值视为 向量,因为通常,模型可以有任意数量的输出。

由于我们主要在训练的上下文中讨论 autograd, 我们感兴趣的输出将是模型的损失。损失函数 L(\(\vec{y}\)) = L(\(\vec{M}\)\(\vec{x}\))) 是一个 模型输出的单值标量函数。此功能 表示模型的预测与特定 input 的理想输出。注意:在这一点之后,我们通常会省略 向量符号,它应该在上下文中清晰 - 例如,\(y\) 而不是 \(\vec y\)。

在训练模型时,我们希望将损失降至最低。在理想化的情况下 ,这意味着调整其学习权重 - 即 函数的可调参数 - 使得 loss 为零 所有输入。在现实世界中,它意味着一个迭代的轻推过程 学习权重,直到我们看到 a 的损失是可以容忍的 多种输入。

我们如何决定将权重推多远以及朝哪个方向轻推?我们 希望将损失降至最低,这意味着进行其一阶导数 对于等于 0 的输入:\(\frac{\partial L}{\partial x} = 0\)。

不过,回想一下,损失并不是直接来自输入, 而是模型输出的函数(即 input 的函数 直接), \(\frac{\partial L}{\partial x}\) = \(\frac{\partial {L({\vec y})}}{\partial x}\)。按照 微积分,我们有 \(\frac{\partial {L({\vec y})}}{\partial x}\) = \(\frac{\partial L}{\partial y}\frac{\partial y}{\partial x}\) = \(\frac{\partial L}{\partial y}\frac{\partial M(x)}{\partial x}\)。

\(\frac{\partial M(x)}{\partial x}\) 是事情变得复杂的地方。 模型输出相对于其 inputs,如果我们再次使用链式规则扩展表达式, 将涉及每个相乘上的许多局部偏导数 学习权重、每个激活函数和所有其他数学 模型中的 transformation。每个此类部分的完整表达式 导数是每个 通过以变量 我们试图测量其梯度。

特别是,学习权重上的梯度很有趣 对我们来说 - 它们告诉我们改变每个权重的方向以获得 loss 函数更接近于零。

由于此类局部导数(每个导数对应一个 单独的路径)将趋于上升 神经网络的深度呈指数增长,复杂性也呈指数增长 在计算它们。这就是 autograd 的用武之地:它跟踪 每次计算的历史。PyTorch 中的每个计算张量 model 携带其输入张量的历史记录,以及用于 创建它。结合 PyTorch 函数旨在作用于 每个张量都有一个内置的实现,用于计算自己的 导数,这大大加快了局部 学习所需的衍生物。

一个简单的例子

这是很多理论 - 但是在 autograd 中使用是什么样子的 实践?

让我们从一个简单的例子开始。首先,我们将执行一些导入操作 让我们绘制结果图:

# %matplotlib inline

import torch

import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import math

接下来,我们将在 区间 \([0, 2{\pi}]\) 并指定 。(喜欢 大多数创建 Tensor 的函数都接受 可选选项。设置此标志意味着在 接下来的每次计算,autograd 都会累积 该计算的输出张量中的计算历史记录。requires_grad=Truetorch.linspace()requires_grad

a = torch.linspace(0., 2. * math.pi, steps=25, requires_grad=True)
print(a)
tensor([0.0000, 0.2618, 0.5236, 0.7854, 1.0472, 1.3090, 1.5708, 1.8326, 2.0944,
        2.3562, 2.6180, 2.8798, 3.1416, 3.4034, 3.6652, 3.9270, 4.1888, 4.4506,
        4.7124, 4.9742, 5.2360, 5.4978, 5.7596, 6.0214, 6.2832],
       requires_grad=True)

接下来,我们将执行计算,并根据其 输入:

b = torch.sin(a)
plt.plot(a.detach(), b.detach())
autogradyt 教程
[<matplotlib.lines.Line2D object at 0x7f6a9b8e2980>]

让我们仔细看看张量 .当我们打印它时,我们会看到 一个指示它正在跟踪其计算历史的指示器:b

print(b)
tensor([ 0.0000e+00,  2.5882e-01,  5.0000e-01,  7.0711e-01,  8.6603e-01,
         9.6593e-01,  1.0000e+00,  9.6593e-01,  8.6603e-01,  7.0711e-01,
         5.0000e-01,  2.5882e-01, -8.7423e-08, -2.5882e-01, -5.0000e-01,
        -7.0711e-01, -8.6603e-01, -9.6593e-01, -1.0000e+00, -9.6593e-01,
        -8.6603e-01, -7.0711e-01, -5.0000e-01, -2.5882e-01,  1.7485e-07],
       grad_fn=<SinBackward0>)

这给了我们一个提示,当我们执行 反向传播步骤并计算梯度,我们需要计算 \(\sin(x)\) 的导数。grad_fn

让我们执行更多计算:

c = 2 * b
print(c)

d = c + 1
print(d)
tensor([ 0.0000e+00,  5.1764e-01,  1.0000e+00,  1.4142e+00,  1.7321e+00,
         1.9319e+00,  2.0000e+00,  1.9319e+00,  1.7321e+00,  1.4142e+00,
         1.0000e+00,  5.1764e-01, -1.7485e-07, -5.1764e-01, -1.0000e+00,
        -1.4142e+00, -1.7321e+00, -1.9319e+00, -2.0000e+00, -1.9319e+00,
        -1.7321e+00, -1.4142e+00, -1.0000e+00, -5.1764e-01,  3.4969e-07],
       grad_fn=<MulBackward0>)
tensor([ 1.0000e+00,  1.5176e+00,  2.0000e+00,  2.4142e+00,  2.7321e+00,
         2.9319e+00,  3.0000e+00,  2.9319e+00,  2.7321e+00,  2.4142e+00,
         2.0000e+00,  1.5176e+00,  1.0000e+00,  4.8236e-01, -3.5763e-07,
        -4.1421e-01, -7.3205e-01, -9.3185e-01, -1.0000e+00, -9.3185e-01,
        -7.3205e-01, -4.1421e-01,  4.7684e-07,  4.8236e-01,  1.0000e+00],
       grad_fn=<AddBackward0>)

最后,我们来计算一个单元素输出。当你在没有参数的情况下调用张量时,它期望调用 tensor 的 API 中,就像计算 loss 函数。.backward()

out = d.sum()
print(out)
tensor(25., grad_fn=<SumBackward0>)

每个都与我们的张量一起存储,允许您遍历 计算一直返回到其 Inputs 及其属性。我们可以在下面看到,深入研究这个属性向我们展示了所有先验张量的梯度函数。请注意,报告为 ,表示这是一个输入 添加到没有自己的历史记录的函数中。grad_fnnext_functionsda.grad_fnNone

print('d:')
print(d.grad_fn)
print(d.grad_fn.next_functions)
print(d.grad_fn.next_functions[0][0].next_functions)
print(d.grad_fn.next_functions[0][0].next_functions[0][0].next_functions)
print(d.grad_fn.next_functions[0][0].next_functions[0][0].next_functions[0][0].next_functions)
print('\nc:')
print(c.grad_fn)
print('\nb:')
print(b.grad_fn)
print('\na:')
print(a.grad_fn)
d:
<AddBackward0 object at 0x7f6a9b88c100>
((<MulBackward0 object at 0x7f6acaa42b00>, 0), (None, 0))
((<SinBackward0 object at 0x7f6a9b88c100>, 0), (None, 0))
((<AccumulateGrad object at 0x7f6acaa42b00>, 0),)
()

c:
<MulBackward0 object at 0x7f6a9b88c100>

b:
<SinBackward0 object at 0x7f6a9b88c100>

a:
None

有了所有这些机制,我们如何推出衍生品?你 对 output 调用 该方法,并检查 input 的属性以检查梯度:backward()grad

out.backward()
print(a.grad)
plt.plot(a.detach(), a.grad.detach())
autogradyt 教程
tensor([ 2.0000e+00,  1.9319e+00,  1.7321e+00,  1.4142e+00,  1.0000e+00,
         5.1764e-01, -8.7423e-08, -5.1764e-01, -1.0000e+00, -1.4142e+00,
        -1.7321e+00, -1.9319e+00, -2.0000e+00, -1.9319e+00, -1.7321e+00,
        -1.4142e+00, -1.0000e+00, -5.1764e-01,  2.3850e-08,  5.1764e-01,
         1.0000e+00,  1.4142e+00,  1.7321e+00,  1.9319e+00,  2.0000e+00])

[<matplotlib.lines.Line2D object at 0x7f6a9b911870>]

回想一下我们为了到达这里而采取的计算步骤:

a = torch.linspace(0., 2. * math.pi, steps=25, requires_grad=True)
b = torch.sin(a)
c = 2 * b
d = c + 1
out = d.sum()

添加一个常量,就像我们对 计算 所做的那样,不会改变 导数。剩下 \(c = 2 * b = 2 * \sin(a)\) 导数 其中应该是 \(2 * \cos(a)\)。看上图, 这就是我们所看到的。d

请注意,只有计算的叶节点才有其梯度 计算。例如,如果您尝试了,您将返回 .在这个简单的示例中,只有输入是叶节点,因此只有 它计算了梯度。print(c.grad)None

Autograd 在培训中的应用

我们已经简要了解了 autograd 的工作原理,但是当 它用于其预期目的?让我们定义一个小模型,然后 检查它在单个训练批次后如何变化。首先,定义一个 几个常量、我们的模型以及一些输入和输出的替代品:

BATCH_SIZE = 16
DIM_IN = 1000
HIDDEN_SIZE = 100
DIM_OUT = 10

class TinyModel(torch.nn.Module):

    def __init__(self):
        super(TinyModel, self).__init__()

        self.layer1 = torch.nn.Linear(DIM_IN, HIDDEN_SIZE)
        self.relu = torch.nn.ReLU()
        self.layer2 = torch.nn.Linear(HIDDEN_SIZE, DIM_OUT)

    def forward(self, x):
        x = self.layer1(x)
        x = self.relu(x)
        x = self.layer2(x)
        return x

some_input = torch.randn(BATCH_SIZE, DIM_IN, requires_grad=False)
ideal_output = torch.randn(BATCH_SIZE, DIM_OUT, requires_grad=False)

model = TinyModel()

您可能会注意到的一件事是,我们从未为模型的层指定。在 的子类中,假设我们想要跟踪 layers 的权重进行学习。requires_grad=Truetorch.nn.Module

如果我们查看模型的各层,我们可以检查 weights,并验证尚未计算梯度:

print(model.layer2.weight[0][0:10]) # just a small slice
print(model.layer2.weight.grad)
tensor([ 0.0920,  0.0916,  0.0121,  0.0083, -0.0055,  0.0367,  0.0221, -0.0276,
        -0.0086,  0.0157], grad_fn=<SliceBackward0>)
None

让我们看看当我们运行一个训练批次时,情况会如何变化。对于 loss 函数,我们只使用欧几里得距离的平方 在 our 和 之间,我们将使用 基本的随机梯度下降优化器。predictionideal_output

tensor(211.2634, grad_fn=<SumBackward0>)

现在,让我们打电话看看会发生什么:loss.backward()

tensor([ 0.0920,  0.0916,  0.0121,  0.0083, -0.0055,  0.0367,  0.0221, -0.0276,
        -0.0086,  0.0157], grad_fn=<SliceBackward0>)
tensor([12.8997,  2.9572,  2.3021,  1.8887,  5.0710,  7.3192,  3.5169,  2.4319,
         0.1732, -5.3835])

我们可以看到,每次学习的梯度都已经计算过了 weight 的 intent 表达式,但权重保持不变,因为我们尚未运行 optimizer 还没有。优化器负责更新模型权重 基于计算出的梯度。

tensor([ 0.0791,  0.0886,  0.0098,  0.0064, -0.0106,  0.0293,  0.0186, -0.0300,
        -0.0088,  0.0211], grad_fn=<SliceBackward0>)
tensor([12.8997,  2.9572,  2.3021,  1.8887,  5.0710,  7.3192,  3.5169,  2.4319,
         0.1732, -5.3835])

您应该会看到 的权重已更改。layer2

关于进程的一件重要事情:调用 、 后,您需要调用 、 或 else 每次运行 学习权重将累积:optimizer.step()optimizer.zero_grad()loss.backward()

print(model.layer2.weight.grad[0][0:10])

for i in range(0, 5):
    prediction = model(some_input)
    loss = (ideal_output - prediction).pow(2).sum()
    loss.backward()

print(model.layer2.weight.grad[0][0:10])

optimizer.zero_grad(set_to_none=False)

print(model.layer2.weight.grad[0][0:10])
tensor([12.8997,  2.9572,  2.3021,  1.8887,  5.0710,  7.3192,  3.5169,  2.4319,
         0.1732, -5.3835])
tensor([ 19.2095, -15.9459,   8.3306,  11.5096,   9.5471,   0.5391,  -0.3370,
          8.6386,  -2.5141, -30.1419])
tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

运行上面的单元格后,您应该会看到,在运行多次后,大多数 梯度会大得多。之前未能将梯度归零 运行下一个训练批次将导致梯度在 这种方式,会导致不正确和不可预测的学习结果。loss.backward()

关闭和打开 Autograd

在某些情况下,您需要对 是否启用 autograd。有多种方法可以做到这一点, 视情况而定。

最简单的方法是更改张量上的标志 径直:requires_grad

a = torch.ones(2, 3, requires_grad=True)
print(a)

b1 = 2 * a
print(b1)

a.requires_grad = False
b2 = 2 * a
print(b2)
tensor([[1., 1., 1.],
        [1., 1., 1.]], requires_grad=True)
tensor([[2., 2., 2.],
        [2., 2., 2.]], grad_fn=<MulBackward0>)
tensor([[2., 2., 2.],
        [2., 2., 2.]])

在上面的单元格中,我们看到有一个 (即一个 traced computation history),这就是我们所期望的,因为它是从 一个启用了 autograd 的张量 。当我们关闭 autograd 时 显式 with ,计算历史为 NO 更长的跟踪时间,正如我们在计算 时看到的那样。b1grad_fnaa.requires_grad = Falseb2

如果你只需要暂时关闭 autograd,更好的方法是使用 这:torch.no_grad()

a = torch.ones(2, 3, requires_grad=True) * 2
b = torch.ones(2, 3, requires_grad=True) * 3

c1 = a + b
print(c1)

with torch.no_grad():
    c2 = a + b

print(c2)

c3 = a * b
print(c3)
tensor([[5., 5., 5.],
        [5., 5., 5.]], grad_fn=<AddBackward0>)
tensor([[5., 5., 5.],
        [5., 5., 5.]])
tensor([[6., 6., 6.],
        [6., 6., 6.]], grad_fn=<MulBackward0>)

torch.no_grad()也可以用作函数或方法装饰器:

def add_tensors1(x, y):
    return x + y

@torch.no_grad()
def add_tensors2(x, y):
    return x + y


a = torch.ones(2, 3, requires_grad=True) * 2
b = torch.ones(2, 3, requires_grad=True) * 3

c1 = add_tensors1(a, b)
print(c1)

c2 = add_tensors2(a, b)
print(c2)
tensor([[5., 5., 5.],
        [5., 5., 5.]], grad_fn=<AddBackward0>)
tensor([[5., 5., 5.],
        [5., 5., 5.]])

有一个对应的上下文管理器 ,用于 在 autograd 尚未打开时将其打开。它也可以用作 装饰。torch.enable_grad()

最后,您可能有一个需要梯度跟踪的张量,但您 想要一个没有的拷贝。为此,我们有对象的方法 - 它创建与计算历史分离的张量副本:Tensordetach()

x = torch.rand(5, requires_grad=True)
y = x.detach()

print(x)
print(y)
tensor([0.0670, 0.3890, 0.7264, 0.3559, 0.6584], requires_grad=True)
tensor([0.0670, 0.3890, 0.7264, 0.3559, 0.6584])

当我们想要绘制一些张量时,我们在上面做了这个操作。这是 因为需要一个 NumPy 数组作为输入,而隐式的 未启用从 PyTorch 张量到 NumPy 数组的转换 requires_grad=True 的张量。创建分离的副本可让我们移动 向前。matplotlib

Autograd 和 In-place Operations

到目前为止,在这个笔记本的每个示例中,我们都使用了变量来 捕获计算的中间值。Autograd 需要这些 中间值来执行梯度计算。因此, 在使用 autograd 的这样做可能会破坏您需要计算的信息 衍生物。PyTorch 甚至会阻止你,如果 您尝试对需要 autograd 的 API 中,如下所示。backward()

注意

以下代码单元引发运行时错误。这是意料之中的。

a = torch.linspace(0., 2. * math.pi, steps=25, requires_grad=True)
torch.sin_(a)

Autograd 分析器

Autograd 会详细跟踪计算的每个步骤。这样的 计算历史与时序信息相结合,将使 方便的 Profiler - 而 Autograd 内置了该功能。这里有一个快速的 示例用法:

device = torch.device('cpu')
run_on_gpu = False
if torch.cuda.is_available():
    device = torch.device('cuda')
    run_on_gpu = True

x = torch.randn(2, 3, requires_grad=True)
y = torch.rand(2, 3, requires_grad=True)
z = torch.ones(2, 3, requires_grad=True)

with torch.autograd.profiler.profile(use_cuda=run_on_gpu) as prf:
    for _ in range(1000):
        z = (z / x) * y

print(prf.key_averages().table(sort_by='self_cpu_time_total'))
/var/lib/workspace/beginner_source/introyt/autogradyt_tutorial.py:485: FutureWarning:

The attribute `use_cuda` will be deprecated soon, please use ``use_device = 'cuda'`` instead.

-------------------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------
                     Name    Self CPU %      Self CPU   CPU total %     CPU total  CPU time avg     Self CUDA   Self CUDA %    CUDA total  CUDA time avg    # of Calls
-------------------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------
          cudaEventRecord        43.35%       8.486ms        43.35%       8.486ms       2.122us       0.000us         0.00%       0.000us       0.000us          4000
                aten::div        28.94%       5.665ms        28.94%       5.665ms       5.665us       9.991ms        50.69%       9.991ms       9.991us          1000
                aten::mul        27.65%       5.412ms        27.65%       5.412ms       5.412us       9.719ms        49.31%       9.719ms       9.719us          1000
    cudaDeviceSynchronize         0.06%      12.618us         0.06%      12.618us      12.618us       0.000us         0.00%       0.000us       0.000us             1
-------------------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------
Self CPU time total: 19.576ms
Self CUDA time total: 19.710ms

分析器还可以标记代码的单个子块,将 data 通过输入张量形状,并将数据导出为 Chrome 跟踪工具 文件。有关 API 的完整详细信息,请参阅文档

高级主题:更多 Autograd 详细信息和高级 API

如果您有一个具有 n 维输入和 m 维的函数 output, \(\vec{y}=f(\vec{x})\) 时,完整的梯度是 每个输出相对于每个输入的导数,称为雅可比矩阵:

\[J = \left(\begin{array}{ccc} \frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{1}}{\partial x_{n}}\\ \vdots & \ddots & \vdots\\ \frac{\partial y_{m}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}} \end{array}\right)\]

如果你有第二个函数 \(l=g\left(\vec{y}\right)\) that 采用 m 维输入(即与 output),并返回一个标量输出,则可以将其 相对于 \(\vec{y}\) 作为列向量的梯度,\(v=\left(\begin{array}{ccc}\frac{\partial l}{\partial y_{1}} & \cdots & \frac{\partial l}{\partial y_{m}}\end{array}\right)^{T}\) - 这实际上只是一个单列雅可比矩阵。

更具体地说,将第一个函数想象成您的 PyTorch 模型(使用 可能有许多输入和许多输出),第二个函数为 loss 函数(以模型的输出作为输入,损失值为 标量输出)。

如果我们将第一个函数的雅可比矩阵乘以 second 函数,并应用链式规则,我们得到:

\[J^{T}\cdot v=\left(\begin{array}{ccc} \frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{1}}\\ \vdots & \ddots & \vdots\\ \frac{\partial y_{1}}{\partial x_{n}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}} \end{array}\right)\left(\begin{array}{c} \frac{\partial l}{\partial y_{1}}\\ \vdots\\ \frac{\partial l}{\partial y_{m}} \end{array}\right)=\left(\begin{array}{c} \frac{\partial l}{\partial x_{1}}\\ \vdots\\ \frac{\partial l}{\partial x_{n}} \end{array}\right)\]

注意:您也可以使用等效的操作 \(v^{T}\cdot J\), 并返回 row 向量。

生成的列向量是第二个函数的梯度,其中 尊重第一个 - 或者在我们的模型的情况下,以及 loss 函数,损失相对于模型的梯度 输入。

''torch.autograd'' 是计算这些产品的引擎。这 是我们如何在 向后传递。

因此,调用还可以采用可选的 向量输入。这个向量表示张量上的一组梯度, 它们乘以 autograd 跟踪张量的雅可比行列式,其中 在它之前。让我们尝试一个具有小向量的特定示例:backward()

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

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

print(y)
tensor([  299.4868,   425.4009, -1082.9885], grad_fn=<MulBackward0>)

如果我们现在尝试调用,我们会收到一个运行时错误和一个 消息,即只能隐式计算标量的梯度 输出。对于多维输出,autograd 希望我们提供 gradients,它可以乘以 雅可比:y.backward()

v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float) # stand-in for gradients
y.backward(v)

print(x.grad)
tensor([1.0240e+02, 1.0240e+03, 1.0240e-01])

(请注意,输出梯度都与 2 的幂有关 - 其中 我们预期会重复加倍操作。

高级 API

autograd 上有一个 API,可让您直接访问重要的 差分矩阵和向量运算。特别是,它允许您 计算特定 函数。(Hessian 曲线类似于 Jacobian,但 表示所有偏阶导数。它还提供了方法 用于取这些矩阵的向量积。

我们以简单函数的雅可比行列式为例,计算为 2 单元件输入:

def exp_adder(x, y):
    return 2 * x.exp() + 3 * y

inputs = (torch.rand(1), torch.rand(1)) # arguments for the function
print(inputs)
torch.autograd.functional.jacobian(exp_adder, inputs)
(tensor([0.7212]), tensor([0.2079]))

(tensor([[4.1137]]), tensor([[3.]]))

如果你仔细观察,第一个输出应该等于 \(2e^x\)(因为 \(e^x\) 的导数是 \(e^x\)),第二个值 应为 3。

当然,您可以使用高阶张量执行此操作:

inputs = (torch.rand(3), torch.rand(3)) # arguments for the function
print(inputs)
torch.autograd.functional.jacobian(exp_adder, inputs)
(tensor([0.2080, 0.2604, 0.4415]), tensor([0.5220, 0.9867, 0.4288]))

(tensor([[2.4623, 0.0000, 0.0000],
        [0.0000, 2.5950, 0.0000],
        [0.0000, 0.0000, 3.1102]]), tensor([[3., 0., 0.],
        [0., 3., 0.],
        [0., 0., 3.]]))

该方法的工作原理相同 (假设你的函数是两倍可微的),但返回一个矩阵 的所有二阶导数。torch.autograd.functional.hessian()

还有一个函数可以直接计算向量 - 雅可比矩阵 product,如果您提供向量:

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

inputs = torch.randn(3)
my_gradients = torch.tensor([0.1, 1.0, 0.0001])
torch.autograd.functional.vjp(do_some_doubling, inputs, v=my_gradients)
(tensor([-665.7186, -866.7054,  -58.4194]), tensor([1.0240e+02, 1.0240e+03, 1.0240e-01]))

该方法执行相同的矩阵 乘法与反向操作数相同。and 方法对向量 Hessian 积执行相同的操作。torch.autograd.functional.jvp()vjp()vhp()hvp()

有关更多信息,包括 docs 上的性能说明。 功能的 应用程序接口

脚本总运行时间:(0 分 0.766 秒)

由 Sphinx-Gallery 生成的图库

文档

访问 PyTorch 的全面开发人员文档

查看文档

教程

获取面向初学者和高级开发人员的深入教程

查看教程

资源

查找开发资源并解答您的问题

查看资源