# mypy: 允许未类型化定义
导入 functools
导入
检查
导入 itertools
导入
警告
来自
集合
导入 OrderedDict
来自
打字
导入
任何,
可选
来自 typing_extensions
导入
已弃用
导入
火炬
导入 torch._C as _C
导入 torch._functorch as _functorch
导入 torch.utils.hooks as
钩子
来自 torch._C
导入
函数
来自 torch._functorch.autograd_function
导入
自定义函数调用
全部 = [
函数上下文,
向后 C 函数,
"功能元",
"功能",
"一次可微分",
"就地函数",
"嵌套 IO 函数",
]
# 每个继承自 Function 的类的唯一 ID 提供者
# 在类定义期间在 FunctionMeta 中递增
AUTOGRAD_FUNCTION_COUNTER = itertools.数量()
# 之前称为:_ContextMethodMixin
类
函数上下文:
[文档] def
保存用于回放(self, *
张量:
PyTorch.
张量):
r将给定的张量保存以供后续调用 :func:`~Function.backward`。
``save_for_backward`` 应最多调用一次,在 :func:`setup_context` 或 :func:`forward` 方法中,并且仅针对张量。
所有打算在反向传播中使用的张量都应该被保存。
所有打算在反向传播中使用的张量都应该被保存。
使用 `save_for_backward`(而不是直接在 `ctx` 上)来防止
不正确的梯度计算和内存泄漏,并启用保存张量的钩子应用。
查看 :class:`torch.autograd.graph.saved_tensors_hooks`。
注意,如果中间张量,即既不是输入也不是输出的张量
forward 函数的输出在反向传播时不会被保存,您的自定义函数
可能不支持双重反向传播。
不支持双重反向传播的自定义函数应该使用 ``@once_differentiable`` 装饰其
backward 方法,以便执行
双向求导会引发错误。如果您想支持双向求导,
您可以选择根据输入在反向过程中重新计算中间变量,
或者将中间变量作为自定义函数的输出返回。请参阅 `双向求导教程 `_
`双向求导教程 `_
更多详情请查看。
在 :func:`backward` 函数中,可以通过 :attr:`saved_tensors` 属性访问保存的张量。
在将它们返回给用户之前,会进行检查以确保它们没有被用于任何修改其内容的就地操作。
属性。在返回之前,会检查它们是否被用于任何修改其内容的就地操作。
参数也可以是 `None`。这是一个无操作。
更多关于如何使用此方法的详细信息,请参阅 :ref:`扩展 autograd`。
示例::
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_AUTOGRAD)
>>> class Func(Function):
>>> @staticmethod
>>> def forward(ctx, x: torch.Tensor, y: torch.Tensor, z: int):
>>> w = x * z
>>> out = x * y + y * z + w * y
>>> ctx.save_for_backward(x, y, w, out)
>>> ctx.z = z # z 不是张量
>>> return out
...
>>> @staticmethod
>>> @once_differentiable
>>> def backward(ctx, grad_out):
>>> x, y, w, out = ctx.saved_tensors
>>> z = ctx.z
>>> gx = grad_out * (y + y * z)
>>> gy = grad_out * (x + z + w)
>>> gz = None
>>> return gx, gy, gz
...
>>> a = torch.tensor(1., requires_grad=True, dtype=torch.double)
>>> b = torch.tensor(2., requires_grad=True, dtype=torch.double)
>>> c = 4
>>> d = Func.apply(a, b, c)
"""
self.保存 =
张量
def 保存以供转发(self, *
张量:
PyTorch.
张量):
r将给定的张量保存,以供将来调用 :func:`~Function.jvp` 的调用。
``save_for_forward`` 应最多调用一次,无论是在 ...
`setup_context` 或 `forward` 方法,以及所有参数
应该是张量。
在 `jvp` 中,可以通过 `saved_tensors` 属性访问已保存的对象。
属性。
参数也可以是 `None`。这是一个无操作。
更多关于如何使用此方法的详细信息,请参阅 :ref:`扩展 autograd`。
示例::
>>> # xdoctest: +SKIP
>>> class Func(torch.autograd.Function):
>>> @staticmethod
>>> def forward(ctx, x: torch.Tensor, y: torch.Tensor, z: int):
>>> ctx.save_for_backward(x, y)
>>> ctx.save_for_forward(x, y)
>>> ctx.z = z
>>> 返回 x * y * z
...
>>> @staticmethod
>>> def jvp(ctx, x_t, y_t, _):
>>> x, y = ctx.saved_tensors
>>> z = ctx.z
>>> return z * (y * x_t + x * y_t)
...
>>> @staticmethod
>>> def vjp(ctx, grad_out):
>>> x, y = ctx.saved_tensors
>>> z = ctx.z
>>> return z * grad_out * y, z * grad_out * x, None
...
>>> a = torch.tensor(1., requires_grad=True, dtype=torch.double)
>>> t = torch.tensor(1., dtype=torch.double)
>>> b = torch.tensor(2., requires_grad=True, dtype=torch.double)
>>> c = 4
...
>>> with fwAD.dual_level():
>>> a_dual = fwAD.make_dual(a, t)
>>> d = Func.apply(a_dual, b, c)
"""
for 张量
在
张量:
断言 isinstance(
张量,
PyTorch.
张量)
或者
张量
是
无, (
"save_for_forward 期望所有参数都是张量;你应该 "
"将非张量作为 ctx 的属性保存。"
)
self.保存以供转发 =
张量
[文档] def mark_dirty(self, *args: torch.Tensor):
r"""将给定的张量标记为就地操作中的已修改。
这应该在 :func:`setup_context` 中最多调用一次。
或:func:`forward` 方法,所有参数应为输入。
每个在调用 :func:`forward` 中就地修改的张量
应传递给此函数,以确保我们检查的正确性。
它无关紧要,函数是在调用之前还是之后
修改。
示例::
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_AUTOGRAD)
>>> class Inplace(函数):
>>> @staticmethod
>>> def forward(ctx, x):
>>> x_npy = x.numpy() # x_npy 与 x 共享存储
>>> x_npy += 1
>>> ctx.mark_dirty(x)
>>> 返回 x
>>>
>>> @staticmethod
>>> @once_differentiable
>>> def backward(ctx, grad_output):
>>> return grad_output
>>>
>>> a = torch.tensor(1., requires_grad=True, dtype=torch.double).clone()
>>> b = a * a
>>> Inplace.apply(a) # 这会导致错误的梯度!
>>> # 但引擎不知道,除非我们标记为脏
>>> # xdoctest: +SKIP
>>> b.backward() # 运行时错误:所需的变量之一在就地操作中被修改以进行梯度计算
>>> # 计算过程中所需的变量已被就地操作修改
"""
self.dirty_tensors = args
@deprecated(
"`mark_shared_storage` 已弃用。"
具有共享存储的张量会自动跟踪。
注意,对 `set_()` 的调用不会被跟踪。,
分类=
未来警告,
)
def mark_shared_storage(self, *pairs):
通过
[文档] def mark_non_differentiable(self, *args: torch.Tensor):
r"""标记输出为不可微分。
这应该在 :func:`setup_context` 中最多调用一次,
或:func:`forward` 方法,所有参数应为张量输出。
这将标记输出不需要梯度,增加
反向计算的效率。您仍然需要接受梯度
对于每个输出在::meth:`~Function.backward`中,但它始终会
与相应输出的形状相同的零张量
例如,用于从排序中返回的索引。请参见示例:
这用于例如从排序中返回的索引。请参见示例:
class Func(Function):
>>> @staticmethod
>>> def forward(ctx, x):
>>> sorted, idx = x.sort()
>>> ctx.mark_non_differentiable(idx)
>>> ctx.save_for_backward(x, idx)
>>> return sorted, idx
>>>
>>> @staticmethod
>>> @once_differentiable
>>> def backward(ctx, g1, g2): # 仍然需要接受 g2
>>> x, idx = ctx.saved_tensors
>>> grad_input = torch.zeros_like(x)
>>> grad_input.index_add_(0, idx, g1)
>>> return grad_input
"""
self.non_differentiable = args
[文档] def set_materialize_grads(self, value: bool):
r"""设置是否实例化梯度张量。默认为 ``True``。
应仅从 :func:`setup_context` 或
func:`forward` 方法中调用。
如果为 ``True``,未定义的梯度张量将被扩展为全零的张量
在调用 :func:`backward` 和 :func:`jvp` 方法之前。
示例::
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_AUTOGRAD)
>>> class SimpleFunc(Function):
>>> @staticmethod
>>> def forward(ctx, x):
>>> return x.clone(), x.clone()
>>>
>>> @staticmethod
>>> @once_differentiable
>>> def backward(ctx, g1, g2):
>>> 返回 g1 + g2 # 无需检查 None
>>>
>>> 我们修改 SimpleFunc 以处理非物化梯度输出
>>> class Func(Function):
>>> @staticmethod
>>> def forward(ctx, x):
>>> ctx.set_materialize_grads(False)
>>> ctx.save_for_backward(x)
>>> 返回 x 的克隆,x 的克隆
>>>
>>> @staticmethod
>>> @once_differentiable
>>> def backward(ctx, g1, g2):
>>> x, = ctx.saved_tensors
>>> grad_input = torch.zeros_like(x)
>>> if g1 is not None: # 我们现在必须检查 None
>>> grad_input += g1
>>> 如果 g2 不为 None:
>>> grad_input += g2
>>> 返回 grad_input
>>>
>>> a = torch.tensor(1., requires_grad=True)
>>> b, _ = Func.apply(a) # 诱导 g2 未定义
"""
self.materialize_grads = value
# DO NOT USE: 仅用于加载旧序列化模型
_ContextMethodMixin = 函数上下文
类 _HookMixin:
@staticmethod
def _register_hook(后退钩子, hook):
如果 backward_hooks
是
无:
backward_hooks = 有序字典()
handle = 钩子.
可移除句柄(
后退钩子)
后退钩子[
处理.id] =
钩子
返回
后退钩子, handle
[文档]类 BackwardCFunction(_C._FunctionBase, FunctionCtx, _HookMixin):
r"""
这个类用于内部自动微分工作。请勿使用。
"""
[文档] def apply(self, *args):
r"""
应用在执行此节点时使用的反向方法
```python
# 输入文本
input_text = '"""'
# 翻译函数(此处为示例,实际翻译功能需调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 假设的翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
# _forward_cls 由派生类定义
用户应定义反向或 vjp,但不能同时定义两者。
backward_fn = self._forward_cls.backward # 忽略属性定义
vjp_fn = self._forward_cls.vjp # 忽略属性定义
if backward_fn is not Function.backward and vjp_fn is not Function.vjp:
raise RuntimeError(
实现自定义函数的“反向”和“vjp”功能
不允许同时实现这两个功能。您应该只实现其中一个
的功能。
)
user_fn = vjp_fn if vjp_fn is not Function.vjp else backward_fn
return user_fn(self, *args)
[文档] def apply_jvp(self, *args):
r"""
在执行前向模式自动微分时使用的方法
"""
# _forward_cls 由派生类定义
return self._forward_cls.jvp(self, *args) # 类型:忽略[属性定义]
def _compiled_autograd_key(self): return self._forward_cls._compiled_autograd_key(self) # 类型:忽略[属性定义]
类
函数元信息(
类型):
函数元类。
这个元类设置了以下属性:
_backward_cls:对应于微分操作的函数类
此函数的版本(由该函数动态生成)
元类
"""
def __init__(类,
名称, bases,
属性):
backward_fn = 类型(
名称 +
"向后", (
向后 C 函数,), {"_forward_cls":
类}
)
backward_fn.自动微分函数 ID =
下一(AUTOGRAD_FUNCTION_COUNTER)
# 类型:忽略[已定义]
backward_fn._bw_module = 无
# 类型:忽略[已定义]
如果 getattr(
类,
_lazy_backward_info,
无):
backward_fn._bw_module = 类._lazy_backward_info.bw_module
# 类型:忽略[已定义]
类._backward_cls = backward_fn
超级().__init__(
名称, bases,
属性)
类
单级函数(
_C._函数基类,
函数上下文, _HookMixin,
元类=
函数元信息
):
@staticmethod
def 前向(*
参数:
任何, **kwargs:
任何) ->
任何:
r定义自定义自动微分函数的前向操作。
此函数必须由所有子类重写。
定义前向有两种方式:
使用 1(组合前向和 ctx):
@staticmethod
def forward(ctx: Any, *args: Any, **kwargs: Any) -> Any:
通过
- 它必须接受一个上下文 ctx 作为第一个参数,后面可以跟任何
参数数量(张量或其他类型)。
- 更多详情请参阅 :ref:`结合前向上下文`
使用方法 2(分离前向和 ctx)::
@staticmethod
def forward(*args: Any, **kwargs: Any) -> Any:
通过
@staticmethod
def setup_context(ctx: Any, inputs: Tuple[Any, ...], output: Any) -> None:
通过
前向函数不再接受 ctx 参数。
取而代之,您必须重写 :meth:`torch.autograd.Function.setup_context`
静态方法来处理设置 ``ctx`` 对象。
``output`` 是前向的输出,``inputs`` 是输入的元组
到前向的。
- 更多详情请参阅 :ref:`extending-autograd`
上下文可以用来存储任意数据,然后
在反向传播过程中检索。张量不应直接存储在 `ctx` 上(尽管这目前没有强制执行,以保持向后兼容)。相反,如果张量打算用于反向传播,则应使用 :func:`ctx.save_for_backward` 保存。
直接在 `ctx` 上(尽管这目前没有强制执行,以保持向后兼容)。相反,张量应保存为 :func:`ctx.save_for_backward`,如果它们打算用于反向传播。
(尽管这目前没有强制执行,以保持向后兼容)。相反,如果张量打算用于反向传播,则应使用 :func:`ctx.save_for_backward` 保存。
如果它们打算用于反向传播,则应使用 :func:`ctx.save_for_backward` 保存。
``backward``(等价于 ``vjp``)或 :func:`ctx.save_for_forward`
如果它们打算用于 ``jvp``。
"""
抛出
不支持的操作异常(
"你必须实现自定义 autograd.Function 的前向函数。"
)
@staticmethod
def 设置上下文(ctx:
任何,
输入:
元组[Any, ...
]
输出:
任何) ->
任何:
r"""定义 autograd.Function 的前向传递有两种方式。
Either:
1. 使用签名 `forward(ctx, *args, **kwargs)` 覆盖 forward。
`setup_context` 未被覆盖。设置 ctx 用于 backward 发生在 `forward` 内部。
发生在 `forward` 内部。
2. 使用签名 `forward(*args, **kwargs)` 覆盖 forward 并
覆盖 `setup_context`。设置 ctx 以支持向后操作
在 `setup_context` 内部(与在 `forward` 内部相对)
请参阅 :meth:`torch.autograd.Function.forward` 和 :ref:`extending-autograd` 以获取更多详细信息。
"""
抛出
不支持的操作异常(
"setup_context 尚未实现。")
@staticmethod
def 反向(ctx:
任何, *grad_outputs:
任何) ->
任何:
r定义使用向后模式自动微分对操作进行求导的公式。
此函数必须由所有子类重写。
定义此函数等同于定义 ``vjp`` 函数。
它必须接受一个上下文 :attr:`ctx` 作为第一个参数,后面可以跟
任意多个输出,这些输出与 :func:`forward` 返回的相同(对于非张量输出,将传递 None),
逗号分隔,逗号后面可以跟任意多个输出,这些输出与 :func:`forward` 返回的相同(对于非张量输出,将传递 None),
应返回与输入数量相同的张量,
func:`forward`。每个参数是相对于给定输出的梯度,
每个返回值应该是相对于相应输入的梯度。
如果一个输入不是张量,或者是一个非张量的张量,
需要梯度时,您可以为该输入传递 None 作为梯度。
上下文可以用来检索在正向传播过程中保存的张量
通过。它还有一个属性::attr:`ctx.needs_input_grad` 作为元组
表示每个输入是否需要梯度的布尔值。例如:
`:func:`backward` 将设置 `ctx.needs_input_grad[0] = True`,如果 `:func:`forward` 的第一个输入需要计算关于输出的梯度。
第一个输入需要计算关于输出的梯度。
您必须实现 `backward` 或 `vjp` 方法之一。
"""
抛出
不支持的操作异常(
"你必须实现 `backward` 或 `vjp` 方法之一。"
"自定义 autograd.Function 以使用它进行反向传播"
"模式 AD。"
)
# vjp 和 backward 是彼此的别名
vjp = 向后
@staticmethod
def jvp(ctx: 任何, *
梯度输入:
任何) ->
任何:
r定义使用前向模式自动微分进行操作微分的公式。
此函数必须由所有子类重写。
它必须接受一个上下文 :attr:`ctx` 作为第一个参数,后面可以跟
如 :func:`forward` 所获得的那么多输入(将传递 None)
对于前向函数的非张量输入),
应返回与输出数量相同的张量,
func:`forward`。每个参数是相对于给定输入的梯度,
每个返回值应该是相对于相应输入的梯度。
相应的输出。如果输出不是张量或者该函数对输出不可微分,你可以为该输入传递 None 作为梯度。
你可以使用:attr:`ctx`对象从正向传递任何值到这个函数。
你可以传递 None 作为该输入的梯度。
你可以使用:attr:`ctx`对象从正向传递任何值到这个函数。
函数。
"""
抛出
不支持的操作异常(
您必须实现自定义的 jvp 函数
自动微分的前向模式 AD 使用的 autograd.Function。
)
[文档]
类
函数(
单级函数):
r基础类,用于创建自定义 `autograd.Function`。
创建自定义 `autograd.Function`,继承此类并实现
the :meth:`forward` 和 :meth:`backward` 静态方法。然后,为了使用您的自定义
在正向传播中,调用类的 ``apply`` 方法。不要调用
直接使用 :meth:`forward` 方法。
确保正确性和最佳性能,请确保您正在调用正确的
``ctx`` 上的正确方法,并使用 :func:`torch.autograd.gradcheck` 验证您的反向函数。
使用 :func:`torch.autograd.gradcheck` 验证您的反向函数。
查看更多关于如何使用此类的详细信息,请参阅::ref:`extending-autograd`。
示例:
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_AUTOGRAD)
>>> class Exp(Function):
>>> @staticmethod
>>> def forward(ctx, i):
>>> result = i.exp()
>>> ctx.save_for_backward(result)
>>> return result
...
>>> @staticmethod
>>> def backward(ctx, grad_output):
>>> result, = ctx.saved_tensors
>>> return grad_output * result
...
>>> # 使用它,请调用 apply 方法:
>>> # xdoctest: +SKIP
>>> output = Exp.apply(input)
"""
def __init__(self, *参数, **kwargs):
警告.
警告(
f"{self.类}
应该不被实例化。自动微分函数的方法
都是静态的,所以你应该在类本身上调用它们。
实例化一个 autograd 函数将引发一个
错误出现在 PyTorch 的将来版本中。,
弃用警告,
栈级别=2,
)
def __调用__(self, *
参数, **kwargs):
抛出
运行时错误(
遗留的具有非静态前向方法的 autograd 函数已弃用。
请使用具有静态前向方法的新的 autograd 函数。
"(示例:https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function)"
)
""
指定 PyTorch 是否尝试自动生成布尔值
func:`torch.vmap` 对此 autograd.Function 的支持。您可能需要将其设置为
仅当此 autograd.Function 的 forward、backward 和 jvp(如果有的话)为 True
存在(exist)的函数是用 PyTorch 操作编写的;否则,请覆盖
使用 :meth:`torch.autograd.Function.vmap` 添加对 :func:`torch.vmap` 的支持。
更多详情请参阅 :ref:`func-autograd-function`。
"""
generate_vmap_rule = 假
[文档] @staticmethod
def vmap(info, in_dims, *args):
在 :func:`torch.vmap` 下定义此 autograd.Function 的行为。
为了使 :func:`torch.autograd.Function` 支持
`torch.vmap`,你必须重写这个静态方法,或者将`generate_vmap_rule`设置为`True`(你不能两者都做)。
如果你选择重写这个 staticmethod:它必须接受一个`info`对象作为第一个参数。`info.batch_size`
如果你选择重写这个静态方法:它必须接受
- 一个`info`对象作为第一个参数。`info.batch_size`
指定了进行 vmapped 的维度大小,
而 `info.randomness` 是传递给 :func:`torch.vmap` 的随机性选项,
func:`torch.vmap`。
- 作为第二个参数的 `in_dims` 元组。
对于每个 arg 在`args`中,`in_dims`都有一个对应的
``Optional[int]``. 它是 ``None`` 如果参数不是一个张量或者
参数没有被映射到虚拟内存中,否则它是一个整数
指定 Tensor 的哪个维度正在被 vmapped。
`*args` 与 :meth:`~Function.forward` 的参数相同。
vmap 静态方法的返回值是一个 `(output, out_dims)` 的元组。
与 `in_dims` 类似,`out_dims` 应该与 `output` 具有相同的结构。
`output` 和包含一个 `out_dim` 的结构,每个 `out_dim` 指定每个输出是否
输出具有 vmapped 维度及其索引。
请参阅::ref:`func-autograd-function` 了解更多详情。
```python
# 输入文本
input_text = '"""'
# 翻译函数(此处为示例,实际翻译功能需调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 假设的翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
引发未实现错误(NotImplementedError)
使用 autograd.Function 与 vmap 一起使用时,你必须要么覆盖 "
vmap 静态方法或设置 generate_vmap_rule=True。
)
@classmethod
def 应用(
类, *
参数, **kwargs):
def 绑定默认参数(
函数, *
参数, **kwargs):
签名 =
检查.
签名(
函数)
绑定参数 =
签名.
绑定(*
参数, **kwargs)
绑定参数.
应用默认值()
返回
绑定参数.args
是否已定义设置上下文 =
_是否已定义设置上下文(
类.
设置上下文)
如果
是否已定义设置上下文:
args = 绑定默认参数(
类.
前向, *
参数, **kwargs)
如果
不
PyTorch._C.
都是 functorch 转换激活():
# 注意:[functorch vjp 和 autograd 交互]
args = _functorch.工具.
解包无效包装器(
参数)
返回
超级().
应用(*
参数, **kwargs)
# 类型:忽略[杂项]
如果
不
是否已定义设置上下文:
抛出
运行时错误(
为了使用 functorch 转换与 autograd.Function 一起
(vmap, grad, jvp, jacrev, ...), 必须重写 setup_context
staticmethod. 更多详情,请参阅
https://pytorch.org/docs/main/notes/扩展.func.html
)
返回
自定义函数调用(
类, *
参数, **kwargs)
@staticmethod
def _编译自动微分键(ctx):
返回 (ctx.
_自动微分函数 ID,)
def _是否已定义设置上下文(
函数):
返回 fn !=
单级函数.
设置上下文
[文档]def 一次可微分(fn):
@functools.wraps(fn)
def wrapper(ctx, *args):
with torch.no_grad():
outputs = fn(ctx, *args)
if not torch.is_grad_enabled():
返回输出
如果任何输入具有 requires_grad=True,我们强制输出
需要具有 requires_grad=True 但指向一个抛出异常的 grad_fn
# 双向传播过程中的错误信息。
# XXX:这只是一个对 requires_grad 的近似——没有办法
# 确定如果 fn 没有使用 ctx.saved_tensors,那么即使没有参数,某些 Tensor 也可能需要梯度。
# 不幸的是,这会导致意外的错误信息(“没有节点”)
# “Unfortunately, this leads to unexpected error messages ("no nodes")
# 需要计算梯度"),但我没有更好的主意。
这些函数在反向传播中无论如何都会引发错误。
requires_grad = any(
isinstance(arg, torch.Tensor) and arg.requires_grad for arg in args
翻译:arg 属于 torch.Tensor 类型且 arg 需要梯度,对于 args 中的每个 arg
)
如果不需要梯度:
返回输出
如果输出不是元组类型:
outputs = (outputs,)
err_fn = _functions.DelayedError(
尝试对标记了 @once_differentiable 的函数进行两次微分
with @once_differentiable
len(outputs),
)
# 创建每个需要 requires_grad=True 的输出的别名。我们需要
# 至少一个输入到 err_fn 需要梯度,以便
# output will have a grad_fn.
def fake_requires_grad(var):
if var is not None:
var = var.detach()
var.requires_grad = True
return var
return err_fn(*[fake_requires_grad(v) for v in outputs])
return wrapper
[文档]class InplaceFunction(Function):
r"""
这个类仅为了向后兼容而存在。
对于任何新的用例,请使用 :class:`Function` 而不是这个。
"""
"""
def __init__(self, inplace=False):
super().__init__()
self.inplace = inplace
def _nested_map(condition, 函数,
条件消息=
无):
def _map(对象):
如果 condition(
对象):
返回
函数(
对象)
如果...否则
对象
是
无:
返回
无
如果...否则 isinstance(
对象, (
列表,
元组)):
已映射 = (_map(x) for x
在
对象)
如果
有属性(
对象,
"_字段"):
# obj 是命名元组
返回
类型(
对象)(*
映射)
返回
类型(
对象)(
映射)
如果...否则 isinstance(
对象,
字典):
返回 {x: _map(
对象[x]) for x
在
对象}
否则:
抛出
值错误(
"自动嵌套不知道如何处理 "
"一个输入对象类型为"
+ PyTorch.
类型名(
对象)
+ (
"。支持的类型:" +
条件消息 +
",或它们的列表/元组"
如果
条件消息
否则
请提供需要翻译的文本
)
)
返回
地图
def _jit_unwrap_structured(对象):
如果
有属性(
对象, "_jit_unwrap"):
返回
对象._jit_unwrap()
返回
对象
def 迭代过滤(condition,
允许未知=False,
条件消息=
无,
转换=
无):
def _迭代(
对象):
如果
转换
是
不
无:
对象 =
转换(
对象)
如果 condition(
对象):
产生
对象
如果...否则
对象
是
无:
返回
如果...否则 isinstance(
对象, (
列表,
元组)):
for o 在
对象:
yield from _迭代(o)
如果...否则 isinstance(
对象,
字典):
仅接受原始键类型,因此无需检查它们
for o 在
对象.
值():
yield from _迭代(o)
如果...否则
允许未知:
产生
对象
否则:
抛出
值错误(
"自动嵌套不知道如何处理 "
"一个输入对象类型为"
+ PyTorch.
类型名(
对象)
+ (
"。支持的类型:" +
条件消息 +
",或它们的列表/元组"
如果
条件消息
否则
请提供需要翻译的文本
)
)
返回
_迭代
def _unflatten(输入, proto):
# 将列表或元组输入展开成嵌套列表/元组结构
# specified by proto
def unflatten_helper(输入, proto):
资源:
列表[
可选[
PyTorch.
张量]] =
输入文本为空,请提供需要翻译的文本
如果
有属性(proto,
_jit_wrap):
返回 proto._jit_wrap(
输入)
如果
不 isinstance(proto, (
列表,
元组)):
返回
输入[0
]
输入[1
]
for e 在 proto:
如果 e
是
无:
资源.
添加(e)
否则:
res_e, 输入 = unflatten_helper(
输入, e)
资源.
添加(res_e)
返回
类型(proto)(
资源),
输入
返回 unflatten_helper(
输入, proto
)]0]
迭代_jit_values =
迭代过滤(
Lambda 函数 o: o
是
无
或者 isinstance(o,
PyTorch._C.
值),
条件消息=
JIT 的值或 None,
)
_iter_tensors = 迭代过滤(
Lambda 函数 x: isinstance(x,
PyTorch.
张量),
条件消息=
张量,
转换=_jit_unwrap_structured,
)
_iter_tensors_permissive = 迭代过滤(
Lambda 函数 x: isinstance(x,
PyTorch.
张量),
允许未知=True,
条件消息=
张量(宽松),
)
_iter_None_tensors = 迭代过滤(
Lambda 函数 o: o
是
无
或者 isinstance(o,
PyTorch.
张量),
条件消息=
"张量或无"
)
_map_tensor_data = _nested_map(
Lambda 函数 x: isinstance(x,
PyTorch.
张量),
Lambda 函数 o: o.
数据,
条件消息=
张量
)
[文档]
类
嵌套 IO 函数(
函数):
r""
这个类仅为了向后兼容而存在。
请使用 :class:`Function` 而不是这个,以用于任何新的用例。
"""
因为这些函数在这里被声明为 '@staticmethod',所以需要 'type: ignore' 语句
超类(Function)是静态方法,但在这里是实例方法,mypy 报告为不兼容
def _执行前向(self, *
输入):
self._nested_input = 输入
平面输入 =
元组(
_迭代张量(
输入))
平面输出 =
超级().
_执行前向(*
平面输入)
# 类型:忽略[杂项]
嵌套张量 = _unflatten(
平面输出, self.
_嵌套输出)
返回
嵌套张量
def 执行反向操作(self,
渐变,
保留变量):
self.保留变量 =
保留变量
结果 =
超级().
执行反向操作(
渐变,
保留变量)
# 类型:忽略[杂项]
如果
不
保留变量:
删除 self.
_嵌套输出
删除 self.
保存嵌套
返回
结果
[文档] def backward(self, *gradients: Any) -> Any: # type: ignore[override]
r"""
共享反向工具。
"""
nested_gradients = _unflatten(gradients, self._nested_output)
result = self.backward_extended(*nested_gradients) # 忽略[func-returns-value]
return tuple(_iter_None_tensors(result))
__call__ = _do_forward
[文档] def forward(self, *args: Any) -> Any: # type: ignore[override]
r"""
共享前向实用程序。
""
nested_tensors = _map_tensor_data(self._nested_input)
result = self.forward_extended(*nested_tensors) # 忽略[func-returns-value]类型
删除 self._nested_input
self._nested_output = result
返回 tuple(_iter_tensors(result))
[文档] def save_for_backward(self, *args: Any) -> None:
r"""
查看 :meth:`Function.save_for_backward`。
"""
self.to_save = tuple(_iter_tensors(args))
self._to_save_nested = args
@property
def 已保存的张量(self):
r""
查看 :meth:`Function.saved_tensors`。
"""
平坦张量 =
超级().
保存的张量
# 类型:忽略[杂项]
返回 _unflatten(flat_tensors, self._to_save_nested)
[文档] def mark_dirty(self, *args: Any, **kwargs: Any) -> None:
r"""
查看 :meth:`Function.mark_dirty`。
"""
self.dirty_tensors = tuple(_iter_tensors((args, kwargs)))
[文档] def mark_non_differentiable(self, *args: Any, **kwargs: Any) -> None:
r"""
查看 :meth:`Function.mark_non_differentiable`.
"""
self.non_differentiable = tuple(_iter_tensors((args, kwargs)))
[文档] def forward_extended(self, *input: Any) -> None:
r"""
用户自定义的前向函数。
"``"
引发未实现异常
[文档] def backward_extended(self, *grad_output: Any) -> None:
r"""
用户自定义反向操作。
"""
引发未实现错误