torch.autograd 的源代码
"""
``torch.autograd`` 提供了实现任意标量值函数的自动微分的类和函数。它只需要对现有代码进行最小的更改 - 您只需要使用 ``requires_grad=True`` 关键字声明 :class:`Tensor` 来计算梯度。
目前,我们仅支持浮点型 :class:`Tensor` 类型的自动微分(half, float, double 和 bfloat16)和复数型 :class:`Tensor` 类型(cfloat, cdouble)。
"""
import warnings
from typing import Any, Callable, cast, List, Optional, Sequence, Tuple, Union
import torch
from torch.types import _size, _TensorOrTensors, _TensorOrTensorsOrGradEdge
from .. import _vmap_internals
from ..overrides import handle_torch_function, has_torch_function, is_tensor_like
from . import forward_ad, functional, graph
from .anomaly_mode import detect_anomaly, set_detect_anomaly
from .function import Function, NestedIOFunction
from .grad_mode import (
_force_original_view_tracking,
_unsafe_preserve_version_counter,
enable_grad,
inference_mode,
no_grad,
set_grad_enabled,
set_multithreading_enabled,
)
from .gradcheck import gradcheck, gradgradcheck
from .graph import _engine_run_backward
from .variable import Variable
__all__ = ["Variable", "Function", "backward", "grad_mode"]
_OptionalTensor = Optional[torch.Tensor]
_ShapeorNestedShape = Union[_size, Sequence[_size], torch.Tensor]
def _calculate_shape(
output: torch.Tensor, grad: torch.Tensor, is_grads_batched: bool
) -> Tuple[_ShapeorNestedShape, _ShapeorNestedShape]:
# is_same_size 确保两个张量要么是嵌套的,要么是非嵌套的
# 循环导入
from torch.nested._internal.nested_tensor import NestedTensor
if output.is_nested and not isinstance(output, NestedTensor):
if is_grads_batched:
raise RuntimeError("Batched grads are not supported with Nested Tensor.")
out_shape = output._nested_tensor_size()
grad_shape = grad._nested_tensor_size()
return out_shape, grad_shape
reg_out_shape = output.shape
reg_grad_shape = grad.shape if not is_grads_batched else grad.shape[1:]
return reg_out_shape, reg_grad_shape
def _make_grads(
outputs: Sequence[torch.Tensor],
grads: Sequence[_OptionalTensor],
is_grads_batched: bool,
) -> Tuple[_OptionalTensor, ...]:
new_grads: List[_OptionalTensor] = []
for out, grad in zip(outputs, grads):
if isinstance(grad, torch.Tensor):
from torch.fx.experimental.symbolic_shapes import expect_true, sym_eq
first_grad = grad if not is_grads_batched else grad[0]
# TODO: 一旦我们统一使用单例 int 来表示不规则维度,我们就可以删除这个条件,这样嵌套张量的 size() 调用就可以工作了
if out.is_nested or first_grad.is_nested:
shape_matches = torch.is_same_size(out, first_grad)
else:
# 我们需要进行常规的 size 检查,而不通过操作符,以便能够处理未支持的 symints
# expect_true 确保我们可以处理未支持的情况
shape_matches = expect_true(sym_eq(out.size(), first_grad.size()))
if not shape_matches:
out_shape, grad_shape = _calculate_shape(
out, first_grad, is_grads_batched
)
if is_grads_batched:
raise RuntimeError(
"If `is_grads_batched=True`, we interpret the first "
"dimension of each grad_output as the batch dimension. "
"The sizes of the remaining dimensions are expected to match "
"the shape of corresponding output, but a mismatch "
"was detected: grad_output["
+ str(grads.index(grad))
+ "] has a shape of "
+ str(grad_shape)
<span class="o