快捷键

torch.optim.optimizer 的源代码

# mypy: 允许未类型化定义
"""基础优化器。"""
导入 functools
导入 警告
from 集合 导入 默认字典, OrderedDict
from collections.abc 导入 不可变, 迭代器, 序列
from 复制 导入 深拷贝
from itertools 导入 连接
from 打字 导入 任何, 可调用, 角色, 可选, 过载, 类型变量, 联合
from typing_extensions 导入 参数规范, 自身, 类型别名

导入 火炬
导入 torch.utils.hooks  钩子
from torch.utils._foreach_utils 导入 (
    支持的设备获取_foreach_kernels,
    支持的设备获取_fused_kernels,
    按设备类型和数据类型分组张量,
    索引,
    TensorListList,
)
from torch.utils.hooks 导入 可移除句柄


_T = 类型变量("_T")
_P = 参数规范("_P")

参数: 类型别名 = 元组[任何, ...]
关键字参数: 类型别名 = 字典[字符串, 任何]
状态字典: 类型别名 = 字典[字符串, 任何]
设备字典 = 字典[可选[火炬.设备] 火炬.张量]
设备数据类型字典 = 字典[可选[元组[火炬.设备, 火炬.数据类型]], 火炬.张量]


全局优化器预钩子: 类型别名 = 可调用[
    ["优化器", 参数, 关键字参数] 可选[元组[参数, 参数]]
]
全局优化器后钩: 类型别名 = 可调用[["优化器", 参数, 参数] ]

全部 = [
    "优化器",
    注册优化器步骤前钩子,
    注册优化器步骤后钩子,
]
_全局优化器前钩: 字典[int, GlobalOptimizerPreHook] = 有序字典()
全局优化器后钩子: 字典[int, GlobalOptimizerPostHook] = 有序字典()
每个支持类型 = [火炬.张量, 火炬.神经网络.参数.参数]


 _RequiredParameter:
    表示优化器所需参数的单例类。

    定义 __repr__() 输入文本:
->

翻译:
-> 字符串:
        返回 "<必需参数>"


必需 = _必需参数()


定义 _use_grad_for_differentiable(函数):
    定义 _使用梯度(, *参数, **kwargs):
        导入 torch._dynamo

        prev_grad = 火炬.梯度是否启用()
        尝试:
            # 注意以下图断:
            # 我们需要图断来确保 aot 尊重 no_grad 注解。
            # 这对性能很重要,因为没有这个,函数化将生成一个尾声
            # 这会更新优化器中不可见给感应器的参数,因此,
            # 感应器将为模型中的每个参数分配资源,这非常糟糕。
            # 因此,AOT 可以正确地识别这是一个推理图,并且功能化会生成
            # 一个附录,该附录附加到图中,并且对感应器可见,因此,感应器可以看到
            步骤已经就位,并且能够避免额外的分配。
            未来,我们可能会 1)继续在反向上进行图断开,这样这个图断开就不重要了。
            或者 2)拥有一个完全融合的前向和反向图,这将默认启用 no_grad,我们可以移除这个图断开,以便编译完全融合的前后向优化图。
            # 图断开来允许编译完全融合的前后向优化图。
            # see https://github.com/pytorch/pytorch/issues/104053
            火炬.设置梯度启用(.默认值[可微分的])
            火炬._dynamo.图断点()
            返回 = 函数(, *参数, **kwargs)
        最后:
            火炬._dynamo.图断点()
            火炬.设置梯度启用(前向梯度)
        返回 返回

    functools.更新包装器(使用梯度, 函数)
    返回 使用梯度


定义 _获取值(x):
    # 项目在 eager 模式中比 CPU 张量快得多
    如果  火炬.算子.是否正在脚本化()  火炬.编译器.is_compiling():
        返回 x
    else:
        返回 x.项目() 如果 isinstance(x, 火炬.张量) 否则 x


定义 _stack_if_compiling(x):
    如果  火炬.算子.是否正在脚本化()  火炬.编译器.is_compiling():
        返回 火炬.(x)
    else:
        返回 x


定义 _如果不受支持则禁用 Dynamo(
    单个张量函数: 可选[可调用[..., 对象]] = 
) 输入文本:
->

翻译:
-> 可调用[[可调用[_P, _T]], 可调用[_P, _T]]
    # torchscript BC 的解决方案
    所有被调用的函数都必须在全局环境中
    在创建 maybe_fallback 闭包的站点上
    可能的回退
    如果 单个张量函数:
        全局变量()[单个张量函数.__name__] = 单个张量函数

    定义 包装器(函数: 可调用[_P, _T]) 输入文本:
->

翻译:
-> 可调用[_P, _T]:
        导入 检查

        禁用功能 = 火炬._禁用_dynamo(函数)
        ps = 检查.签名(函数).参数
        有状态步骤 = 真实
        尝试:
            状态步骤 = 列表(ps.()).索引(状态步骤)
        除了 ValueError:
            有状态步骤 = 

        今天,存在一些情况,我们会堆叠状态步骤
        然后将它们作为 foreach 操作的值参数传递。
        在 CUDA 上作为值参数的状态步骤在 eager 中不受支持,
        但这种情况只发生在用户明确删除的罕见情况下。
        可捕获的标志。如果可捕获=True,则这不是问题。
        @functools.包装(函数)
        定义 可能的回退(*参数: _P.参数, **kwargs: _P.kwargs):
            如果 火炬.编译器.is_compiling()  (
                 kwargs.获取("可捕获的", 错误)
                 具有状态步骤
                 (参数 := 参数[状态步骤索引])
                 isinstance(arg, 序列)
                 arg[0].is_cuda
                或者 (
                    状态步骤  kwargs
                     (关键字参数 := kwargs[状态步骤])
                     isinstance(关键字参数, 序列)
                     关键字参数[0].is_cuda
                )
            ):
                返回 禁用功能(*参数, **kwargs)
            else:
                返回 函数(*参数, **kwargs)

        返回 可能回退

    返回 包装器


对于任何具有更快实现的优化器,我们尝试默认使用
尽可能快且最稳定的。对于 foreach,要求是拥有
所有原生参数都在 CUDA 上。对于融合,目前还有一个额外要求
矩阵的数据类型必须是浮点型。这两种选择都不支持 torch.jit.script 或可微,因此在这些情况下,我们回退到单个张量实现。
torch.jit.script 和可微,因此在这些情况下,我们回退到单个张量实现。
实现。
定义 默认为融合或遍历(
    参数: 列表[火炬.张量] 可微分的: 布尔, 使用融合的: 布尔值 = 
) 输入文本:
->

翻译:
-> 元组[布尔, 布尔]:
    如果 火炬.算子.是否正在脚本化() 或者 可微分的:
        返回 错误, 

    支持的设备 = 获取支持的融合内核设备()
    遍历支持的设备 = 获取支持的遍历内核设备()
    fused = 使用融合  所有(
        p  
        或者 (
            类型(p)  每个支持类型
             p.设备.类型  支持的设备
             火炬.is_floating_point(p)
        )
        for p  params
    )
    foreach =  fused  所有(
        p  
        或者 (
            类型(p)  每个支持类型
             p.设备.类型  遍历支持的设备
        )
        for p  params
    )
    返回 融合, foreach


定义 _检查融合的设备数据类型(
    p: 火炬.张量, cuda 不支持: 布尔值 = 
) 输入文本:
->

翻译:
-> :
    支持的设备 = 获取支持的融合内核设备()
    如果 cuda 不支持:
        支持的融合设备.删除(cuda)
    如果  (p.设备.类型  支持的融合设备  火炬.is_floating_point(p)):
        提升 运行时错误(
            `fused=True` 需要所有参数都是浮点型张量
            f支持的设备:{融合支持设备}但是{p.数据类型}{p.设备.类型}"
        )


定义 真实查看(参数, *状态和梯度):
    for i, p  列举(参数):
        如果 火炬.是复杂的(p):
            参数[i] = 火炬.真实查看(参数[i])
            for s  状态和梯度:
                s[i] = 火炬.真实查看(s[i])


定义 _获取标量数据类型(是否融合=):
    如果 是否融合:
        返回 火炬.float32
    返回 (
        火炬.float64 如果 火炬.获取默认数据类型() == 火炬.float64 否则 火炬.float32
    )


定义 _获取可捕获的设备(支持 XLA: 布尔值 = ) 输入文本:
->

翻译:
-> 列表[字符串]:
    r返回支持捕获优化器的设备类型列表。
    可捕获支持的设备 = [cuda, XPU, hpu]
    如果  火炬.算子.是否正在脚本化():
        支持捕获的设备.append(火炬._C._get_privateuse1_backend_name())
    如果 支持 XLA:
        支持捕获的设备.append("xla")
    返回 可捕获支持的设备


# 优化器之间的公共文档字符串
_params_doc = r"""params (iterable): 可优化参数的迭代器或命名参数
或定义参数组的字典的迭代器。当使用命名参数时,
所有组中的所有参数都应该是命名的"""

_foreach_doc = r"""foreach(bool,可选):是否使用优化器的 foreach 实现。如果用户未指定(即 foreach 为 None),我们将尝试使用 CUDA 上的 for-loop 实现 foreach,因为它通常性能更优。请注意,foreach 实现使用"""
""。如果用户未指定(即 foreach 为 None),我们将尝试使用 CUDA 上的 for-loop 实现 foreach,因为它通常性能更优。请注意,foreach 实现使用""
""CUDA 上的 for-loop 实现 foreach,因为它通常性能更优。请注意,foreach 实现使用""
""请注意,foreach 实现使用""
~ sizeof(params) 比 for 循环版本占用更多峰值内存,因为存在中间变量
作为一个 tensor 列表与只是一个 tensor 相比。如果内存受限,则批量减少
参数通过优化器一次传递或切换此标志为 False(默认:无)"""

_fused_doc = rfused(布尔值,可选):是否使用融合实现。
目前,支持 `torch.float64`、`torch.float32`、`torch.float16` 和 `torch.bfloat16`
支持。 (默认:无)

.. note:: foreach 和融合实现通常比 for 循环更快
单张量实现,融合的从理论上讲是最快的
垂直和水平融合。因此,如果用户没有指定任一标志(即 foreach = fused = None),我们将尝试在张量都在 CUDA 上时使用默认的 foreach 实现为什么不融合?因为融合实现相对较新,我们希望给它足够的时间来稳定。
标志(即 foreach = fused = None),我们将尝试默认到 foreach 实现当张量都在 CUDA 上时。为什么不融合?因为融合实现相对较新,我们希望给它足够的时间来稳定。
为什么不融合?因为融合实现相对较新,我们希望给它足够的时间来稳定。
因为融合实现相对较新,我们希望给它足够的时间来稳定。
要指定融合,请传递 True 以启用融合。要强制执行 for-loop 的实现,请传递 False 以使用 foreach 或融合。
""可捕获(bool,可选):此实例是否安全可捕获。""

_capturable_doc = r"""capturable(bool,可选):是否安全捕获此实例。"""
在 CUDA 图中捕获。传递 True 可能会损害未图化的性能,
因此,如果您不打算为这个实例进行图捕获,请将其设置为 False
(默认:False)"""

_可微文档 = r可微(bool,可选):是否在训练过程中通过优化器步骤进行。否则,step() 函数将在 torch.no_grad() 上下文中运行。将其设置为 True 可能会降低性能,因此如果您不打算运行 autograd,请将其保留为 False。
否则,step() 函数将在 torch.no_grad() 上下文中运行。
将其设置为 True 可能会降低性能,因此如果您不打算运行 autograd,请将其保留为 False。
请将其保留为 False,如果您不打算运行 autograd。
通过此实例(默认:False)"""

_最大化文档 = r"""最大化(bool,可选):相对于 params 最大化目标,而不是最小化(默认:False)"""
params,而不是最小化(默认:False)"""


定义 注册优化器步骤预钩子(hook: 全局优化器预钩子) 输入文本:
->

翻译:
-> 可移除句柄:
    r注册一个对所有优化器通用的预钩子。

该钩子应具有以下签名:

hook(optimizer, args, kwargs) -> None 或修改后的 args 和 kwargs

参数:
钩子(Callable):一个用户定义的钩子,它在所有优化器上注册。

返回:
`:class:`torch.utils.hooks.可移除句柄`:
一个可以通过调用来移除已添加钩子的句柄
处理.remove()
"文档"
    handle = 钩子.可移除句柄(全局优化器预钩子)
    全局优化器预钩子[处理.id] = 钩子
    返回 handle


定义 注册优化器步骤后钩子(hook: GlobalOptimizerPostHook) 输入文本:
->

翻译:
-> 可移除句柄:
    r"""注册一个对所有优化器都通用的后钩子。

该钩子应具有以下签名:

        hook(optimizer, args, kwargs) -> None

参数:
hook (Callable): 用户自定义的钩子,注册在所有优化器上。

返回:
class:`torch.utils.hooks.RemovableHandle`:
一个可以用来通过调用移除已添加钩子的句柄。
`handle.remove()`
"文档"
    handle = 钩子.可移除句柄(_全局优化器后钩子)
    _全局优化器后钩子[处理.id] = 钩子
    返回 handle


参数 T: 类型别名 = 并集[
    迭代器[火炬.张量] 迭代器[字典[字符串, 任何]], 迭代器[元组[字符串, 火炬.张量]]
]

R = 类型变量("R")
T = 类型变量(T)


[文档] 优化器: r所有优化器的基类。 .. 警告:: 参数需要指定为具有确定性的集合 运行间一致的排序。不排序的对象示例。 满足这些属性是集合,并且是字典值的迭代器。 参数: params (可迭代对象): 一个 :class:`torch.Tensor` 的可迭代对象 `dict` 类。指定应优化的张量。 默认值:(dict)。包含优化默认值的字典。 选项(当参数组未指定时使用)。 "文档" OptimizerPreHook: 类型别名 = 可调用[[自身, 参数, 关键字参数] 可选[元组[参数, 关键字参数]]] # 类型:忽略[杂项] 优化器后钩: 类型别名 = 可调用[[自身, 参数, 关键字参数] ] # 类型:忽略[杂项] _优化器步骤前钩: 字典[int, 优化器预钩子] _优化器步骤后钩子: 字典[int, 优化器后钩子] _优化器状态字典预钩子: 'OrderedDict[int, Callable[["Optimizer"], None]]' _optimizer_state_dict_post_hooks: 'OrderedDict[int, Callable[["Optimizer", StateDict], Optional[StateDict]]]' _optimizer_load_state_dict_pre_hooks: 'OrderedDict[int, Callable[["Optimizer", StateDict], Optional[StateDict]]]' _optimizer_load_state_dict_post_hooks: 'OrderedDict[int, Callable[["Optimizer"], None]]' 定义 __init__(, 参数: 参数 T, 默认值: 字典[字符串, 任何]) 输入文本: -> 翻译: -> : # 无需注意:D107 火炬._C._log_api_usage_once("python.optimizer") .默认 = 默认 ._optimizer_step_pre_hooks = 有序字典() ._optimizer_step_post_hooks = 有序字典() ._optimizer_state_dict_pre_hooks = 有序字典() ._optimizer_state_dict_post_hooks = 有序字典() ._optimizer_load_state_dict_pre_hooks = 有序字典() ._optimizer_load_state_dict_post_hooks = 有序字典() ._patch_step_function() 如果 isinstance(参数, 火炬.张量): 提升 类型错误( 传递给优化器的 "params" 参数应该是 "一个可迭代的张量或字典,但得到了" + 火炬.类型名(参数) ) .状态: 默认字典[火炬.张量, 任何] = 默认字典(字典) .参数组: 列表[字典[字符串, 任何]] = 输入文本为空,请提供需要翻译的文本 参数组 = 列表(参数) 如果 长度(参数组) == 0: 提升 ValueError("优化器得到了一个空的参数列表") 如果 isinstance(参数组[0] 字典): 参数组 = [ - 检查输入 ]参数: 参数组}] for 参数组 参数组: 自身.添加参数组(角色(字典, 参数组)) 允许 _cuda_graph_capture_health_check 在 Python 中模拟一个简陋的 TORCH_WARN_ONCE 我认为这个并不存在 https://github.com/pytorch/pytorch/issues/72948 ._warned_capturable_if_run_uncaptured = 真实 定义 __getstate__() 输入文本: -> 翻译: -> 字典[字符串, 任何]: # 无需注意:D105 返回 { 默认值: .默认值, 状态: .状态, 参数组: 自身.参数组, } 定义 __setstate__(, 状态: 字典[字符串, 任何]) 输入文本: -> 翻译: -> : # 无需注意:D105 .字典.更新(状态) 如果 "_optimizer_step_pre_hooks" .字典: ._optimizer_step_pre_hooks = 有序字典() 如果 "_optimizer_step_post_hooks" .字典: ._optimizer_step_post_hooks = 有序字典() 如果 "_optimizer_state_dict_pre_hooks" .字典: ._optimizer_state_dict_pre_hooks = 有序字典() 如果 "_optimizer_state_dict_post_hooks" .字典: ._optimizer_state_dict_post_hooks = 有序字典() 如果 "_optimizer_load_state_dict_pre_hooks" .字典: ._optimizer_load_state_dict_pre_hooks = 有序字典() 如果 "_optimizer_load_state_dict_post_hooks" .字典: ._optimizer_load_state_dict_post_hooks = 有序字典() ._补丁步骤函数() # 支持多进程 pickle/unpickle .默认值.setdefault(可微分的, 错误) 定义 __repr__() 输入文本: -> 翻译: -> 字符串: # 无需注意:D105 格式化字符串 = ..__name__ + " (" for i, 列举(.参数组): 格式化字符串 += "输入文本翻译为简体中文为:\n" 格式化字符串 += f参数组{i}输入文本翻译为简体中文为:\n" for key 排序(群组.()): 如果 key != 参数: 格式化字符串 += f" {}: {群组[]}输入文本翻译为简体中文为:\n" 格式化字符串 += )" 返回 格式化字符串 目前由 Adam 和 AdamW 需要 定义 _cuda_graph_capture_health_check() 输入文本: -> 翻译: -> : 注意 [torch.compile x 可捕获] 如果我们在编译,我们会自动尝试采取可捕获路径 在追踪期间将标志设置为 True。因此,我们跳过所有检查 通常需要确定我们是否可以使用 CUDA 图, 将责任转移到 torch.inductor。这可以在追踪期间节省时间 因为在没有牺牲用户体验的情况下,inductor 会发出警告, # 如果无法启用 CUDA 图,例如, # https://github.com/pytorch/pytorch/blob/d3ba8901d8640eb16f88b2bfef9df7fa383d4b47/torch/_inductor/compile_fx.py#L390. # 因此,在编译时,inductor 将根据是否存在输入突变或 CPU 张量来决定是否启用 cudagraphs。 # 可以启用基于是否存在输入突变或 CPU 张量。 如果 ( 火炬.编译器.is_compiling() 火炬.后端.cuda.是否构建() 火炬.cuda.是否可用() ): 捕捉 = 火炬.cuda.当前流是否正在捕获() 如果 捕获 所有( 群组["可捕获的"] for .参数组 ): 提升 运行时错误( 尝试捕获实例中的 step() 的 CUDA 图形捕获,但 param_groups' capturable 为 False。 + ..__name__ + "_warned_capturable_if_run_uncaptured" ) 如果 ( ( getattr(, _如果未捕获运行则警告可捕获性, 错误)) 所有(群组["可捕获的"] for .参数组) ( 捕获) ): 警告.警告( "此实例使用 capturable=True 构造,或者所有参数组中的一些带有 capturable=True," "但是 step() 正在运行而没有 CUDA 图形捕获。如果你从不打算捕获此实例," "则 capturable=True 可能会降低性能,你应该设置为 capturable=False。" ) .警告:如果未捕获运行,则可捕获 = 真实 定义 优化器步进代码() 输入文本: -> 翻译: -> : 入口点为 `torch.profile.profiler`。 当启用 Python 跟踪时,分析器将挂钩到这 在 CPython 级别上检查优化器的参数 参数 groups。在`step()`之后调用它,因为许多优化器 懒加载状态。 这是因为优化器缺少适当的步骤钩子,所以这是一个权宜之计, 如果存在,将会被移除。 "文档" @staticmethod 定义 profile_hook_step(函数: 可调用[_P, R]) 输入文本: -> 翻译: -> 可调用[_P, R]: # 无需注意:D102 @functools.包装(函数) 定义 包装器(*参数: _P.参数, **kwargs: _P.kwargs) 输入文本: -> 翻译: -> R: , *_ = args self = 角色(优化器, ) 用户名 = f优化器.step#{..__name__}.step 火炬.自动微分.分析器.记录功能(用户名): # 调用优化器步骤预钩子 for 预钩子 chain( 全局优化器预钩子.(), .优化器步骤预钩子.(), ): 结果 = 预钩子(, 参数, kwargs) 如果 结果 : 如果 isinstance(结果, 元组) 长度(结果) == 2: 参数, kwargs = 结果 # 类型:忽略[赋值] else: 提升 运行时错误( f"{函数}必须返回 None 或一个包含(new_args, new_kwargs)的元组,但得到了{结果} ) out = 函数(*参数, **kwargs) ._optimizer_step_code() # 调用优化器步骤后钩子 for 后钩 chain( ._optimizer_step_post_hooks.(), 全局优化器后钩子.(), ): 后钩(, 参数, kwargs) 返回 out 返回 包装器 @staticmethod 定义 按设备类型和数据类型分组张量( 张量列表列表: TensorListList, 带索引: 布尔值 = 错误, ) 输入文本: -> 翻译: -> 并集[ 字典[元组[, ] 元组[TensorListList, 索引]], 字典[元组[火炬.设备, 火炬.数据类型] 元组[TensorListList, 索引]], ]: 将张量列表按设备和数据类型分组。 如果正在编译,则跳过此步骤,因为这将发生在电感降低期间。 "文档" 如果 火炬.编译器.is_compiling(): 返回 {(, ): (tensorlistlist, 列表(范围(长度(tensorlistlist[0]))))} else: 返回 按设备类型和数据类型分组张量(tensorlistlist, 带索引) # 类型:忽略[返回值,参数类型] 定义 _修补步骤函数() 输入文本: -> 翻译: -> : ._zero_grad_profile_name = ( f"优化器.zero_grad#"{..__name__}.zero_grad ) 已钩 = getattr(..步长, 着迷, ) 如果 着迷: ..步骤 = .用户配置钩子步骤(..步长) # 类型:忽略[赋值] ..步长.已挂载 = 真实 # 类型: 忽略[attr-defined]
[文档] def 注册步骤前钩子(self, hook: OptimizerPreHook) -> RemovableHandle: r"""注册一个在优化器步骤之前调用的优化器步骤前钩子。""" 应具有以下签名:: hook(optimizer, args, kwargs) -> None 或修改后的 args 和 kwargs ``optimizer`` 参数是正在使用的优化器实例。如果 args 和 kwargs 被预钩子修改,则 返回的值是一个包含新_args 和新_kwargs 的元组。 Args: 钩子(Callable):用户定义的待注册钩子。 Returns: `torch.utils.hooks.RemovableHandle`: 可以用来通过调用 `handle.remove()` 移除已添加的钩子的句柄 `handle.remove()` `""" handle = hooks.RemovableHandle(self._optimizer_step_pre_hooks) self._optimizer_step_pre_hooks[handle.id] = hook return handle
[文档] def register_step_post_hook(self, hook: OptimizerPostHook) -> RemovableHandle: 注册一个优化器步骤后钩子,该钩子将在优化器步骤之后被调用。 它应该具有以下签名:: hook(optimizer, args, kwargs) -> None ``optimizer`` 参数是正在使用的优化器实例。 Args: 钩子(Callable):用户定义的注册钩子。 Returns: class:`torch.utils.hooks.RemovableHandle`: 可以用来通过调用移除已添加的钩子的句柄 ``handle.remove()`` """ handle = hooks.RemovableHandle(self._optimizer_step_post_hooks) self._optimizer_step_post_hooks[handle.id] = hook return handle
[文档] def register_state_dict_pre_hook( self, hook: Callable[["Optimizer"], None], prepend: bool = False ) -> RemovableHandle: # noqa: D101 r"""注册一个在调用 :meth:`~torch.optim.Optimizer.state_dict` 之前将被调用的状态字典预钩子。 应具有以下签名:: hook(optimizer) -> None ``optimizer`` 参数是正在使用的优化器实例。 在对 ``self`` 调用 ``state_dict`` 之前,将使用 ``self`` 作为参数调用钩子。 注册的钩子可以在调用 ``state_dict`` 之前执行预处理。 调用之前。 Args: 钩子(Callable):要注册的用户定义钩子。 prepend(布尔值):如果为 True,提供的预 ``钩子`` 将在之前触发 所有已注册的 `state_dict` 预钩子。否则, 提供的 `hook` 将在所有已注册的触发后执行 预钩子。(默认:False) 返回: `:class:`torch.utils.hooks.RemoveableHandle`:可移除处理句柄 一个可以通过调用来移除已添加钩子的句柄 处理.remove() """ handle = hooks.RemovableHandle(self._optimizer_state_dict_pre_hooks) self._optimizer_state_dict_pre_hooks[handle.id] = hook if prepend: self._optimizer_state_dict_pre_hooks.move_to_end(handle.id, last=False) return handle
[文档] def register_state_dict_post_hook( self, hook: 可调用[["Optimizer", StateDict"], Optional[StateDict]] prepend: bool = False, ) -> RemovableHandle: r"""注册一个在调用 :meth:`~torch.optim.Optimizer.state_dict` 之后将被调用的状态字典后钩子。 它应该具有以下签名:: hook(optimizer, state_dict) -> state_dict 或 None 在生成 `state_dict` 之后,将使用 `self` 和 `state_dict` 作为参数调用钩子。 钩子可能会就地修改 `state_dict` 或可选地 返回一个新的。已注册的钩子可用于执行后处理 在返回之前对 `state_dict` 进行处理。 参数: 钩子(Callable):用户定义的注册钩子。 prepend(布尔值):如果为 True,提供的后置“钩子”将在执行之前被触发 所有已注册的 `state_dict` 后钩子。否则, 提供的 `hook` 将在所有已注册的触发后执行 post-hooks.(默认:False) 返回: `:class:`torch.utils.hooks.RemoveableHandle`:可移除处理句柄 一个可以通过调用来移除已添加钩子的句柄 处理.remove() """ handle = hooks.RemovableHandle(self._optimizer_state_dict_post_hooks) self._optimizer_state_dict_post_hooks[handle.id] = hook if prepend: self._optimizer_state_dict_post_hooks.move_to_end(handle.id, last=False) 返回 handle
[文档] @torch.禁用 dynamo 定义 状态字典() 输入文本: -> 翻译: -> StateDict: r"""返回优化器状态作为 :class:`dict`。 它包含两个条目: * ``状态``: 一个字典,包含当前的优化状态。其内容 在不同的优化器类之间有所不同,但有一些共同的特征 。例如,状态是按参数保存的,并且参数 它本身不会被保存。`state` 是一个将参数 ID 映射的字典 将每个参数对应的状态转换为一个字典。 * ``param_groups``: 包含所有参数组的列表 参数组是一个字典。每个参数组包含元数据 专门针对优化器的,例如学习率和权重衰减, 以及组内参数的参数 ID 列表。 如果一个参数组是用 `named_parameters()` 初始化的, 其内容也将保存在状态字典中。 注意:参数 ID 看起来像索引,但它们只是 ID 将状态与 param_group 关联。当从 state_dict 加载时, 优化器将压缩 param_group ``params``(整数 ID)和 优化器 `param_groups`(实际的 `nn.Parameter`)顺序 匹配状态无需额外验证。 返回的状态字典可能看起来像: .. 代码块:: text { 'state': { 0: {'momentum_buffer': 张量(...), ...}, 1: {'momentum_buffer': 张量(...), ...}, 2: {'momentum_buffer': 张量(...), ...}, 3: {'momentum_buffer': 张量(...), ...} }, 'param_groups': [ { 'lr': 0.01 'weight_decay': 0 ... 'params': [0] 'param_names' ['param0'] (optional) }, { 'lr': 0.001 'weight_decay': 0.5 ... 'params': [1, 2, 3] 'param_names': ['param1', 'layer.weight', 'layer.bias'] (可选) } ] } "文档" for 预处理钩子 ._优化器状态字典预处理钩子.(): 预处理钩子() # 保存顺序索引而不是张量 参数映射: 字典[int, int] = {} 起始索引 = 0 定义 打包组(群组: 字典[字符串, 任何]) 输入文本: -> 翻译: -> 字典[字符串, 任何]: 非局部 起始索引 打包 = {k: v for k, v 群组.项目() 如果 k != 参数} 参数映射.更新( { id(p): i for i, p 列举(群组[参数] 开始索引) 如果 id(p) 参数映射 } ) 拼装[参数] = [参数映射[id(p)] for p 群组[参数]] 起始索引 += 长度(拼装[参数]) 返回 打包 参数组 = [打包组(g) for g .参数组] # 将状态重映射为使用顺序索引作为键 打包后的状态 = { (参数映射[id(k)] 如果 isinstance(k, 火炬.张量) 否则 k): v for k, v .状态.项目() } 状态字典 = { 状态: 打包状态, 参数组: 参数组, } for 后置钩子 .优化器状态字典后钩.(): 钩子结果 = 后钩(, 状态字典) 如果 钩子结果 : 状态字典 = 钩子结果 返回 状态字典
@staticmethod 定义 根据参数策略处理值( 参数: 火炬.张量, : 火炬.张量, 参数 ID: int, 参数组: 列表[字典[任何, 任何]], : 可哈希的 = , ) 输入文本: -> 翻译: -> 火炬.张量: 浮点类型在这里有点特殊。它们是唯一被假定为始终与 params 类型匹配的类型。 # 这些类型被假定为始终与 params 类型匹配。 # 确保不要将 state['step']强制转换为类型 https://github.com/pytorch/pytorch/issues/74424 # 除非融合或可捕获,否则不要转换,参见[特殊设备托管步骤]的说明 fused = 可捕获的 = 断言 参数组 for pg 参数组: 如果 param_id pg[参数]: fused = pg[融合] 如果 混合 pg 否则 可捕获的 = pg["可捕获的"] 如果 可捕获的 pg 否则 断开 如果 key == 步骤: 如果 可捕获的 或者 融合: 返回 .(数据类型=torch.float32, 设备=参数.设备) else: 返回 else: 如果 参数.is_floating_point(): 返回 .(数据类型=参数.数据类型, 设备=参数.设备) else: 返回 .(设备=参数.设备)
[文档] def register_load_state_dict_pre_hook( self, hook: Callable[["Optimizer", StateDict], Optional[StateDict]], prepend: bool = False, ) -> 可移除句柄: # noqa: D205 D400 注册一个在调用之前将被调用的 load_state_dict 预钩子 torch.optim.Optimizer.load_state_dict() 被调用。它应该有 以下签名:: hook(optimizer, state_dict) -> state_dict 或 None ``optimizer`` 参数是正在使用的优化器实例,而 ``state_dict`` 参数是用户传递给 ``load_state_dict`` 的 ``state_dict`` 的浅拷贝。钩子可以就地修改 state_dict 。钩子可以就地修改 state_dict 或者返回一个新的。如果返回了一个 state_dict,它将被使用 要加载到优化器中。 钩子将在传递参数 `self` 和 `state_dict` 之前被调用 在 `self` 上调用 `load_state_dict`。注册的钩子可以被用来 在调用 ``load_state_dict`` 方法之前进行预处理。 Args: hook (Callable): 用户定义的钩子,用于注册。 prepend (bool): 如果为 True,提供的预 ``hook`` 将在 所有已经注册的 ``load_state_dict`` 预钩子。否则, 提供的 ``hook`` 将在所有已经注册的 预钩子之后触发。(默认:False) 返回值: `torch.utils.hooks.RemoveableHandle`: 可以用来通过调用 `handle.remove()` 移除已添加的钩子的句柄 `handle.remove()` """ handle = hooks.RemovableHandle(self._optimizer_load_state_dict_pre_hooks) self._optimizer_load_state_dict_pre_hooks[handle.id] = hook if prepend: self._optimizer_load_state_dict_pre_hooks.move_to_end(handle.id, last=False) 返回处理
[文档] 注册加载状态字典后钩子( self, 钩子: Callable[["优化器"], None], prepend: bool = False ) -> 可移除句柄: # noqa: D205 D400 注册一个在调用后钩子,它将在加载状态字典之后被调用 torch.optim.Optimizer.load_state_dict() 被调用。它应该有 以下签名:: hook(优化器) -> 无 优化器参数是正在使用的优化器实例。 在调用 `self` 的 `load_state_dict` 方法之后,钩子将使用 `self` 作为参数被调用。 在 `self` 上调用 `load_state_dict` 后,注册的钩子可以用来 在 `load_state_dict` 加载完状态字典后执行后处理。 `state_dict`. Args: hook (Callable): 用户定义的钩子,用于注册。 prepend (bool): 如果为 True,提供的后置 `hook` 将在 所有已注册的 `load_state_dict` 的 post-hooks。否则, 提供的 `hook` 将在所有已注册的触发后执行 post-hooks.(默认:False) 返回: `torch.utils.hooks.RemoveableHandle`: 可以用来通过调用 `handle.remove()` 移除已添加的钩子的句柄 `handle.remove()` """ handle = hooks.RemovableHandle(self._optimizer_load_state_dict_post_hooks) self._optimizer_load_state_dict_post_hooks[handle.id] = hook if prepend: self._optimizer_load_state_dict_post_hooks.move_to_end(handle.id, last=False) # type: ignore[attr-defined] 返回处理
[文档] @torch.禁用 dynamo 定义 加载状态字典(, 状态字典: 状态字典) 输入文本: -> 翻译: -> : r"""加载优化器状态。 参数: state_dict (dict): 优化器状态。应为返回的对象。 从对 :meth:`state_dict` 的调用。 .. 注意:: 参数名称(如果它们存在于每个参数组的"param_names"键下) 在 `state_dict` 方法中定义的参数不会影响加载过程。 使用参数名称进行自定义情况(例如,当加载的状态字典中的参数) 与优化器中初始化的不同, 应该实现一个自定义的 `register_load_state_dict_pre_hook` 来适应加载的字典。 相应地。 如果 `param_names` 存在于加载的状态字典 `param_groups` 中,它们将被保存并覆盖。 当前优化器状态中存在的名称(如果有的话)。如果它们不在加载的状态字典中, 优化器的 `param_names` 将保持不变。 "文档" # 浅拷贝,以与模块 API 保持一致 状态字典 = 状态字典.复制() for 预钩子 ._optimizer_load_state_dict_pre_hooks.(): hook_result = pre_hook(, 状态字典) 如果 hook_result : 状态字典 = 钩子结果 # 验证状态字典 组们 = .参数组 # 深拷贝,因为我们稍后写入 saved_groups 以更新状态 saved_groups = 深拷贝(状态字典["参数组"]) 如果 长度(群组) != 长度(已保存组): 提升 ValueError( "加载的状态字典参数组数量不同" ) 参数镜头 = (长度(g[参数]) for g 群组) 保存镜头 = (长度(g[参数]) for g 已保存的组) 如果 任何(p 长度 != s 长度 for p 长度, s 长度 zip(参数镜头, 保存的镜头)): 提升 ValueError( "加载的状态字典包含一个参数组" "该参数组的大小与优化器组不匹配" ) 更新状态 id 映射 = 字典( zip( chain.from_iterable(g[参数] for g 已保存的组), chain.from_iterable(g[参数] for g 群组), ) ) 定义 _类型转换(参数, , 参数 ID=, 参数组=, =): r“对值进行深度复制,将所有张量转换为 param 的设备。” 如果 isinstance(, torch.张量): 返回 优化器.根据 param 策略处理值( 参数, , param_id, 参数组, key ) elif isinstance(, 字典): 返回 { k: _类型转换( 参数, v, 参数 ID=参数 ID, 参数组=参数组, =k ) for k, v .项目() } elif isinstance(, 迭代器): 返回 类型()(_类型转换(参数, v, 参数 ID=参数 ID, 参数组=参数组) for v ) 忽略调用参数 else: 返回 # 将状态复制到 params 中(并将张量转换为适当的类型)。 # 未分配给 params 的状态按原样复制(用于 # 向后兼容)。 状态: 默认字典[torch.张量, 字典[任何, 任何]] = 默认字典(字典) for k, v 状态字典[状态].项目(): 如果 k ID 映射: 参数 = ID 映射[k] 状态[参数] = _投射( 参数, v, param_id=k, 参数组=状态字典["param_groups"] ) else: 状态[k] = v 更新参数组,设置它们的 'params' 值 定义 更新组( 群组: 字典[字符串, 任何] 创建新组: 字典[字符串, 任何] ) 输入文本: -> 翻译: -> 字典[字符串, 任何]: 创建新组[参数] = 群组[参数] 如果 "参数名称" "参数名称" 创建新组: 创建新组["参数名称"] = 群组["参数名称"] 返回 新分组 参数组 = [更新分组(g, ng) for g, ng zip(群组, 保存的组)] .__setstate__({状态: 状态, "参数组": 参数组}) for 后钩 ._优化器加载状态字典后钩.(): 后钩()
[文档] @torch.禁用 dynamo 定义 零梯度(, 设置为 None: 布尔值 = ) 输入文本: -> 翻译: -> : r重置所有优化过的 :class:`torch.Tensor` 的梯度。 参数: set_to_none (bool): 不设置为 0,而是将梯度设置为 None。 通常情况下,这将具有更低的内存占用,并且可以适度提高性能。 然而,它改变了某些行为。例如: 1. 当用户尝试访问梯度并对其进行手动操作时, None 属性或充满 0 的 Tensor 将会有不同的行为。 如果用户请求 ``zero_grad(set_to_none=True)`` 后进行反向传播,则 ``.grad`` 将保证对于未接收梯度的参数为 None。 对于未接收梯度的参数,它们的 ``.grad`` 保证为 None。 3. ``torch.optim`` 优化器在梯度为 0 或 None 时表现不同 (在一种情况下它使用梯度为 0 进行步进,而在另一种情况下它跳过 完全删除步骤。 "文档" foreach = .默认值.获取(foreach, 错误) 或者 .默认值.获取( 融合, ) 如果 有属性(, _zero_grad_profile_name): ._修补步骤函数() 按设备类型和数据类型梯度: 可选[ 默认字典[torch.设备, 默认字典[torch.数据类型, 列表[torch.张量]]] ] 如果 foreach: 设备类型和 dtype 梯度 = 默认字典(lambda: 默认字典(列表)) else: 每设备每数据类型梯度 = torch.自动微分.分析器.记录功能(._零梯度配置文件名): for .参数组: for p 群组[参数]: 如果 p.梯度 : 如果 设置为 None: p.梯度 = else: 如果 p.研究生.grad_fn : p.研究生.断开连接() else: p.研究生.需要梯度_(错误) 如果 foreach 或者 p.研究生.is_sparse: p.研究生.零_() else: 断言 每设备每数据类型梯度 每设备每数据类型梯度[p.研究生.设备] p.研究生.dtype ].append(p.研究生) 如果 foreach: 断言 每设备每数据类型梯度 for 每数据类型梯度 每设备每数据类型梯度.(): for 梯度 per_dtype_grads.(): torch._foreach_zero_(梯度)
@overload 定义 步长(, 闭包: = ...) 输入文本: -> 翻译: -> : ... @overload 定义 步长(, 闭包: 可调用[] float]) 输入文本: -> 翻译: -> float: ...
[文档] def step(self, closure: Optional[Callable[[], float]] = None) -> Optional[float]: r"""执行单个优化步骤以更新参数。 Args: 闭包(Callable):一个重新评估模型并返回损失的闭包。对于大多数优化器是可选的。 闭包(Callable):一个重新评估模型并返回损失的闭包。对于大多数优化器是可选的。 """ 抛出未实现异常
[文档] @torch.禁用 dynamo 定义 添加参数组(, 参数组: 字典[字符串, 任何]) 输入文本: -> 翻译: -> : r将参数组添加到 :class:`Optimizer` 的 `param_groups` 中。 这在微调预训练网络时可能很有用,因为冻结的层可以被设置为可训练的,并在训练过程中添加到 :class:`Optimizer` 中。 这可以在微调预训练网络时很有用,因为冻结的层可以被设置为可训练的,并在训练过程中添加到 :class:`Optimizer` 中。 参数: param_group(字典):指定哪些张量应与组一起优化 指定特定的优化选项。 "文档" 如果 isinstance(参数组, 字典): 提升 类型错误(f"param_group 必须是字典类型,但得到了"{类型(参数组)}") params = 参数组[参数] 如果 isinstance(参数, torch.张量): 参数组[参数] = [参数] elif isinstance(参数, 设置): 提升 类型错误( "优化器参数需要按顺序组织到集合中,但" "张量在集合中的顺序将在运行之间发生变化。请使用列表代替。" ) else: 参数组[参数] = 列表(参数) 提取的参数张量 = 输入文本为空,请提供需要翻译的文本 提取的参数名称 = 输入文本为空,请提供需要翻译的文本 for 参数 参数组[参数]: 如果 isinstance(参数, 元组): 参数名称 = 参数[0] 提取的参数名称.append(` 的类型为 List[torch.Tensor]) 提取的参数张量.append(参数[1]) else: 提取的参数张量.append(参数) 参数组[参数] = 提取的参数张量 如果 长度(提取的参数名称) != 0: 如果 长度(提取的参数名称) == 长度(提取的参数张量): 参数组["参数名称"] = 提取的参数名称 else: 提升 ValueError( "所有优化器参数应带有/不带名称。一些参数名称缺失" ) for 参数 参数组[参数]: 如果 isinstance(参数, torch.张量): 提升 类型错误( "优化器只能优化张量," "但其中一个参数是," + torch.类型名(参数) ) 如果 .默认值.获取(可微分的, ) ( 参数.叶子节点 或者 参数.保留梯度 ): 提升 ValueError(无法优化非叶子张量) for 名称, 默认 .默认值.项目(): 如果 默认 必需的 名称 参数组: 提升 ValueError( f"参数组未指定必需优化参数的值"{名称}" ) else: 参数组.setdefault(名称, 默认) params = 参数组[参数] 如果 长度(参数) != 长度(设置(参数)): 警告.警告( "优化器包含具有重复参数的参数组;" "将来这将会导致错误;" "更多信息请参阅 github.com/pytorch/pytorch/issues/40967", 栈级别=3, ) 参数集: 设置[torch.张量] = 设置() for .参数组: 参数设置.更新(设置(群组[参数])) 如果 ("参数名称" 参数组) != ("参数名称" 群组): 当前组文本 = ( "带有名称" 如果 "参数名称" 参数组 否则 "不带名称" ) 提升 ValueError( "所有优化器参数组都应该带有/不带名称。" f无法添加参数组{current_group_txt}到优化器中 ) 如果 param_set.isdisjoint(设置(参数组[参数])): 提升 ValueError("某些参数出现在多个参数组中") .参数组.append(参数组)

© 版权所有 PyTorch 贡献者。

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

文档

查看 PyTorch 的全面开发者文档

查看文档

教程

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

查看教程

资源

查找开发资源,获取您的疑问解答

查看资源