快捷键

torch.optim.radam 的源代码

# mypy: 允许未类型化定义
rRAdam 算法的实现
from 打字 导入 角色, 可选, 联合

导入 火炬
from 火炬 导入 张量

from .优化器 导入 (
    _可捕获文档,
    默认为融合或遍历,
    _可区分文档,
    _如果不受支持则禁用 Dynamo,
    _foreach_doc,
    _获取可捕获的设备,
    _获取标量数据类型,
    _获取值,
    _maximize_doc,
    _params_doc,
    _use_grad_for_differentiable,
    真实查看,
    优化器,
    参数 T,
)


全部 = ["RAdam", radam]


[文档] RAdam(优化器): # 无需注意:D101 定义 __init__( , 参数: 参数 T, 学习率: 并集[float, 张量] = 0.001, betas: 元组[float, float] = (0.9, 0.999), eps: 浮点数 = 1e-8, 权重衰减: 浮点数 = 0, 解耦权重衰减: 布尔值 = 错误, *, foreach: 可选[布尔] = , 最大化: 布尔值 = 错误, 可捕捉的: 布尔值 = 错误, 可微分的: 布尔值 = 错误, ): # 无需注意:D107 如果 isinstance(学习率, 张量) 学习率.元素数量() != 1: 提升 ValueError("Tensor lr 必须是 1 个元素") 如果 0.0 <= 学习率: 提升 ValueError(f"无效的学习率:"{学习率}") 如果 0.0 <= eps: 提升 ValueError(f"无效的 epsilon 值:"{eps}") 如果 0.0 <= betas[0] < 1.0: 提升 ValueError(f"在索引 0 处的无效 beta 参数:"{betas[0]}") 如果 0.0 <= betas[1] < 1.0: 提升 ValueError(f"无效的 beta 参数,索引为 1:"{betas[1]}") 如果 0.0 <= 权重衰减: 提升 ValueError(f"无效的 weight_decay 值:"{权重衰减}") 默认 = 字典( 学习率=学习率, betas=betas, eps=eps, 权重衰减=权重衰减, 最大化=最大化, foreach=foreach, 可捕捉的=可捕捉的, 解耦权重衰减=解耦权重衰减, 可微分的=可微分的, ) 超级().__init__(参数, 默认值) 定义 __setstate__(, 状态): # 无需注意:D105 超级().__setstate__(状态) for .参数组: 群组.setdefault(foreach, ) 群组.setdefault(最大化, 错误) 群组.setdefault(可微分的, 错误) 群组.setdefault("解耦权重衰减", 错误) 群组.setdefault("可捕获的", 错误) for p 群组[参数]: 状态 = .状态.获取(p, [] 如果 长度(状态) != 0 torch.is_tensor(状态[步骤)] 步骤值 = float(状态[步骤]) p_state[步骤] = ( torch.张量( 步值, 数据类型=_获取标量数据类型(), 设备=p.设备 ) 如果 群组["可捕获的"] 否则 torch.张量(步值, 数据类型=_获取标量数据类型()) ) 定义 初始化组( , 群组, 带梯度的参数, 梯度, 实验平均值, 实验平均平方值, 状态步骤 ): 复杂的参数 = for p 群组[参数]: 如果 p.梯度 : 复杂的参数 |= 火炬.是复杂的(p) 带梯度的参数.append(p) 如果 p.研究生.is_sparse: 提升 运行时错误("RAdam 不支持稀疏梯度") 梯度.append(p.研究生) 状态 = .状态[p] 懒惰状态初始化 如果 长度(状态) == 0: 状态[步骤] = ( 火炬.零值((), 数据类型=_获取标量数据类型(), 设备=p.设备) 如果 群组["可捕获的"] 否则 火炬.张量(0.0, 数据类型=_获取标量数据类型()) ) 指数移动平均的梯度值 状态[平均值] = 火炬.等于零的( p, 内存格式=火炬.保留格式 ) 平方梯度值的指数移动平均 状态["exp_avg_sq"] = 火炬.等于零的( p, 内存格式=火炬.保留格式 ) 实验平均值.append(状态[平均值]) 实验平均平方值.append(状态["exp_avg_sq"]) 状态步数.append(状态[步骤]) 返回 复杂的参数
[文档] @使用梯度进行可微分 def step(self, closure=None): """执行单个优化步骤。 Args: 闭包(Callable,可选):一个重新评估模型并返回损失的闭包。 。 """ self._cuda_graph_capture_health_check() loss = None if closure is not None: with torch.enable_grad(): loss = closure() for group in self.param_groups: params_with_grad: list[Tensor] = [] grads: list[Tensor] = [] exp_avgs: 列[Tensor] = [] exp_avg_sqs: 列[Tensor] = [] state_steps: 列[Tensor] = [] beta1, beta2 = cast(tuple[float, float], group["betas"]) has_complex = self._init_group( group, params_with_grad, grads, exp_avgs, exp_avg_sqs, state_steps ) radam( params_with_grad, grads, exp_avgs, exp_avg_sqs, 状态步骤, beta1=beta1, beta2=beta2, lr=group["lr"], weight_decay=group["weight_decay"], eps=group["eps"], maximize=group["maximize"], foreach=group["foreach"], capturable=group["capturable"] differentiable=group["differentiable"] decoupled_weight_decay=group["decoupled_weight_decay"] has_complex=has_complex ) 返回损失
RAdam.__doc__ = ( r实现 RAdam 算法。 .. math:: \begin{aligned} &\rule{110mm}{0.4pt} \\ &textbf{输入} : γ (lr), β1, β2 (betas), θ0 (params), f(θ) (目标函数), λ (权重衰减), \:\textit{maximize} \\ &\hspace{13mm} ε (epsilon), \textit{decoupled\_weight\_decay} \\ 初始化:m_0 ← 0(第一矩) v_0 ← 0(二阶矩),\\ &\hspace{18mm} \rho_{\infty} \leftarrow \frac{2}{1-\beta_2} -1 &\rule{110mm}{0.4pt} \\ for t=1 到 ... do 如果 \: \textit{最大化}: \\ g_t ← -∇_θ f_t (θ_{t-1}) \\ &\hspace{6mm}else \\ g_t ← ∇_θ f_t (θ_{t-1}) \\ &\hspace{6mm} θ_t ← θ_{t-1} \\ 如果 λ 不等于 0 如果 decoupled_weight_decay &\hspace{18mm} θ_t ← θ_t - γλθ_t \\ 否则 &\hspace{18mm} g_t ← g_t + λθ_t m_t ← β_1 m_{t-1} + (1 - β_1) g_t \\ v_t ← β_2 v_{t-1} + (1-β_2) g^2_t &\hspace{6mm}\widehat{m_t} \leftarrow m_t/\big(1-\beta_1^t \big) \\ 翻译:&\hspace{6mm}\widehat{m_t} \leftarrow m_t/\big(1-\beta_1^t \big) \\ &\hspace{6mm}\rho_t \leftarrow \rho_{\infty} - 2 t β^t_2 /\big(1-β_2^t \big) \\[0.1.ex] 如果 \: \rho_t > 5 \\ l_t ← √((1-β^t_2)) / (√v_t + ε) r_t ← \sqrt{\frac{(\rho_t-4)(\rho_t-2)\rho_{\infty}}{(\rho_{\infty}-4)(\rho_{\infty}-2) \rho_t}} \\ \sqrt{\frac{(\rho_t-4)(\rho_t-2)\rho_{\infty}}{(\rho_{\infty}-4)(\rho_{\infty}-2) \rho_t}} \\ &\hspace{12mm}θ_t ← θ_t - γ 估计 m_t r_t l_t \\ 否则 &\hspace{12mm}\theta_t \leftarrow \theta_t - \gamma \widehat{m_t} \\ &\规则{110 毫米}{0.4 点} \\[-1.ex] &\bf{return} \: \theta_t \\[-1.ex] &\规则{110 毫米}{0.4 点} \\[-1.ex] \end{aligned} 有关算法的更多详细信息,请参阅《自适应学习率方差及其超越》_。 此实现提供了一种选项,可以使用 Adam 中的原始 weight_decay 实现 (其中 weight_decay 应用于梯度)或 AdamW 中的实现 通过 decoupled_weight_decay 选项调整权重。当 decoupled_weight_decay 设置为 False 时 (默认),它使用原始 Adam 风格的权重衰减,否则,它使用 AdamW 风格 更接近于 RAdam 论文中`作者的实现`。更多信息 关于解耦权重衰减的内容,可以在《解耦权重衰减正则化》_中找到。 "文档" + rf"" 参数: {_params_doc} lr(浮点数,张量,可选):学习率(默认:1e-3) betas (Tuple[float, float], 可选): 用于计算系数 运行平均梯度及其平方(默认:(0.9, 0.999)) eps (float, 可选): 添加到分母中的项,以改善 数值稳定性(默认:1e-8) 权重衰减(float,可选):权重衰减(L2 惩罚)(默认:0) decoupled_weight_decay (bool, 可选): 是否解耦权重 类似 AdamW 中的衰减以获得 RAdamW。如果为 True,则算法不会在动量或方差中累积权重衰减。(默认:False) 在动量或方差中累积权重衰减。(默认:False) {_foreach_doc} {_maximize_doc} {_可捕获文档} {_可区分文档} .. _On the variance of the adaptive learning rate and beyond: https://arxiv.org/abs/1908.03265 .. _作者实现: https://github.com/LiyuanLucasLiu/RAdam .. _解耦权重衰减正则化: https://arxiv.org/abs/1711.05101 "文档" ) 定义 _single_tensor_radam( 参数: 列表[张量] 梯度: 列表[张量] 实验平均值: 列表[张量] 实验平均平方值: 列表[张量] 状态步数: 列表[张量] *, beta1: float, beta2: float, 学习率: float, 权重衰减: float, eps: float, 解耦权重衰减: 布尔, 可微分的: 布尔, 最大化: 布尔, 可捕捉的: 布尔, 有复杂的: 布尔, ): for i, 参数 列举(参数): 梯度 = 梯度[i] 如果 最大化 否则 -梯度[i] 指数平均值 = 实验平均值[i] 指数平均值的平方 = 实验平均平方值[i] 步骤_t = 状态步数[i] 如果编译,编译器将处理 cudagraph 检查,参见注释[torch.compile x capturable] 如果 火炬.编译器.is_compiling() 可捕捉的: 可捕获支持的设备 = _获取可捕获的设备() 断言 ( 参数.设备.类型 == 步骤_t.设备.类型 参数.设备.类型 可捕获支持的设备 ), f如果 capturable=True,则 params 和 state_steps 必须在支持的设备上:{支持捕获的设备} 如果 火炬.是复杂的(参数): 参数 = 火炬.真实查看(参数) 梯度 = 火炬.真实查看(研究生) 指数平均值 = 火炬.真实查看(exp_avg) 指数平均值的平方 = 火炬.真实查看(指数平均平方) # 更新步骤 步骤_t += 1 步骤 = 步骤_t 如果 可捕获的 否则 _获取值(步骤_t) 如果 权重衰减 != 0: 如果 解耦权重衰减: 参数.mul_(1 - 左右 * 权重衰减) else: 梯度 = 研究生.添加(参数, 阿尔法=权重衰减) 衰减第一个和第二个矩度的运行平均值系数 exp_avg.线性插值 _(研究生, 1 - beta1) 指数平均平方.mul_(beta2).addcmul_(研究生, 研究生, =1 - beta2) 偏差校正 1 = 1 - beta1**步骤 偏差校正 2 = 1 - beta2**步骤 纠正第一移动矩量的偏差 偏差校正的期望平均值 = 指数平均值 / 偏差校正 1 近似 SMA 的最大长度 比值无穷 = 2 / (1 - beta2) - 1 计算近似 SMA 的长度 ρ_t = ρ_∞ - 2 * 步骤 * (beta2**步长) / 偏差校正 2 定义 _compute_rect(): 返回 ( (rho_t - 4) * (rho_t - 2) * ρ∞ / ((ρ∞ - 4) * (ρ∞ - 2) * rho_t) ) ** 0.5 定义 _compute_adaptive_lr(): 期望平均平方根 = 指数平均平方.平方根() 如果 可微分的: 期望平均平方根 = 指数平均平方根.添加(eps) else: 期望平均平方根 = 指数平均平方根.加_(eps) 返回 (偏差校正 2**0.5) / 期望平均平方根 # 计算方差校正项并相应更新参数 如果 可捕捉的: 更新 = 火炬.哪里( rho_t > 5.0, _compute_rect() * _compute_adaptive_lr(), 1.0 ) 参数.加_(bias_corrected_exp_avg * 左右 * 更新, 阿尔法=-1.0) else: 如果 rho_t > 5.0: 参数.加_( 偏差校正的指数平均 * 左右 * _compute_adaptive_lr() * _compute_rect(), 阿尔法=-1.0, ) else: 参数.加_(偏差校正平均 * 学习率, 阿尔法=-1.0) 定义 多张量 RAdam( 参数: 列表[张量] 梯度: 列表[张量] 实验平均值: 列表[张量] 实验平均平方值: 列表[张量] 状态步数: 列表[张量] *, beta1: float, beta2: float, 学习率: float, 权重衰减: float, eps: float, 解耦权重衰减: 布尔, 可微分的: 布尔, 最大化: 布尔, 可捕捉的: 布尔, 有复杂的: 布尔, ): 如果 长度(参数) == 0: 返回 断言 可微分的, "_foreach 操作不支持自动求导" 如果编译,编译器将处理 cudagraph 检查,参见注释[torch.compile x capturable] 如果 火炬.编译器.is_compiling() 可捕捉的: 可捕获支持的设备 = _获取可捕获的设备( 支持 XLA= ) 断言 所有( p.设备.类型 == 步长.设备.类型 p.设备.类型 可捕获支持的设备 for p, 步骤 zip(参数, 状态步数) ), f如果 capturable=True,则 params 和 state_steps 必须在支持的设备上:{支持捕获的设备} 分组张量 = 优化器.按设备类型和数据类型分组张量( [参数, 梯度, 实验平均值, 实验平均平方值, 状态步数] # type: ignore[list-item] ) for ( 分组参数_, 分组梯度_, 分组实验平均值_, 分组实验平均平方, 分组状态步骤_, ), _ 分组张量.(): 分组参数 = 角色(列表[张量] 分组参数_) 分组梯度 = 角色(列表[张量] 分组梯度_) 分组实验平均值 = 角色(列表[张量] 分组实验平均值_) 分组实验平均平方 = 角色(列表[张量] 分组实验平均平方) 分组状态步骤 = 角色(列表[张量] 分组状态步骤_) # 更新步骤 # 如果步骤在 CPU 上,foreach 将回退到慢速路径,即通过循环调用 t.add(1) #然后 1 会被反复包裹成 Tensor,这比只包裹一次要慢。 #alpha 是必须的,以确保我们进入正确的重载。 如果 火炬.编译器.is_compiling() 分组状态步骤[0].是 CPU: 火炬._foreach_add_( 分组状态步骤, 火炬.张量(1.0, 设备="cpu"), 阿尔法=1.0 ) else: 火炬._foreach_add_(分组状态步骤, 1) 如果 有复杂的: 真实查看( 分组参数, 分组梯度, 分组实验平均值, 分组经验平均平方 ) 如果 最大化: 分组梯度 = 火炬._foreach_neg(分组梯度) # 类型:忽略[赋值] 近似 SMA 的最大长度 比值无穷 = 2 / (1 - beta2) - 1 计算近似 SMA 的长度 偏差校正 1: 并集[元组[张量, ...] 列表[张量]] 偏差校正 2: 并集[元组[张量, ...] 列表[张量]] rho_t_list: 并集[元组[张量, ...] 列表[张量]] 如果 可捕捉的: 偏差校正 1 = 火炬._foreach_pow(beta2, 分组状态步骤) 火炬._foreach_neg_(偏差校正 1) 火炬._foreach_add_(偏差校正 1, 1) 偏差校正 2 = 火炬._foreach_pow(beta2, 分组状态步骤) 火炬._foreach_mul_(偏差校正 2, 分组状态步骤) 火炬._foreach_mul_(偏差校正 2, 2) 火炬._foreach_div_(偏差校正 2, 偏差校正 1) 火炬._foreach_neg_(偏差校正 2) 火炬._foreach_add_(偏差校正 2, ρ∞) ρt 列表 = 偏差校正 2 else: ρt 列表 = [ ρ∞ - 2 * _获取值(步长) * (beta2 ** _获取值(步长)) / (1 - beta2 ** _获取值(步长)) for 步骤 分组状态步骤 ] 如果 权重衰减 != 0: 如果 解耦权重衰减: 火炬._foreach_mul_(分组参数, 1 - 左右 * 权重衰减) else: 重复使用已分配给最大化操作的中间内存(grouped_grads) 如果 最大化: 火炬._foreach_add_( 分组梯度, 分组参数, 阿尔法=权重衰减 ) else: 分组梯度 = 火炬._foreach_add_( # 类型:忽略[赋值] 分组梯度, 分组参数, 阿尔法=权重衰减 ) 衰减第一个和第二个矩度的运行平均值系数 火炬._foreach_lerp_(分组实验平均值, 分组梯度, 1 - beta1) 火炬._foreach_mul_(分组经验平均平方, beta2) 火炬._foreach_addcmul_( 分组经验平均平方, 分组梯度, 分组梯度, 1 - beta2 ) 删除本地中间文件,因为它将不再使用,以节省峰值内存 删除 分组梯度 如果 可捕捉的: 数字 = 火炬.遍历子项(rho_t_list, 4) sub2 = 火炬.遍历子项(rho_t_list, 2) 火炬._foreach_mul_(数字, sub2) 删除 sub2 torch._foreach_mul_(数字, 无穷大) ρ_∞ = (ρ_∞ - 4) * (ρ_∞ - 2) 分母 = torch._foreach_mul(ρ_t_列表, rho_inf) torch._foreach_div_(数字, denom) 删除 分母 torch._foreach_sqrt__(数字) # TODO(mlazos): 我们应该尝试获取 foreach_where 操作 https://github.com/pytorch/pytorch/issues/117884 矩形 = [ torch.哪里(rho_t > 5.0, n, 0.0) for n, ρ_t zip(数字, ρ_t 列表) ] 删除 数字 删除 ρ_t 列表 未校正步长 = [torch.哪里(矩形 > 0, 0.0, 1.0) for 矩形 矩形] torch._foreach_mul_(非矩形步长, 学习率) 偏差校正 1 = torch._foreach_pow(beta1, 分组状态步骤) torch._foreach_neg_(偏差校正 1) torch._foreach_add_(偏差校正 1, 1) torch._foreach_div_(不规则步长, 偏差校正 1) torch._foreach_neg_(不规则步长) 偏差校正 2 = torch._foreach_pow(beta2, 分组状态步骤) torch._foreach_neg_(偏差校正 2) torch._foreach_add_(偏差校正 2, 1) torch._foreach_sqrt__(偏差校正 2) torch._foreach_mul_(偏差校正 2, 学习率) torch._foreach_mul_(偏差校正 2, 矩形) 删除 矩形 torch._foreach_neg_(偏差校正 2) torch._foreach_div_(偏差校正 2, 偏差校正 1) 删除 偏差校正 1 else: 矩形 = [ ( # 类型:忽略[杂项] (rho_t - 4) # type: ignore[arg-type] * (ρ_t - 2) * ρ_∞ / ((ρ_∞ - 4) * (ρ_∞ - 2) * ρ_t) ) ** 0.5 如果 ρ_t > 5 否则 0 for ρ_t ρ_t_list ] 未校正的 = [0 如果 矫正 > 0 否则 1.0 for 矫正 矫正] 偏差校正 1 = [ 1 - beta1 ** _获取值(步长) for 步骤 分组状态步骤 ] 未校正步长 = [ (左右 * 矩形 / bc) * -1 for 矩形, bc zip(未校正的, 偏差校正 1) ] 偏差校正 2 = [ ((1 - beta2 ** _获取值(步长)) ** 0.5) * (左右 * 矫正 / bc) * -1 for 步长, 矫正, bc zip(分组状态步骤, 矩形, 偏差校正 1) ] 缓冲区 = torch._foreach 平方根(分组经验平均平方) torch._foreach_add_(缓冲区, eps) torch._foreach_div_(缓冲区, 偏差校正 2) torch._foreach_reciprocal_(缓冲区) torch._foreach_add_(缓冲区, 非矩形步长) # 这里,buffer = sqrt(1 - beta2^t) * 矩形步长 / (sqrt(v) + eps) + 非矩形步长 torch._foreach_addcmul_(分组参数, 分组实验平均值, 缓冲区) @_disable_dynamo_if_unsupported(单个张量函数=_单张量 radam) 定义 radam( 参数: 列表[张量] 梯度: 列表[张量] 实验平均值: 列表[张量] 实验平均平方值: 列表[张量] 状态步数: 列表[张量] 使用 torchscript 编译的函数不支持带默认值的只写关键字参数问题 #70627 现由 torch/distributed/optim 编译的函数 API 参数 解耦权重衰减: 布尔值 = 错误, foreach: 可选[布尔] = , 可微分的: 布尔值 = 错误, 可捕捉的: 布尔值 = 错误, 有复杂的: 布尔值 = 错误, 最大化: 布尔值 = 错误, *, beta1: float, beta2: float, 学习率: float, 权重衰减: float, eps: float, ): r功能性 API,执行 RAdam 算法计算。 详细信息请参阅 :class:`~torch.optim.RAdam`。 "文档" 如果 所有(isinstance(t, torch.张量) for t 状态步数): 提升 运行时错误( "API 已更改,`state_steps`参数必须包含一个单例张量列表" ) 如果 foreach : _, foreach = 默认为融合或遍历( 参数, 可微分的, 使用融合的= ) 如果 foreach torch.算子.是否正在脚本化(): 提升 运行时错误("torch.jit.script 不支持 foreach 优化器") 如果 foreach torch.算子.是否正在脚本化(): 函数 = _多张量 RAdam else: 函数 = _单张量 RAdam 函数( 参数, 梯度, 实验平均值, 实验平均平方值, 状态步数, beta1=beta1, beta2=beta2, 学习率=学习率, 权重衰减=权重衰减, eps=eps, 最大化=最大化, 解耦权重衰减=解耦权重衰减, 可微分的=可微分的, 可捕捉的=可捕捉的, 有复杂的=有复杂的, )

© 版权所有 PyTorch 贡献者。

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

文档

查看 PyTorch 的全面开发者文档

查看文档

教程

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

查看教程

资源

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

查看资源