• 文档 >
  • 模块代码 >
  • torch >
  • torch 自动微分
快捷键

源代码 for torch.autograd

# mypy: 允许未类型化定义
""
torch.autograd 提供了实现任意标量值函数自动微分的类和函数。

它只需要对现有代码进行最小改动——你只需声明 :class:`Tensor` s
需要计算梯度的变量应使用 `requires_grad=True` 关键字。
目前,我们仅支持浮点类型 :class:`Tensor` 的 autograd
half、float、double 和 bfloat16)以及复数类型:class:`Tensor`(cfloat、cdouble)。
""

import 警告
from collections.abc import 序列
from 打字 import 演员表, 可选的, 联合

import 火炬
from 火炬 import _vmap 内部
from torch.overrides import handle_torch_function, 具有 torch 函数, 类似于 tensor
from torch 的类型 import _size, _TensorOrTensors, _TensorOrTensorsOrGradEdge

from . import forward_ad, 功能性, 
from .异常模式 import 检测异常, 设置检测异常
from .函数 import 函数, 嵌套 IO 函数
from .梯度模式 import (
    _强制原始视图跟踪,
    _不安全保留版本计数器,
    启用梯度,
    inference_mode,
    不梯度,
    设置梯度启用,
    设置多线程启用,
)
from .gradcheck import gradcheck, gradgradcheck
from .graph import _engine_run_backward
from .变量 import 变量


全部 = [
    "变量",
    "功能",
    "向后",
    "梯度模式",
    "嵌套 IO 函数",
    检测异常,
    启用梯度,
    梯度,
    梯度检查,
    "gradgradcheck",
    "推理模式",
    "关闭梯度",
    "设置检测异常",
    set_grad_enabled,
    set_multithreading_enabled,
    变量,
]

_可选张量 = 可选[PyTorch.张量]
_形状或嵌套形状 = 联合[_大小, 序列[尺寸] PyTorch.张量]


定义 计算_形状(
    输出: 并集[PyTorch.张量, .梯度边缘]
    研究生: PyTorch.张量,
    是否批处理研究生: bool,
) -> 元组[_形状或嵌套形状, _形状或嵌套形状]
    # 确保两个张量要么都是嵌套的,要么都不是嵌套的
    # 循环导入
    from torch.nested._internal.nested_tensor import NestedTensor

    如果 isinstance(输出, .梯度边缘):
        我们已经检查过我们不是 C++嵌套张量
        如果 is_grads_batched:
            提升 RuntimeError(批量梯度不支持与 GradientEdge 一起使用)
        out_metadata = 输出.节点.输入元数据[输出.输出编号]
        返回 PyTorch.大小(输出元数据.形状), 梯度.形状

    如果 输出.是否嵌套 以及  isinstance(输出, 嵌套张量):
        如果 是否批处理梯度:
            提升 RuntimeError("不支持嵌套张量中的批处理梯度。")
        输出形状 = 输出._嵌套张量大小()
        梯度形状 = 梯度._嵌套张量大小()

        返回 输出形状, 梯度形状

    归一化输出形状 = 输出.形状
    归一化梯度形状 = 梯度.形状 如果  是否批处理梯度 否则 梯度.形状[1]
    返回 注册输出形状, 注册梯度形状


定义 _make_grads(
    输出: 联盟[序列[PyTorch.张量] 序列[.梯度边缘]]
    梯度: 序列[可选张量]
    是否批处理梯度: bool,
) -> 元组[可选张量, ...]
    新梯度: 列表[可选张量] = 输入文本为空,请提供需要翻译的文本
     , 毕业生  压缩(输出, 毕业生):
        出去 = 演技(联合[PyTorch.张量, .梯度边缘] 输出)
        输出大小 = 无。
        输出设备 = 无。

        如果 isinstance(输出, .梯度边缘):
            输出元数据 = 输出.节点.输入元数据[输出.输出编号]
            输出大小 = PyTorch.尺寸(输出元数据.形状)
            输出数据类型 = 输出元数据.dtype
            输出设备 = 输出元数据.设备
            输出是否嵌套 = 输出元数据.是否嵌套张量
            如果 输出元数据.是否是 C++嵌套张量:
                抛出 RuntimeError(
                    "C++嵌套 Tensor 不支持与 GradientEdge"
                )
            out_is_cpp_nested = 
        else:
            # 循环导入
            from torch.nested._internal.nested_tensor import NestedTensor

            断言 isinstance(输出, PyTorch.张量)
            输出数据类型 = 输出.dtype
            输出是否嵌套 = 输出.是嵌套的
            输出_is_cpp_nested = 输出_is_nested 以及  isinstance(输出, 嵌套张量)
            如果  输出是 C++嵌套:
                输出大小 = .形状

        如果 isinstance(毕业生, PyTorch.张量):
            from torch.fx.experimental.symbolic_shapes import 预期为真, 等式

            一阶导数 = 梯度 如果  是否梯度批处理 否则 梯度[0]

            # TODO: 我们可以在统一使用后删除此条件
            表示锯齿状维度的单例整型,以便于嵌套张量的 size()调用
            以便于嵌套张量的 size()调用
            如果 输出为 cpp 嵌套:
                断言 isinstance(输出, PyTorch.张量)
                形状匹配 = PyTorch.大小相同(输出, 第一梯度)
            else:
                我们需要做常规大小检查,而不通过操作符
                以便能够处理未备份的符号
                (expect_true 确保我们可以处理未备份的)
                断言 输出大小   无。
                形状匹配 = 预期为真(相等(输出大小, 第一梯度.尺寸()))

            如果  形状匹配:
                外部 = 角色(联合[PyTorch.张量, .梯度边缘] 输出)
                输出形状, 累积形状 = _计算形状(
                    输出, 第一梯度, 是否批处理梯度
                )
                如果 是否批处理梯度:
                    抛出 RuntimeError(
                        如果 `is_grads_batched=True`,我们将每个 grad_output 的第一个维度解释为批维度。
                        "每个 grad_output 的第一个维度被解释为批维度。"
                        "剩余维度的尺寸预期应与"
                        "相应的输出形状相匹配,但检测到不匹配:grad_output["
                        "梯度"
                        + str(梯度.索引(梯度))
                        + "] 形状为 "
                        + str(梯度形状)
                        + " 和输出["
                        + str(输出.索引(输出))
                        + "] 的形状为 "
                        + str(输出形状)
                        + ". "
                        "如果您只想将`grad_output`中的某些张量视为 "
                        "批处理,请考虑使用 vmap。"
                    )
                else:
                    抛出 RuntimeError(
                        "形状不匹配:grad_output["
                        + str(研究生.索引(研究生))
                        + "] 的形状为 "
                        + str(研究生形状)
                        + "和输出["
                        + str(输出.索引())
                        + "]的形状为"
                        + str(输出形状)
                        + "."
                    )
            如果 输出数据类型.是否为复数 != 梯度.数据类型.是复杂的:
                抛出 RuntimeError(
                    对于复杂的张量,grad_output 和 output
                    都需要具有相同的数据类型。
                    "dtype 不匹配:grad_output["
                    + str(梯度.索引(梯度值))
                    + "]的数据类型为"
                    + str(研究生.数据类型)
                    + "并且输出["
                    + str(输出.索引(输出))
                    + "] 的数据类型为 "
                    + str(输出数据类型)
                    + “点”
                )
            新毕业生.添加(毕业)
        elif 毕业  :
            如果 isinstance(, .梯度边缘) 或者 .需要梯度:  # 类型:忽略[已定义]
                如果 isinstance(, .梯度边缘):
                    断言 输出大小   无。
                    输出元素数量为 1 = 所有(o == 1  o  输出大小)
                else:
                    断言 isinstance(输出, PyTorch.张量)
                    out_numel_is_1 = 输出.元素数量() == 1
                如果  out_numel_is_1:
                    提升 RuntimeError(
                        "梯度只能为标量输出隐式创建"
                    )
                如果  out_dtype.is_floating_point:
                    msg = (
                        "梯度只能为实数标量输出隐式创建"
                        f"但得到了"{out_dtype}"
                    )
                    提升 RuntimeError(消息)
                如果 isinstance(输出, .梯度边缘):
                    断言 输出大小   无。
                    断言 输出设备   无。
                    新员工.添加(
                        PyTorch.(
                            输出大小,
                            数据类型=输出数据类型,
                            设备=输出设备,
                        )
                    )
                else:
                    断言 isinstance(输出, PyTorch.张量)
                    新梯度.添加(
                        PyTorch.喜欢的(, 内存格式=PyTorch.保留格式)
                    )
            else:
                新毕业生.添加()
        else:
            提升 TypeError(
                "梯度可以是张量或 None,但得到了"
                + 类型(梯度).__name__
            )
    返回 元组(新梯度)


定义 张量或张量到元组的转换(
    张量: 可选[_TensorOrTensors] 长度: 整型
) -> 元组[可选张量, ...]
    如果 张量  :
        返回 (,) * 长度
    如果 isinstance(张量, PyTorch.张量):
        返回 (张量,)
    返回 元组(张量)


[文档]定义 反向( 张量: _张量或张量或梯度边, 累加张量: 可选[_张量或张量列表] = , 保留图结构: 可选[bool] = , 创建图: 布尔 = False, 梯度变量: 可选[_Tensor 或 Tensors] = , 输入: 可选[_Tensor 或 Tensors 或 GradEdge] = , ) -> : r计算给定张量相对于图叶的梯度之和。 使用链式法则对图进行微分。如果任何 ``tensors`` 是非标量(即其数据包含多个元素)并且需要 梯度,则将计算雅可比-向量积。 函数还需要额外指定 ``grad_tensors``。 它应该是一个长度匹配的序列,包含“向量” 在雅可比-向量乘积中,通常是相对于对应张量的函数梯度(``None`` 是对于该值的可接受值) 相对于对应张量的函数梯度(``None`` 是一个可接受值) 所有不需要梯度张量的张量。 此函数在叶子节点中累积梯度 - 你可能需要将其清零。 在调用之前,请查看 `.grad` 属性或将其设置为 `None`。 请参阅::ref:`默认梯度布局`。 关于累积梯度的内存布局详情。 .. 注意: 使用此方法并设置 `create_graph=True` 将创建一个引用循环 参数及其梯度之间可能导致内存泄漏。 我们建议在创建图时使用 `autograd.grad` 来避免这种情况。 如果您必须使用此函数,请确保在使用后重置参数的 `.grad` 字段为 `None` 以断开循环并避免泄漏。 参数的 `.grad` 字段重置为 `None`,以断开循环并避免泄漏。 .. 注意:: 如果您运行任何前向操作,创建 `grad_tensors`,以及/或调用 `backward` 在用户指定的 CUDA 流上下文中,请参阅 ref:`反向传播的流语义`. .. 注意:: 当提供 `inputs` 并给定输入不是叶子节点时, 当前实现将调用其 grad_fn(即使严格来说不需要获取这些梯度)。 这是一个实现细节,用户不应依赖。 更多详情请见 https://github.com/pytorch/pytorch/pull/60521#issuecomment-867061780。 参数: 张量(Sequence[Tensor] 或 Tensor 或 Sequence[GradientEdge] 或 GradientEdge):张量 导数将被计算。 grad_tensors (Sequence[Tensor 或 None]或 Tensor, 可选): "向量" 雅可比-向量积,通常是对每个元素的梯度 对应的张量。对于标量张量或不需要梯度的张量,可以指定 None 值。 如果 None 值对所有不需要梯度的张量都适用。 如果 grad_tensors 可以接受 None 值,则此参数是可选的。 retain_graph(布尔值,可选):如果为 False,则用于计算梯度的图将被保留。 将被释放。请注意,在几乎所有情况下,将此选项设置为“True” 不需要,通常可以通过更有效的方法来解决这个问题 方式。默认为 `create_graph` 的值。 创建图(布尔值,可选):如果 ``True``,则创建导数的图 可构建,以便计算高阶导数乘积。 默认为 ``False``。 输入(Sequence[Tensor] 或 Tensor 或 Sequence[GradientEdge],可选):相对于这些输入的梯度 将累积到 ``.grad`` 中。所有其他 Tensor 都将被忽略。如果 未提供,梯度累积到所有叶张量中 用于计算::`tensors`。 """ 如果 PyTorch._C.都是 functorch 转换激活(): 提升 RuntimeError( backward() 在 functorch 转换内部调用。这并不是“ "请使用 functorch.grad 或 functorch.vjp 代替" "或在 functorch 转换外部调用 backward()。" ) 如果 梯度变量 : 警告.警告( "`grad_variables` 已弃用。请使用 `grad_tensors` 代替。", 未来警告, 栈级别=2, ) 如果 grad_tensors : grad_tensors = grad_variables else: 提升 RuntimeError( "`grad_tensors` 和 `grad_variables`(已弃用)" "两个参数都传递给 `backward()`。请只" 使用 `grad_tensors`。 ) 如果 输入 无。 以及 len(输入) == 0: 提升 RuntimeError(`backward()` 函数的 `inputs` 参数不能为空。) 如果 is_tensor_like(张量) 或者 isinstance(张量, .梯度边缘): 张量 = 投射( 联盟[元组[PyTorch.张量] 元组[.梯度边缘]] (张量,) ) else: 张量 = 元组(张量) 输入 = ( (输入,) 如果 isinstance(输入, (PyTorch.张量, .梯度边缘)) 否则 元组(输入) 如果 输入 无。 否则 () ) grad_tensors_ = _tensor_or_tensors_to_tuple(梯度张量, len(张量)) 梯度张量_ = _make_grads(张量, grad_tensors_, 是否批处理梯度=False) 如果 保留图 : 保留图 = 创建图 我们重复下面相同的注释的原因是 一些 Python 版本会在跟踪回溯中打印出多行函数的第一行调用 以及一些打印出最后一行 _engine_run_backward( 张量, grad_tensors_, 保留图, 创建图, 输入, 允许不可达=True, 累加梯度=True, )
[文档]定义 梯度( 输出: _张量或张量或梯度边, 输入: _张量或张量或梯度边, 梯度输出: 可选[_张量或张量列表] = , 保留图结构: 可选[bool] = , 创建图: 布尔 = False, 仅输入: 布尔 = True, 允许未使用: 可选[bool] = , 是否批处理梯度: 布尔 = False, 实现梯度: 布尔 = False, ) -> 元组[PyTorch.张量, ...] r计算并返回输出相对于输入的梯度的总和。 ``grad_outputs`` 应该是一个长度与 ``output`` 匹配的序列 包含向量-雅可比乘积中的 "vector",通常是预先计算的 对每个输出的梯度。如果一个输出不需要 require_grad,那么梯度可以是 ``None``)。 .. 注意:: 如果您运行任何前向操作,创建 ``grad_outputs``,以及/或调用 ``grad`` 在用户指定的 CUDA 流上下文中,请参阅 ref:`反向传播的流语义`. .. 注意: ``only_inputs`` 参数已弃用,现在将被忽略(默认为 ``True``)。 要累积图的其他部分的梯度,请使用 ``torch.autograd.backward``。 参数: 输出(Tensor 或 GradientEdge 序列):微分函数的输出。 输入(Tensor 或 GradientEdge 序列):相对于该梯度将被返回(而不是累积到 ``.grad`` 中)的输入。 返回值(序列 Tensor):向量-雅可比积中的“向量”。 grad_outputs(序列 Tensor):向量-雅可比积中的“向量”。 通常针对每个输出计算梯度。可以指定标量值。 张量或不需要梯度的项。如果 None 值可以接受的话。 对于所有 grad_tensors,此参数是可选的。默认:None。 retain_graph(布尔值,可选):如果为 False,则不保留用于计算梯度的图。 将被释放。请注意,在几乎所有情况下,将此选项设置为“True” 不需要,通常可以通过更有效的方法来解决这个问题 方式。默认为 `create_graph` 的值。 创建图(布尔值,可选):如果 ``True``,则创建导数的图 可以构建,以便计算高阶导数乘积。 默认:``False``。 允许未使用(Optional[bool],optional):如果 ``False``,指定输入 未被用于计算输出(因此它们的梯度为) 总是零(zero)是一个错误。默认为 `materialize_grads` 的值。 is_grads_batched (bool, 可选): 如果 ``True``,每个的每一维度的梯度将被批处理 张量在 `grad_outputs` 中将被解释为批量维度。 而不是计算单个向量-雅可比乘积,我们计算 每个批次中每个“向量”的向量-雅可比积批次。 我们使用 vmap 原型功能作为后端以向量化调用 输入到自动微分引擎中,以便这个计算可以执行 单次调用。与之前相比,这应该会带来性能提升。 手动循环并多次执行反向操作。注意, 由于此功能为实验性,可能会有性能 请使用 `torch._C._debug_only_display_vmap_fallback_warnings(True)` 来显示任何性能警告,如果存在警告,请在 github 上提交问题 以显示任何性能警告,如果存在警告,请在 github 上提交问题 适用于您的用例。默认为 ``False``。 materialize_grads (bool, 可选): 如果 ``True``,将未使用输入的梯度设置为 ``None``。 而不是 ``None``。这在计算高阶导数时很有用。 如果 ``materialize_grads`` 为 ``True`` 且 ``allow_unused`` 为 ``False``,则会引发错误 将抛出异常。默认为 ``False``。 """ 如果 材料化梯度 以及 允许未使用 False: 提升 值错误( "预期 allow_unused 应为 True 或在 materialize_grads=True 时未传递," "但得到:allow_unused=False。" ) 如果 允许未使用 : 允许未使用 = 材料化梯度 如果 是否与张量类似(输出) 或者 isinstance(输出, .梯度边缘): 输出 = 角色( 联盟[序列[PyTorch.张量] 序列[.梯度边缘]] (输出,) ) else: 输出 = 元组(输出) 如果 类似于张量(输入) 或者 isinstance(输入, .梯度边缘): 输入 = 角色(_张量或张量或梯度边, (输入,)) else: 输入 = 元组(输入) 输出 = 元组(i i 输出 如果 是否为张量类型(i)) 输入张量 = 元组(i i 输入 如果 类似张量的(i)) 可覆盖的参数 = 输出 t + 输入 如果 有 torch 功能(可覆盖的参数): 返回 handle_torch_function( 梯度, 可覆盖的参数, 输出, 输入, 梯度输出=梯度输出, 保留图=保留图, 创建图=创建图, 仅输入=仅输入, 允许未使用=允许未使用, 是否批处理梯度=是否批处理梯度, 材料化梯度=材料渐变, ) 如果 仅输入: 警告.警告( "only_inputs 参数已弃用,现在将忽略。" "(默认为 True)。要累积图的其他部分的梯度,请使用 torch.autograd.backward。" "部分,请使用 torch.autograd.backward。", FutureWarning, 栈级别=2, ) grad_outputs_ = _tensor_or_tensors_to_tuple(grad_outputs, len(outputs)) grad_outputs_ = _make_grads( outputs, grad_outputs_, 是否梯度批处理=是否梯度批处理 ) 如果 是否保留图 : 是否保留图 = 创建图 # 以下重复多次注释的原因是因为 # 一些 Python 版本在堆栈跟踪中打印多行函数的第一个调用行 # 一些则打印最后一个调用行 如果 是否批处理梯度: 定义 反向传播(gO): 返回 _engine_run_backward( 输出, gO, 保留图, 创建图, 输入, 允许未使用, 累加梯度=False, ) 结果 = _vmap 内部._vmap(vjp, 0, 0, 允许空值通过=True)( grad_outputs_ ) else: 结果 = _engine_run_backward( outputs, grad_outputs_, retain_graph, 创建图, 输入, 允许未使用, 累加梯度=False, ) 如果 材料化梯度: 如果 任何( 结果[i] 无。 以及 是否与张量类似(输入[i]) i 范围(len(输入)) ): 提升 RuntimeError( "当给定的输入是梯度边时,不能使用 materialize_grads" ) 结果 = 元组( 输出 如果 输出 无。 否则 PyTorch.等于零的(输入, 需要梯度=True) (输出, 输入) zip(结果, 输入) ) 返回 结果
# 此函数适用于梯度检查点的情况 # 优化。目前,仅在通过 torch.autograd.backward()调用执行引擎时,才支持梯度检查点 # # 如果执行引擎是通过 torch.autograd.backward()调用的,则当前支持梯度检查点 输入参数未传递。torch.autograd.grad()不支持。 这是因为如果指定了输入,则不会计算梯度 # 其他内容,例如模型参数如权重、偏差等。 # 此函数返回检查点是否有效,即 torch.autograd.backward # 或不,即 torch.autograd.grad。该实现通过维护一个线程 本地变量在 torch/csrc/autograd/engine.cpp 中,用于查看节点任务 在栈中,并在 evaluate_function 中执行 NodeTask 之前 检查是否必须使用可重入的向后操作。 请参阅 https://github.com/pytorch/pytorch/pull/4594 以获取更多讨论/上下文 定义 _is_checkpoint_valid(): 返回 变量._execution_engine.is_checkpoint_valid() 定义 变量(*参数, **关键字参数): # 无需注意:D103 提升 RuntimeError( torch.autograd.variable(...) 已弃用,请使用 torch.tensor(...) 代替 ) # 钩子变量.Variable 以修复 FX 代码生成问题。FX 大致通过以下方式生成调用 # f"{fn.__module__}.{fn.__name__}(...). 这会产生 torch.autograd.variable.Variable(...) 在 # torch.autograd.variable 模块被不幸地遮蔽了。 # 已弃用的函数 - variable(...)。 variable.变量 = 变量 # 类型:忽略[已定义] 如果 PyTorch._C._autograd_init(): 提升 RuntimeError(自动微分初始化失败) 导入所有原生方法/类 from torch._C._autograd import ( _add_metadata_json, _disable_profiler, _disable_profiler_legacy, 启用分析器, 启用分析器(旧版), 启用记录函数, 获取序列号, 动态步进, 动态事件, 默认钩子保存 pop 张量, 准备分析器, _profiler_enabled, _ProfilerResult, _push_saved_tensors_default_hooks, _record_function_with_args_enter, 记录带参数的函数退出, 设置空测试观察者, 支持的活动, 切换集合动态, 设备类型, 动作可用, 分析器事件, 保存张量, ) from torch._C._profiler import 分析器活动, 分析器配置, 分析器状态 from . import 分析器 定义 为设备注册 Python 张量类(设备, cls): 如果 isinstance(cls, 类型): 提升 RuntimeError("cls 不是一个 typeinfo 对象") PyTorch._C.为设备注册 Python 类(设备, cls) 多线程启用 = PyTorch._C._多线程启用_ PyTorch._C._添加文档字符串_( 多线程启用, "当前是否已启用多线程。" ) 是否启用视图回放 = PyTorch._C._是否启用视图回放 PyTorch._C._添加文档字符串( 视频回放是否已启用, 如果当前已启用视频回放,则返回 True。 )

© 版权所有 PyTorch 贡献者。

使用 Sphinx 构建,并使用 Read the Docs 提供的主题。

文档

PyTorch 的全面开发者文档

查看文档

教程

深入了解初学者和高级开发者的教程

查看教程

资源

查找开发资源并获得您的疑问解答

查看资源