评价此页

Adafactor#

class torch.optim.Adafactor(params, lr=0.01, beta2_decay=-0.8, eps=(None, 0.001), d=1.0, weight_decay=0.0, *, foreach=None, maximize=False)#

Implements Adafactor algorithm.

input:γ(lr),τ(β2 decay),θ0(params),f(θ)(objective),ϵ1,ϵ2 (epsilons),d(clipping threshold),λ(weight decay),maximizeinitialize:R00 (second moment row factor),C00 (second moment col factor),V^00 (second moment for vectors)fort=1todoifmaximize:Gtθft(θt1)elseGtθft(θt1)β^2t1tτρtmin(lr,1t)αtmax(ϵ2,RMS(θt1))ρtθtθt1γλθt1ifdim(Gt)>1:Rtβ^2tRt1+(1β^2t)(GtGt)1mCtβ^2tCt1+(1β^2t)1n(GtGt)V^tRtCtmax(1nRt,ϵ1)elseV^tβ^2tV^t1+(1β^2t)(GtGt)UtGtmax(V^t,ϵ1)U^tUtmax(1,RMS(Ut)d)θtθt1αtU^treturnθt\begin{aligned} &\rule{110mm}{0.4pt} \\ &\textbf{input} : \gamma \text{(lr)}, \: \tau \text{(}\beta_2\text{ decay)}, \: \theta_0 \text{(params)}, \: f(\theta) \text{(objective)}, \\ &\hspace{15mm} \: \epsilon_1, \epsilon_2 \text{ (epsilons)}, \: d \text{(clipping threshold)}, \\ &\hspace{15mm} \: \lambda \text{(weight decay)}, \: \textit{maximize} \\ &\textbf{initialize} : \: R_0 \leftarrow 0 \text{ (second moment row factor)}, \\ &\hspace{23mm} \: C_0 \leftarrow 0 \text{ (second moment col factor)}, \\ &\hspace{23mm} \: \widehat{V}_0 \leftarrow 0 \text{ (second moment for vectors)} \\[-1.ex] &\rule{110mm}{0.4pt} \\ &\textbf{for} \: t=1 \: \textbf{to} \: \ldots \: \textbf{do} \\ &\hspace{5mm}\textbf{if} \: \textit{maximize}: \\ &\hspace{10mm}G_t \leftarrow -\nabla_{\theta} f_t (\theta_{t-1}) \\ &\hspace{5mm}\textbf{else} \\ &\hspace{10mm}G_t \leftarrow \nabla_{\theta} f_t (\theta_{t-1}) \\ &\hspace{5mm}\widehat{\beta}_{2_t} \leftarrow 1 - t^{\tau} \\ &\hspace{5mm}\rho_t \leftarrow min(lr, \frac{1}{\sqrt{t}}) \\ &\hspace{5mm}\alpha_t \leftarrow max(\epsilon_2, \text{RMS}(\theta_{t-1}))\rho_t \\ &\hspace{5mm}\theta_t \leftarrow \theta_{t-1} - \gamma \lambda \theta_{t-1} \\ &\hspace{5mm}\textbf{if} \: \text{dim}(G_t) > 1: \\ &\hspace{10mm}R_t \leftarrow \widehat{\beta}_{2_t}R_{t-1}+ (1-\widehat{\beta}_{2_t})(G_t \odot G_t) \cdot 1_m \\ &\hspace{10mm}C_t \leftarrow \widehat{\beta}_{2_t}C_{t-1}+ (1-\widehat{\beta}_{2_t}) 1^\top_n \cdot (G_t \odot G_t) \\ &\hspace{10mm}\widehat{V}_t \leftarrow \frac{R_t \cdot C_t}{max(1^\top_n \cdot R_t, \epsilon_1)} \\ &\hspace{5mm}\textbf{else} \\ &\hspace{10mm}\widehat{V}_t \leftarrow \widehat{\beta}_{2_t}\widehat{V}_{t-1}+ (1-\widehat{\beta}_{2_t}) \cdot (G_t \odot G_t) \\ &\hspace{5mm}U_t \leftarrow \frac{G_t}{max(\sqrt{\widehat{V}_t}, \epsilon_1)} \\ &\hspace{5mm}\widehat{U}_t \leftarrow \frac{U_t}{max(1, \frac{\text{RMS}(U_t)}{d})} \\ &\hspace{5mm}\theta_t \leftarrow \theta_{t-1} - \alpha_t \widehat{U}_t \\ &\rule{110mm}{0.4pt} \\[-1.ex] &\bf{return} \: \theta_t \\[-1.ex] &\rule{110mm}{0.4pt} \\[-1.ex] \end{aligned}

For further details regarding the algorithm we refer to Adafactor: Adaptive Learning Rates with Sublinear Memory Cost.

参数
  • params (iterable) – 要优化的参数或命名参数的迭代器,或者是定义参数组的字典的迭代器。使用命名参数时,所有组中的所有参数都应该命名。

  • lr (float, Tensor, optional) – unlike other optimizers, Adafactor does not require a learning rate, and Noam Shazeer and Mitchell Stern do not use lr at all. Deviating from the paper, this implementation uses lr for applying weight decay and as the maximum value for relative step size rho_t. Note that in the paper, a constant of 0.01 is used as the maximum value for relative step size, and so we set 0.01 as the default value. (default: 1e-2)

  • beta2_decay (float, optional) – the decay rate of beta2. beta2 standardly refers to the coefficient used for computing the running average of the gradient squared. (default: -0.8)

  • eps (Tuple[float, float], optional) – epsilon1 is the term added to the denominator of the update calculation to improve numerical stability. This use of epsilon1 deviates from the algorithm written in the paper! See note below for more details. epsilon2 is the term used to avoid having too small a weight update when applying parameter scaling. (default: (None, 1e-3))

  • d (float, optional) – the clipping threshold, used to avoid larger-than-desired updates.

  • weight_decay (float, optional) – weight decay coefficient (default: 1e-2)

  • foreach (bool, optional) – whether foreach implementation of optimizer is used. Note that the foreach implementation uses ~ sizeof(params) more peak memory than the for-loop version due to the intermediates being a tensorlist vs just one tensor. As Adafactor is commonly used when memory is prohibitive, Adafactor will default to the slower single tensor for-loop implementation unless this flag is explicitly True. This behavior is contrary to other optimizers, which will attempt defaulting to foreach on CUDA for faster runtime. (default: None)

  • maximize (bool, optional) – 最大化目标函数相对于 params,而不是最小化 (默认: False)

注意

The implementation of Adafactor subtly differs from Noam Shazeer and Mitchell Stern and implementations in some other frameworks with its use of learning rate and ϵ1\epsilon_1.

Regarding the learning rate hyperparameter: Noam Shazeer and Mitchell Stern do not use lr at all, as the stated algorithm uses ρt\rho_t and update clipping to affect the step size.

This implementation allows lr to influence the maximum value for ρt\rho_t

ρtmin(lr,1t)\begin{aligned} &\hspace{5mm}\rho_t \leftarrow min(lr, \frac{1}{\sqrt{t}}) \end{aligned}

This differs from Noam Shazeer and Mitchell Stern, who use a constant of 0.01 as the maximum value of ρt\rho_t

ρtmin(0.01,1t)\begin{aligned} &\hspace{5mm}\rho_t \leftarrow min(0.01, \frac{1}{\sqrt{t}}) \end{aligned}

Noam Shazeer and Mitchell Stern do not enforce an opinion on how weight decay should be computed, and so we use the learning rate as a coefficient for decoupled weight decay, similar to what is suggested in Decoupled Weight Decay Regularization.

Regarding the use of ϵ1\epsilon_1: The implementation attempts to replicate the presumed intention of Noam Shazeer and Mitchell Stern to use ϵ1\epsilon_1 as a stabilizing term when the squared gradient becomes small.

This stabilization can be written as

Rtβ^2tRt1+(1β^2t)(GtGt+1n1m)1mCtβ^2tCt1+(1β^2t)1n(GtGt+1n1m)V^tRtCtmax(1nRt,ϵ1)UtGtmax(V^t,ϵ1)\begin{aligned} &\hspace{5mm}R_t \leftarrow \widehat{\beta}_{2_t}R_{t-1}+ (1-\widehat{\beta}_{2_t})(G_t \odot G_t + 1_n \cdot 1^\top_m) \cdot 1_m \\ &\hspace{5mm}C_t \leftarrow \widehat{\beta}_{2_t}C_{t-1}+ (1-\widehat{\beta}_{2_t}) 1^\top_n \cdot (G_t \odot G_t + 1_n \cdot 1^\top_m) \\ &\hspace{5mm}\widehat{V}_t \leftarrow \frac{R_t \cdot C_t}{max(1^\top_n \cdot R_t, \epsilon_1)} \\ &\hspace{5mm}U_t \leftarrow \frac{G_t}{max(\sqrt{\widehat{V}_t}, \epsilon_1)} \\ \end{aligned}

where the row and column factors of gradient squared RtR_t and CtC_t are left alone, and we apply ϵ1\epsilon_1 at the final calculation of the variance estimate V^t\widehat{V}_t and for the update UtU_t.

This is in contrast to Noam Shazeer and Mitchell Stern and other frameworks which apply ϵ1\epsilon_1 to both row and column factors of the squared gradient, but not in the calculations after

Rtβ^2tRt1+(1β^2t)(GtGt+ϵ11n1m)1mCtβ^2tCt1+(1β^2t)1n(GtGt+ϵ11n1m)V^tRtCt1nRtUtGtV^t\begin{aligned} &\hspace{5mm}R_t \leftarrow \widehat{\beta}_{2_t}R_{t-1}+ (1-\widehat{\beta}_{2_t})(G_t \odot G_t + \epsilon_1 1_n \cdot 1^\top_m) \cdot 1_m \\ &\hspace{5mm}C_t \leftarrow \widehat{\beta}_{2_t}C_{t-1}+ (1-\widehat{\beta}_{2_t}) 1^\top_n \cdot (G_t \odot G_t + \epsilon_1 1_n \cdot 1^\top_m) \\ &\hspace{5mm}\widehat{V}_t \leftarrow \frac{R_t \cdot C_t}{1^\top_n \cdot R_t} \\ &\hspace{5mm}U_t \leftarrow \frac{G_t}{\sqrt{\widehat{V}_t}} \\ \end{aligned}

您可能会注意到,Noam Shazeer 和 Mitchell Stern 描述使用了梯度的平方和,而本实现则使用了平均值。这个选择在数学上是等价的,并且对于大的求和来说,能够提供更好的数值稳定性。

add_param_group(param_group)[source]#

Optimizerparam_groups 添加一个参数组。

这在微调预训练网络时可能很有用,因为随着训练的进行,可以使冻结的层变得可训练并添加到 Optimizer 中。

参数

param_group (dict) – 指定哪些 Tensor 应该被优化,以及组特定的优化选项。

load_state_dict(state_dict)[source]#

加载优化器状态。

参数

state_dict (dict) – 优化器状态。应为调用 state_dict() 返回的对象。

警告

请确保在初始化 torch.optim.lr_scheduler.LRScheduler 后调用此方法,因为在此之前调用会覆盖加载的学习率。

注意

参数的名称(如果它们存在于 state_dict() 中每个参数组的“param_names”键下)不会影响加载过程。要为自定义情况(例如,当加载的状态字典中的参数与优化器中初始化的参数不同时)使用参数名称,应实现自定义的 register_load_state_dict_pre_hook 来相应地调整加载的字典。如果加载的状态字典 param_groups 中存在 param_names,则它们将被保存并覆盖优化器状态中当前存在的名称。如果它们不存在于加载的状态字典中,优化器的 param_names 将保持不变。

示例

>>> model = torch.nn.Linear(10, 10)
>>> optim = torch.optim.SGD(model.parameters(), lr=3e-4)
>>> scheduler1 = torch.optim.lr_scheduler.LinearLR(
...     optim,
...     start_factor=0.1,
...     end_factor=1,
...     total_iters=20,
... )
>>> scheduler2 = torch.optim.lr_scheduler.CosineAnnealingLR(
...     optim,
...     T_max=80,
...     eta_min=3e-5,
... )
>>> lr = torch.optim.lr_scheduler.SequentialLR(
...     optim,
...     schedulers=[scheduler1, scheduler2],
...     milestones=[20],
... )
>>> lr.load_state_dict(torch.load("./save_seq.pt"))
>>> # now load the optimizer checkpoint after loading the LRScheduler
>>> optim.load_state_dict(torch.load("./save_optim.pt"))
register_load_state_dict_post_hook(hook, prepend=False)[source]#

注册一个 load_state_dict 后置钩子,它将在调用 load_state_dict() 后被调用。它应该具有以下签名:

hook(optimizer) -> None

参数 optimizer 是正在使用的优化器实例。

调用 load_state_dictself 上后,钩子将使用参数 self 调用。注册的钩子可用于在 load_state_dict 加载了 state_dict 后执行后处理。

参数
  • hook (Callable) – 用户定义的待注册钩子。

  • prepend (bool) – 如果为 True,则提供的后置 hook 将在 load_state_dict 上所有已注册的后置钩子之前执行。否则,提供的 hook 将在所有已注册的后置钩子之后执行。(默认: False)

返回

一个句柄,可用于通过调用 handle.remove() 来移除添加的钩子

返回类型

torch.utils.hooks.RemoveableHandle

register_load_state_dict_pre_hook(hook, prepend=False)[source]#

注册一个 load_state_dict 前置钩子,它将在调用 load_state_dict() 之前被调用。它应该具有以下签名:

hook(optimizer, state_dict) -> state_dict or None

参数 optimizer 是正在使用的优化器实例,参数 state_dict 是用户传递给 load_state_dictstate_dict 的浅拷贝。钩子可以就地修改 state_dict,或者选择性地返回一个新的。如果返回了 state_dict,它将被用于加载到优化器中。

钩子将使用参数 selfstate_dict 调用,在调用 load_state_dictself 上之前。注册的钩子可用于在调用 load_state_dict 之前执行预处理。

参数
  • hook (Callable) – 用户定义的待注册钩子。

  • prepend (bool) – 如果为 True,则提供的预置 hook 将在 load_state_dict 上所有已注册的预置钩子之前执行。否则,提供的 hook 将在所有已注册的预置钩子之后执行。(默认: False)

返回

一个句柄,可用于通过调用 handle.remove() 来移除添加的钩子

返回类型

torch.utils.hooks.RemoveableHandle

register_state_dict_post_hook(hook, prepend=False)[source]#

注册一个 state_dict 后置钩子,它将在调用 state_dict() 后被调用。

它应具有以下签名

hook(optimizer, state_dict) -> state_dict or None

钩子将使用参数 selfstate_dict 调用,在 self 上生成 state_dict 后。钩子可以就地修改 state_dict,或者选择性地返回一个新的。注册的钩子可用于在返回 state_dict 之前对其进行后处理。

参数
  • hook (Callable) – 用户定义的待注册钩子。

  • prepend (bool) – 如果为 True,则提供的后置 hook 将在 state_dict 上所有已注册的后置钩子之前执行。否则,提供的 hook 将在所有已注册的后置钩子之后执行。(默认: False)

返回

一个句柄,可用于通过调用 handle.remove() 来移除添加的钩子

返回类型

torch.utils.hooks.RemoveableHandle

register_state_dict_pre_hook(hook, prepend=False)[source]#

注册一个 state_dict 前置钩子,它将在调用 state_dict() 之前被调用。

它应具有以下签名

hook(optimizer) -> None

参数 optimizer 是正在使用的优化器实例。钩子将使用参数 self 调用,在调用 state_dictself 上之前。注册的钩子可用于在调用 state_dict 之前执行预处理。

参数
  • hook (Callable) – 用户定义的待注册钩子。

  • prepend (bool) – 如果为 True,则提供的预置 hook 将在 state_dict 上所有已注册的预置钩子之前执行。否则,提供的 hook 将在所有已注册的预置钩子之后执行。(默认: False)

返回

一个句柄,可用于通过调用 handle.remove() 来移除添加的钩子

返回类型

torch.utils.hooks.RemoveableHandle

register_step_post_hook(hook)[source]#

注册一个优化器步骤后钩子,它将在优化器步骤之后被调用。

它应具有以下签名

hook(optimizer, args, kwargs) -> None

参数 optimizer 是正在使用的优化器实例。

参数

hook (Callable) – 用户定义的待注册钩子。

返回

一个句柄,可用于通过调用 handle.remove() 来移除添加的钩子

返回类型

torch.utils.hooks.RemovableHandle

register_step_pre_hook(hook)[source]#

注册一个优化器步骤预钩子,它将在优化器步骤之前被调用。

它应具有以下签名

hook(optimizer, args, kwargs) -> None or modified args and kwargs

参数 optimizer 是正在使用的优化器实例。如果 args 和 kwargs 被前置钩子修改,则转换后的值将作为包含 new_args 和 new_kwargs 的元组返回。

参数

hook (Callable) – 用户定义的待注册钩子。

返回

一个句柄,可用于通过调用 handle.remove() 来移除添加的钩子

返回类型

torch.utils.hooks.RemovableHandle

state_dict()[source]#

将优化器的状态作为 dict 返回。

它包含两个条目

  • state:一个包含当前优化状态的 Dict。其内容

    在不同的优化器类中会有所不同,但有一些共同的特点。例如,状态是按参数保存的,而参数本身不保存。 state 是一个映射参数 ID 到一个包含每个参数对应状态的 Dict 的字典。

  • param_groups:一个包含所有参数组的 List,其中每个

    参数组是一个 Dict。每个参数组包含优化器特有的元数据,例如学习率和权重衰减,以及组中参数的 ID 列表。如果参数组使用 named_parameters() 初始化,则名称内容也会保存在状态字典中。

注意:参数 ID 可能看起来像索引,但它们只是将状态与 param_group 关联的 ID。从 state_dict 加载时,优化器会按顺序匹配 param_group 的 params(int ID)和优化器的 param_groups(实际的 nn.Parameter),以匹配状态,而无需额外验证。

返回的状态字典可能看起来像

{
    'state': {
        0: {'momentum_buffer': tensor(...), ...},
        1: {'momentum_buffer': tensor(...), ...},
        2: {'momentum_buffer': tensor(...), ...},
        3: {'momentum_buffer': tensor(...), ...}
    },
    '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'] (optional)
        }
    ]
}
返回类型

dict[str, Any]

step(closure=None)[source]#

执行单个优化步骤。

参数

closure (Callable, 可选) – 一个重新评估模型并返回损失的闭包。

zero_grad(set_to_none=True)[source]#

重置所有优化过的 torch.Tensor 的梯度。

参数

set_to_none (bool, optional) –

将梯度设置为 None,而不是设置为零。默认值:True

这通常会降低内存占用,并能适度提高性能。但是,它会改变某些行为。例如:

  1. 当用户尝试访问梯度并对其进行手动运算时,None 属性或全零的 Tensor 会产生不同的行为。

  2. 如果用户请求 zero_grad(set_to_none=True) 然后执行 backward,对于未收到梯度的参数,其 .grad 保证为 None。

  3. torch.optim 优化器在梯度为 0 或 None 时行为不同(一种情况是以 0 梯度执行步长,另一种情况是跳过该步长)。