快捷键

PyTorch 优化器 Adagrad 的源代码

# mypy: 允许未类型化定义
from 打字 导入 角色, 可选, 联合

导入 火炬
from 火炬 导入 张量

from .优化器 导入 (
    _默认融合或 foreach,
    _融合时设备数据类型检查,
    _可微文档,
    _遍历文档,
    _获取标量数据类型,
    _获取值,
    _maximize_doc,
    _params_doc,
    _use_grad_for_differentiable,
    _view_as_real,
    优化器,
    参数 T,
)


全部 = ["Adagrad", adagrad]


[文档] Adagrad(优化器): def __init__( , 参数: 参数 T, lr: 并集[float, 张量] = 0.01, lr_decay: 浮点数 = 0, weight_decay: 浮点数 = 0, 初始累加器值: 浮点数 = 0, eps: 浮点数 = 1e-10, foreach: 可选[布尔] = , *, 最大化: 布尔值 = 错误, 可微分的: 布尔值 = 错误, 融合的: 可选[布尔] = , ): 如果 isinstance(lr, 张量) lr.元素数量() != 1: 提升 ValueError("张量 lr 必须是 1 个元素") 如果 0.0 <= lr: 提升 ValueError(f"无效的学习率:"{lr}") 如果 0.0 <= lr_decay: 提升 ValueError(f"无效的 lr_decay 值:"{学习率衰减}") 如果 0.0 <= 权重衰减: 提升 ValueError(f"无效的权重衰减值:"{权重衰减}") 如果 0.0 <= 初始累加器值: 提升 ValueError( f"无效的初始累加器值:"{初始累加器值}" ) 如果 0.0 <= eps: 提升 ValueError(f"无效的 epsilon 值:"{eps}") 默认 = 字典( 学习率=学习率, 学习率衰减=学习率衰减, eps=eps, 权重衰减=权重衰减, 初始累积值=初始累积值, foreach=foreach, 最大化=最大化, 可微分的=可微分的, 融合=融合, ) 超级().__init__(参数, 默认值) 如果 融合: 如果 可微分的: 提升 运行时错误("融合不支持可微分") 如果 foreach: 提升 运行时错误("融合和 foreach 不能同时为 True。") .需要为融合进行设备数据类型检查 = 真实 群组 .参数组: p 群组[参数]: 状态 = .状态[p] 状态[步骤] = ( 火炬.零值( (), 数据类型=_获取标量数据类型(是否融合=群组[融合)] 设备=p.设备, ) 如果 群组[融合] 否则 火炬.张量(0.0, 数据类型=_获取标量数据类型()) ) 初始化值 = ( 复杂(初始累加器值, 初始累加器值) 如果 火炬.是复杂的(p) 否则 初始累加器值 ) 状态["求和"] = 火炬.完全一样( p, 初始化值, 内存格式=火炬.保留格式 ) def __setstate__(, 状态): 超级().__setstate__(状态) # 为 "fused" 定义 # MYPY 错误:名称 "fused" 可能未定义 fused = 群组 .参数组: 群组.setdefault(foreach, ) 群组.setdefault(最大化, 错误) 群组.setdefault(可微分的, 错误) 融合 = 群组.setdefault("融合", ) 状态值 = 列表(.状态.()) step_is_tensor = (长度(状态值) != 0) 火炬.is_tensor( 状态值[0] [步骤] ) 如果 步骤是张量: s 状态值: s[步骤] = 火炬.张量( float(s[步骤)] 数据类型=_获取标量数据类型(混合=混合的) ) def 共享内存(): 群组 .参数组: p 群组[参数]: 状态 = .状态[p] 状态["求和"].共享内存_() def _初始化组(, 群组, 带梯度的参数, 梯度, 状态和, 状态步骤): 有稀疏梯度, 有复杂 = 错误, p 群组[参数]: 如果 p.梯度 is : 如果 群组[融合] getattr( , _需要检查融合的设备数据类型, , ): _检查融合的设备数据类型(p, cuda 不支持=) .需要检查设备数据类型是否支持融合 = 有稀疏梯度 |= p.研究生.is_sparse 有复数 |= 火炬.是复杂的(p) 有梯度参数.append(p) 梯度.append(p.研究生) 状态 = .状态[p] 状态求和.append(状态["求和"]) 状态步骤.append(状态[步骤]) 返回 有稀疏梯度, 复杂的
[文档] @使用梯度进行可微分 def step(self, closure=None): """执行单个优化步骤。 Args: 闭包(Callable,可选):一个重新评估模型并返回损失的闭包。 。 """ 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] = [] state_sums: list[Tensor] = [] state_steps: 列表[Tensor] = [] has_sparse_grad, has_complex = self._init_group( group, params_with_grad, grads, state_sums, state_steps ) adagrad( 带梯度的参数, 梯度, 状态和, 状态步骤, 学习率=group["lr"], 权重衰减=group["weight_decay"], 学习率衰减=group["lr_decay"], eps=group["eps"] has_sparse_grad=has_sparse_grad foreach=group["foreach"] maximize=group["maximize"] differentiable=group["differentiable"], has_complex=has_complex, fused=group["fused"], grad_scale=getattr(self, "grad_scale", None), found_inf = getattr(self, "found_inf", None) ) 返回损失
Adagrad.__doc__ = ( r实现 Adagrad 算法。 .. math:: \begin{aligned} &\rule{110mm}{0.4pt} \\ &\textbf{输入} : \gamma \text{ (lr)}, \: \theta_0 \text{ (params)}, \: f(\theta) 目标函数,λ(权重衰减) &\hspace{12mm} τ(初始累加器值),:η(学习率衰减)\\ 初始化:state_sum_0 ← τ &\rule{110mm}{0.4pt} \\ for t=1 到 ... do g_t ← ∇_θ f_t (θ_{t-1}) \\ &\hspace{5mm} ~γ ← γ / (1 + (t-1)η) \\ 如果 λ 不等于 0 g_t ← g_t + λθ_{t-1} 状态和_t ← 状态和_{t-1} + g^2_t &\hspace{5mm}θ_t ← \theta_{t-1}- \tilde{\gamma} \frac{g_t}{\sqrt{state\_sum_t}+\epsilon} \\ \theta_{t-1} - \tilde{\gamma} \frac{g_t}{\sqrt{state\_sum_t}+\epsilon} \\ &\rule{110mm}{0.4pt} \\[-1.ex] &\bf{return} \: \theta_t \\[-1.ex] &\rule{110mm}{0.4pt} \\[-1.ex] \end{aligned} 关于算法的更多细节,请参阅《自适应梯度下降法在线学习和随机优化》_ "文档" + rf"" 参数: {_params_doc} lr (float, Tensor, 可选): 学习率(默认:1e-2) lr_decay (float, 可选): 学习率衰减(默认:0) weight_decay (float, 可选): 权重衰减(L2 惩罚)(默认:0) initial_accumulator_value (float, 可选): 梯度平方和的初始值(默认:0) sum of squares of gradients (float, 可选): 梯度平方和(默认:0) eps(浮点数,可选):添加到分母的项,以提高数值稳定性(默认:1e-10) 数值稳定性(默认:1e-10) {_foreach_doc} {_maximize_doc} {_可微文档} 混合(bool,可选):是否使用混合实现(仅 CPU)。 目前,支持 `torch.float64`、`torch.float32`、`torch.float16` 和 `torch.bfloat16` (默认:None)。请注意,混合实现不 支持稀疏或复杂梯度。 .. _自适应梯度下降法在线学习和随机优化 优化:http://jmlr.org/papers/v12/duchi11a.html "文档" ) def adagrad( 参数: 列表[张量] 梯度: 列表[张量] 状态求和: 列表[张量] 状态步长: 列表[张量] 融合: 可选[布尔] = , 梯度缩放: 可选[张量] = , found_inf: 可选[张量] = , # torchscript 编译的函数不支持只写参数默认值的问题 #70627 # 目前将这些设置为 kwargs,因为功能 API 是由 torch/distributed/optim 编译的 has_sparse_grad: 布尔值 = 错误, foreach: 可选[布尔] = , 可微分的: 布尔值 = 错误, 具有复杂的: 布尔值 = 错误, *, 学习率: float, 权重衰减: float, 学习率衰减: float, eps: float, 最大化: 布尔, ): r功能性 API,执行 Adagrad 算法计算。 详细信息请参阅 :class:`~torch.optim.Adagrad`。 "文档" 如果 所有(isinstance(t, 火炬.张量) t 状态步数): 提升 运行时错误( "API 已更改,`state_steps`参数必须包含单例张量列表。" ) 当用户为 foreach 或 fused 输入 False/True 时,请尊重。我们只想更改 默认值,当两者均未指定时。注意,我们默认为 foreach 并将 False 传递给 use_fused。这不是错误——我们希望在将其设置为默认值之前 烘焙一段时间,即使它通常更快。 如果 融合 is 遍历 is : _, 遍历 = 默认为融合或遍历( 参数, 可微分的, 使用融合的= ) 如果 融合 is : 融合 = 如果 foreach is : foreach = 如果 foreach 火炬.算子.是否正在脚本化(): 提升 运行时错误("torch.jit.script 不支持与 foreach 优化器一起使用") 如果 熔合 火炬.算子.是否正在脚本化(): 提升 运行时错误("torch.jit.script 不支持与熔合优化器一起使用") 如果 融合 火炬.算子.是否正在脚本化(): 函数 = _fused_adagrad 如果...否则 遍历 火炬.算子.是否正在脚本化(): 函数 = 多张量 Adagrad else: 函数 = 单张量 Adagrad 函数( 参数, 梯度, 状态和, 状态步数, lr=lr, 权重衰减=权重衰减, 学习率衰减=学习率衰减, eps=eps, 是否有稀疏梯度=是否有稀疏梯度, 最大化=最大化, 可微分的=可微分的, 包含复杂=复杂的, 梯度尺度=梯度缩放, 发现无穷大=发现无穷大, ) def _制作稀疏(研究生, 梯度索引, ): 大小 = 研究生.尺寸() 返回 火炬.稀疏 Coo 张量(梯度索引, , 尺寸) def _单张张量 Adagrad( 参数: 列表[张量] 梯度: 列表[张量] 状态总和: 列表[张量] 状态步骤: 列表[张量] 学习率梯度缩放: 可选[张量] 发现无穷大: 可选[张量] *, 学习率: float, 权重衰减: float, 学习率衰减: float, eps: float, 有稀疏梯度: 布尔, 最大化: 布尔, 可微分的: 布尔, 具有复杂的: 布尔, ): 断言 梯度缩放 is 发现无穷大 is 参数, 研究生, 状态总和, 步长_t zip(参数, 梯度, 状态总和, 状态步骤): # 更新步骤 步骤_t += 1 步骤 = _获取值(步骤_t) 梯度 = 梯度 如果 最大化 否则 -梯度 如果 权重衰减 != 0: 如果 研究生.is_sparse: 提升 运行时错误( "权重衰减选项与稀疏梯度不兼容" ) 梯度 = 研究生.添加(参数, 阿尔法=权重衰减) 清除率 = lr / (1 + (步骤 - 1) * lr 衰减) 如果 研究生.is_sparse: 梯度 = 研究生.合并() # 更新是非线性的,因此索引必须是唯一的 累加索引 = 研究生.索引() 累加值 = 研究生.() 状态总和.加_(_创建稀疏(研究生, 梯度索引, 梯度值.pow(2))) std = 状态和.sparse_mask(研究生) 标准值 = 标准的.().sqrt_().加_(eps) 参数.加_( 构建稀疏(研究生, 梯度索引, 梯度值 / 标准值), 阿尔法=-清除 ) else: 是否为复数 = 火炬.是复杂的(参数) 如果 是复杂的: 梯度 = 火炬.真实查看(研究生) 状态总和 = 火炬.真实查看(状态总和) 参数 = 火炬.真实查看(参数) 状态和.加减乘_(研究生, 研究生, =1) 如果 可微分的: std = 状态和.平方根() + eps else: std = 状态总和.平方根().加_(eps) 参数.addcdiv_(研究生, 标准的, =-clr) 如果 是复杂的: 参数 = 火炬.以复数视图查看(参数) state_sum = 火炬.以复数视图查看(状态和) def _多张量 Adagrad( 参数: 列表[张量] 梯度: 列表[张量] 状态总和: 列表[张量] 状态步数: 列表[张量] 梯度缩放: 可选[张量] 发现无穷大: 可选[张量] *, 学习率: float, 权重衰减: float, 学习率衰减: float, eps: float, has_sparse_grad: 布尔, maximize: 布尔, differentiable: 布尔, has_complex: 布尔, ): 断言 可微分的, "_foreach 操作不支持自动求导" 断言 梯度缩放 is found_inf is # 每当给空列表提供 foreach 函数时,将会抛出错误 如果 长度(参数) == 0: 返回 grouped_tensorlists = 优化器._group_tensors_by_device_and_dtype( [参数, 梯度, 状态求和, 状态步长] # type: ignore[list-item] ) ( 设备参数_, device_grads_, device_state_sums_, device_state_steps_, ), _ grouped_tensorlists.(): 设备参数 = 角色(列表[张量] 设备参数_) 设备梯度 = 角色(列表[张量] device_grads_) device_state_sums = 角色(列表[张量] device_state_sums_) device_state_steps = 角色(列表[张量] 设备状态步骤_) 设备是否有稀疏梯度 = 有稀疏梯度 任何( 研究生.is_sparse 梯度 设备梯度 ) 如果 设备具有稀疏梯度: 单个张量 Adagrad( 设备参数, 设备梯度, 设备状态和, 设备状态步骤, 学习率=学习率, 权重衰减=权重衰减, 学习率衰减=学习率衰减, eps=eps, 是否有稀疏梯度=, 最大化=最大化, 可微分的=可微分的, 具有复杂的=具有复杂的, 梯度缩放=梯度缩放, 发现无穷大=发现无穷大, ) continue 处理复杂参数 如果 具有复杂: _以真实视图(设备参数, 设备梯度, 设备状态总和) 如果 最大化: 设备梯度 = 火炬._foreach_neg(设备梯度) # 类型:忽略[赋值] # 更新步骤 # 如果步骤在 CPU 上,foreach 将回退到慢速路径,即通过循环调用 t.add(1) #然后 1 会被反复包裹成 Tensor,这比只包裹一次要慢。 #alpha 是必须的,以确保我们进入正确的重载。 如果 火炬.编译器.编译中() 设备状态步骤[0].是 CPU: 火炬._foreach_add_( 设备状态步骤, 火炬.张量(1.0, 设备="cpu"), 阿尔法=1.0 ) else: 火炬._foreach_add_(设备状态步骤, 1) 如果 权重衰减 != 0: 重复使用已分配的中间内存(device_grads)以最大化 如果 最大化: 火炬._foreach_add_(设备梯度, 设备参数, 阿尔法=权重衰减) else: 设备梯度 = 火炬.每次添加( # 类型:忽略[赋值] 设备梯度, 设备参数, 阿尔法=权重衰减 ) 减色 = [ -左右 / (1 + (_获取值(步长) - 1) * 学习率衰减) 步长 设备状态步数 ] 火炬._foreach_addcmul_(设备状态总和, 设备梯度, 设备梯度, =1) std = 火炬._foreach_sqrt(设备状态总和) 火炬._foreach_add_(标准的, eps) 如果 权重衰减 != 0 或者 最大化: 再次,重用已分配的中间内存(device_grads) 火炬._foreach_mul_(device_grads, minus_clr) 分子 = 设备梯度 else: 分子 = 火炬._foreach_mul(设备梯度, 减色) # 类型:忽略[赋值] 火炬._foreach_addcdiv_(设备参数, 分子, 标准的) def _融合 Adam( 参数: 列表[张量] 梯度: 列表[张量] 状态和: 列表[张量] 状态步数: 列表[张量] 梯度缩放: 可选[张量] 发现无穷大: 可选[张量] *, 学习率: float, 权重衰减: float, 学习率衰减: float, eps: float, 有稀疏梯度: 布尔, 最大化: 布尔, 可微的: 布尔, 具有复杂结构: 布尔, ) 翻译 : 如果 参数: 返回 如果 具有稀疏梯度 或者 具有复杂结构: 提升 运行时错误("融合不支持稀疏梯度或复杂参数") 如果 可微分的: 提升 运行时错误( "adagrad with fused=True 不支持 differentiable=True" ) grad_scale_dict = ( {grad_scale.设备: 梯度缩放} 如果 梯度缩放 is 否则 ) 找到无穷字典 = {找到无穷.设备: 发现信息} 如果 发现信息 is 否则 分组张量 = 优化器.按设备类型和 dtype 分组张量( [参数, 梯度, 状态总和, 状态步数] 忽略列表项 ) (设备, _), ( ( device_params_, device_grads_, device_state_sums_, 设备状态步骤, ), _, ) 分组张量.项目(): 设备参数 = 角色(列表[张量] 设备参数_) 设备梯度 = 角色(列表[张量] device_grads_) device_state_sums = 角色(列表[张量] device_state_sums_) device_state_steps = 角色(列表[张量] 设备状态步骤_) 设备梯度缩放, 设备发现无穷 = , 如果 梯度缩放 is 梯度缩放字典 is : 如果 设备 梯度缩放字典: 梯度缩放字典[设备] = 梯度缩放.(设备, 非阻塞=) 忽略索引 设备梯度缩放 = 梯度缩放字典[设备] 忽略索引 如果 发现无穷大 is 发现无穷大字典 is : 如果 发现_信息 发现_信息字典: 发现_信息字典[设备] = 发现_信息.(设备, 非阻塞=) 忽略索引 设备发现信息 = 发现信息字典[设备] 忽略索引 火炬._foreach_add_(设备状态步骤, 1) 火炬._fused_adagrad_( 设备参数, 设备梯度, 设备状态和, 设备状态步骤, 学习率=学习率, 学习率衰减=学习率衰减, 权重衰减=权重衰减, eps=eps, 最大化=最大化, 学习率梯度=设备梯度学习率, 发现无穷大值=设备已找到, ) 如果 设备已找到 is : 火炬._foreach_sub_( 设备状态步骤, [设备已找到] * 长度(设备状态步骤) )

© 版权所有 PyTorch 贡献者。

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

文档

查看 PyTorch 的全面开发者文档

查看文档

教程

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

查看教程

资源

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

查看资源