torch.optim.sparse_adam 的源代码
# mypy: 允许未类型化定义
from 打字
导入
联合
导入
火炬
from 火炬
导入
张量
from . 导入 _functional
是 F
from .优化器
导入 _maximize_doc, _params_doc,
优化器, ParamsT
全部 = [
SparseAdam]
[文档]
类 SparseAdam(
优化器):
定义 __init__(
我,
参数:
参数 T,
学习率:
联盟[float,
张量] =
0.001,
betas: 元组[float, float] = (0.9, 0.999),
eps: 浮点数 = 1e-8,
最大化:
布尔 =
错误,
):
如果 isinstance(
学习率,
张量)
和
学习率.
元素数量() != 1:
raise ValueError("Tensor lr 必须是 1 个元素")
如果
不 0.0 <
学习率:
raise ValueError(f"无效的学习率:"{
学习率}")
如果
不 0.0 < eps:
raise ValueError(f"无效的 epsilon 值:"{eps}")
如果
不 0.0
≤ betas[0] < 1.0:
raise ValueError(f"在索引 0 处的无效 beta 参数:"{betas[0]}")
如果
不 0.0
≤ betas[1] < 1.0:
raise ValueError(f"无效的 beta 参数,索引为 1:"{betas[1]}")
默认 =
字典(
学习率=
学习率, betas=betas, eps=eps,
最大化=
最大化)
超级().__init__(
参数,
默认值)
sparse_params = 输入文本为空,请提供需要翻译的文本
复杂参数 =
输入文本为空,请提供需要翻译的文本
for 索引,
参数组
在
列举(
我.
参数组):
断言 isinstance(
参数组,
字典
), f"param_groups 必须是一个字典列表,但得到了"{
类型(
参数组)}"
# 对于给定的参数组,在迭代之前先将给定的参数转换为列表
for d_index, d_param 在
列举(
参数组[
参数
)]
如果 d_param.is_sparse:
稀疏参数.append
[
索引, d_index])
如果 d_param.
是复杂的():
complex_params.append[
索引, d_index])
如果 sparse_params:
raise ValueError(
f索引处的稀疏参数{sparse_params}
SparseAdam 需要密集的参数张量
)
如果 complex_params:
raise ValueError(
f"在索引处的复杂参数"{complex_params}
: SparseAdam 不支持复杂数据参数
)
[文档] @torch.
不梯度()
定义
步长(
我,
闭包=
无):
执行单个优化步骤。
参数:
闭包(Callable,可选):一个重新评估模型并返回损失的闭包
和返回损失。
"文档"
损失 =
无
如果
闭包
是
不
无:
与 torch.
启用梯度():
损失 =
闭包()
for 组
在
我.
参数组:
带梯度的参数:
列表[
张量] =
输入文本为空,请提供需要翻译的文本
梯度:
列表[
张量] =
输入文本为空,请提供需要翻译的文本
实验平均值:
列表[
张量] =
输入文本为空,请提供需要翻译的文本
实验平均平方值:
列表[
张量] =
输入文本为空,请提供需要翻译的文本
状态步数:
列表[
整数] =
输入文本为空,请提供需要翻译的文本
beta1, beta2 = 群组[
贝塔]
最大化 =
群组.
获取(
最大化,
错误)
for p 在
群组[
参数]:
如果 p.
梯度
是
不
无:
带梯度的参数.append(p)
如果
不 p.
研究生.is_sparse:
raise 运行时错误(
"SparseAdam 不支持稠密梯度,请考虑使用 Adam"
)
梯度.append(p.
研究生)
状态 =
我.
状态[p]
# 状态初始化
如果
长度(
状态) == 0:
状态[
步骤] = 0
指数移动平均的梯度值
状态[
平均值] = torch.
等于零的(
p, 内存格式=torch.
保留格式
)
平方梯度值的指数移动平均
状态["exp_avg_sq"] = torch.
等于零的(
p, 内存格式=torch.
保留格式
)
实验平均值.append(
状态[
平均值])
实验平均平方值.append(
状态["exp_avg_sq"])
更新每个参数组的步骤
状态[
步骤] += 1
记录步骤更新后的步骤
状态步数.append(
状态[
步骤])
F.sparse_adam(
带梯度的参数,
梯度,
实验平均值,
实验平均平方值,
状态步数,
eps=群组[
eps
]
beta1=beta1,
beta2=beta2,
学习率=
群组["lr"
]
最大化=
最大化,
)
返回
损失
SparseAdam.__doc__ = rf稀疏 Adam 实现了 Adam 算法的掩码版本
适用于稀疏梯度。目前,由于实现限制(解释如下)
以下),SparseAdam 仅适用于狭窄的用例子集,具体
密集布局的参数以及稀疏布局的渐变。这种现象发生在
特殊情况,其中模块反向生成已经处于稀疏布局的梯度。
一个表现如此行为的 NN 模块示例是 `nn.Embedding(sparse=True)`。
稀疏 Adam 通过屏蔽参数和动量来近似 Adam 算法
更新对应梯度中零值的操作。而 Adam 算法
将根据所有值更新第一时刻、第二时刻和参数
SparseAdam 只更新梯度非零值对应的动量和参数。
关于`intended`实现的简化思考方式如下:
可以这样简单地思考`intended`实现的意图:
1. 创建稀疏梯度的非零值掩码。例如,
如果你的梯度看起来像[0, 5, 0, 0, 9],那么掩码将是[0, 1, 0, 0, 1]。
2. 将此掩码应用于运行时的矩,并对非零值进行计算。
4. 仅对非零值进行计算。
在参数上应用此掩码,并且仅在非零值上应用更新。
实际上,我们使用稀疏布局张量来优化这个近似,这意味着
被掩码且未实际化的梯度越多,优化性能就越好。
由于我们依赖于使用稀疏布局张量,我们推断出任何实际化的值在
稀疏布局非零,我们实际上并不验证所有值都不是零!
重要的是不要混淆语义稀疏张量(一个许多元素语义上稀疏的张量)
其值均为零的稀疏布局张量(一个`.is_sparse`
返回 `True`。SparseAdam 近似旨在用于 `语义` 稀疏
张量以及稀疏布局只是实现细节。更清晰的实现方式是使用 MaskedTensors,但这些是实验性的。
如果您怀疑您的梯度在语义上是稀疏的(但没有稀疏布局),这个变体可能不适合您。理想情况下,您希望避免
.. 注意::
如果您怀疑您的梯度在语义上是稀疏的(但不是稀疏布局),这个变体可能不适合您。理想情况下,您希望避免
如果您怀疑您的梯度在语义上是稀疏的(但不是稀疏布局),这个变体可能不适合您。理想情况下,您希望避免
将任何一开始就被怀疑是稀疏的东西具体化,因为
需要将所有梯度从密集布局转换为稀疏布局的必要性可能超过
性能提升。在这里,使用 Adam 可能是最佳替代方案,除非你
可以轻松设置您的模块以输出类似于稀疏梯度的输出
nn.Embedding(sparse=True) 如果您坚持转换您的梯度,您可以
因此,通过手动覆盖您的参数的 `.grad` 字段以它们的稀疏
在调用 `.step()` 之前设置等效值。
参数:
{_params_doc}
lr(浮点数,张量,可选):学习率(默认:1e-3)
betas (Tuple[float, float], 可选): 用于计算系数
运行平均梯度及其平方(默认:(0.9, 0.999))
eps (float, 可选): 添加到分母中的项,以改善
数值稳定性(默认:1e-8)
{_maximize_doc}
.. _Adam:随机优化的方法:
https://arxiv.org/abs/1412.6980
"文档"