# mypy: 允许未类型化定义
from 打字
导入
任何,
角色,
可选,
联合
导入
火炬
from 火炬
导入
张量
from .optimizer 导入 (
_capturable_doc,
_default_to_fused_or_foreach,
_可微文档,
_如果不受支持则禁用 Dynamo,
_foreach 文档,
_获取可捕获的受支持设备,
获取标量数据类型,
最大化文档,
参数文档,
使用梯度进行可微分,
真实查看,
优化器,
参数 T,
)
全部 = ["Adadelta",
adadelta]
[文档]
类 Adadelta(
优化器):
def __init__(
我,
参数:
参数 T,
学习率:
并集[float,
张量] = 1.0,
拉欧:
浮点数 = 0.9,
eps: 浮点数 = 1e-6,
权重衰减:
浮点数 = 0,
foreach: 可选[
布尔] =
无,
*,
可捕获的:
布尔值 =
错误,
最大化:
布尔值 =
错误,
可微分的:
布尔值 =
错误,
):
如果 isinstance(
学习率,
张量)
和
学习率.
元素数量() != 1:
提升 ValueError(
"Tensor 学习率必须为 1 个元素")
如果
不 0.0 <=
学习率:
提升 ValueError(f
"无效的学习率:"{
学习率}")
如果
不 0.0 <=
拉索 <= 1.0:
提升 ValueError(f
"无效的 rho 值:"{
拉欧}")
如果
不 0.0 <= eps:
提升 ValueError(f
"无效的 epsilon 值:"{eps}")
如果
不 0.0 <=
权重衰减:
提升 ValueError(f
"无效的权重衰减值:"{
权重衰减}")
默认 =
字典(
学习率=lr,
拉欧=
拉欧,
eps=eps,
weight_decay=weight_decay,
maximize=最大化,
可捕获的=
可捕获的,
foreach=foreach,
可区分的=
可微的,
)
超级().__init__(
参数,
默认值)
def __setstate__(我,
状态):
超级().__setstate__(
状态)
为
群组
在
我.
参数组:
群组.setdefault(
foreach,
无)
群组.setdefault(
最大化,
错误)
群组.setdefault(
可微分的,
错误)
群组.setdefault(
可捕获的,
错误)
为 p
在
群组[
参数]:
状态变量 =
我.
状态.
获取(p,
[]
如果
长度(
状态) != 0
和
不
火炬.is_tensor(
状态[
步骤
)]
步骤值 = float(
状态[
步骤])
状态[
步骤] = (
火炬.
张量(
步值,
数据类型=
获取标量数据类型(),
设备=p.
设备
)
如果
群组[
可捕获的]
否则
火炬.
张量(
步值,
数据类型=
获取标量数据类型())
)
def 初始化组(
我,
群组:
字典[
字符串,
任何
]
带梯度的参数:
列表[
张量
]
梯度:
列表[
张量
]
平方平均值:
列表[
张量
]
acc_deltas: 列表[
张量
]
state_steps: 列表[
张量
]
):
has_complex = 假
p: 张量
为 p
在
群组["params"]:
如果 p.
梯度 is
无:
continue
复杂的参数 |=
火炬.
是复杂的(p)
带梯度的参数.append(p)
如果 p.
研究生.is_sparse:
提升
运行时错误(
Adadelta 不支持稀疏梯度)
梯度.append(p.
研究生)
状态 =
我.
状态[p]
懒惰状态初始化
如果
长度(
状态) == 0:
状态[
步骤] = (
火炬.
零值((),
数据类型=
_获取标量数据类型(),
设备=p.
设备)
如果
群组[
可捕获的]
否则
火炬.
零值((),
数据类型=
_获取标量数据类型())
)
状态["square_avg"] =
火炬.
等于零的(
p, 内存格式=
火炬.
保留格式
)
状态["acc_delta"] =
火炬.
等于零的(
p, 内存格式=
火炬.
保留格式
)
平方平均值.append(
状态[
平方平均])
累加差分.append(
状态[
累加差分值])
状态步骤.append(
状态[
步骤])
返回
具有复杂
[文档] @_use_grad_for_differentiable
def 步长(
我,
闭包=
无):
执行单个优化步骤。
参数:
闭包(Callable,可选):一个重新评估模型并返回损失的闭包
和返回损失。
"文档"
我._cuda_graph_capture_health_check()
损失 =
无
如果
闭包 is
不
无:
与
火炬.
启用梯度():
损失 =
闭包()
为
群组
在
我.
参数组:
带梯度的参数:
列表[
张量] =
输入文本为空,请提供需要翻译的文本
梯度:
列表[
张量] =
输入文本为空,请提供需要翻译的文本
平方平均值:
列表[
张量] =
输入文本为空,请提供需要翻译的文本
累加差分:
列表[
张量] =
输入文本为空,请提供需要翻译的文本
状态步骤:
列表[
张量] =
输入文本为空,请提供需要翻译的文本
(
学习率,
拉欧,
eps,
权重衰减,
foreach,
最大化,
可微的,
可捕捉的,
) = (
群组["lr"
]
群组["rho"
]
群组[
eps
]
群组[
权重衰减
]
群组[
foreach
]
群组[
最大化
]
群组[
可微分的
]
群组[
可捕获的
]
)
具有复杂的 =
我.
_初始化组(
群组, params_with_grad,
梯度,
平方平均值,
累加差分,
状态步数
)
adadelta(
带梯度参数,
梯度,
平方平均值,
累积变化量,
状态步数,
lr=lr,
拉欧=
拉欧,
eps=eps,
权重衰减=
权重衰减,
foreach=foreach,
最大化=
最大化,
可微分的=
可微分的,
可捕捉的=
可捕捉的,
结构复杂的=
具有复杂结构,
)
返回
损失
Adadelta.__doc__ = (
r实现 Adadelta 算法。
.. math::
\begin{aligned}
&\rule{110mm}{0.4pt} \\
&\textbf{输入} : \gamma \text{ (lr)}, \: \theta_0 \text{ (参数)},
\: f(\theta) \text{ (目标函数)}, \: \rho \text{ (衰减)},
\: \lambda \text{ (权重衰减)} \\
初始化:v_0 ← 0(平方平均)
\( u_0 \leftarrow 0 \) (累加变量)
&\rule{110mm}{0.4pt} \\
for t=1 到 ... do
g_t ← ∇_θ f_t (θ_{t-1}) \\
λ ≠ 0 \\
g_t ← g_t + λ θ_{t-1} \\
v_t ← v_{t-1} ρ + g^2_t (1 - ρ) \\
&\hspace{5mm}Δx_t ← \frac{\sqrt{u_{t-1} +}}{}}
\epsilon }}{ \sqrt{v_t + \epsilon} }g_t
u_t ← u_{t-1} ρ +
Δx^2_t (1 - ρ)
&\hspace{5mm}\theta_t \leftarrow \theta_{t-1} - \gamma \Delta x_t \\
&\rule{110mm}{0.4pt} \\[-1.ex]
&\bf{return} \: \theta_t \\[-1.ex]
&\rule{110mm}{0.4pt} \\[-1.ex]
\end{aligned}
有关算法的更多详细信息,请参阅《ADADELTA:自适应学习率方法》_。
"文档"
+ rf""
参数:
{_params_doc}
lr (float, Tensor, optional): 系数,用于在应用之前缩放 delta
到参数(默认:1.0)
rho (float, 可选): 用于计算移动平均的系数
平方梯度的系数(默认:0.9)。`rho`的值越高,
导致平均速度较慢,这有助于防止学习过程中的振荡。
eps(浮点数,可选):添加到分母中的项,以提高数值稳定性(默认:1e-6)。
eps(浮点数,可选):添加到分母中的项,以提高数值稳定性(默认:1e-6)。
eps(浮点数,可选):添加到分母中的项,以提高数值稳定性(默认:1e-6)。
weight_decay (浮点数,可选): 权重衰减(L2 惩罚)(默认:0)
{_foreach_doc}
{_capturable_doc}
{_maximize_doc}
{_可微文档}
.. _ADADELTA:自适应学习率方法:
https://arxiv.org/abs/1212.5701
"文档"
)
def _单张张量_adadelta(
参数:
列表[
张量
]
梯度:
列表[
张量
]
平方平均值:
列表[
张量
]
acc_deltas: 列表[
张量
]
状态步骤:
列表[
张量
]
*,
学习率: float,
拉欧: float,
eps: float,
权重衰减: float,
最大化:
布尔,
可微分的:
布尔,
可捕获的:
布尔,
复杂的:
布尔,
):
如果编译,编译器将处理 cudagraph 检查,参见注释[torch.compile x capturable]
如果
不
火炬.
编译器.
正在编译()
和
可捕获的:
可捕获支持的设备 =
_获取可捕获支持的设备(
支持_xla=
假
)
断言
所有(
p.设备.
类型 ==
步长.
设备.
类型
和 p.
设备.
类型
在
支持捕获的设备
为 p,
步骤
在 zip(
参数,
状态步骤)
), f如果 capturable=True,则 params 和 state_steps 必须在支持设备上:{
可捕获支持的设备}
。
为
参数,
研究生,
平均平方,
加速度变化量,
步数
在 zip(
参数,
梯度,
平方平均值,
累积变化量,
状态步数
):
步骤 += 1
梯度 =
梯度
如果
不
最大化
否则 -
梯度
如果
权重衰减 != 0:
梯度 =
研究生.
添加(
参数,
阿尔法=
权重衰减)
如果
火炬.
是复杂的(
参数):
平方平均值 =
火炬.
真实查看(
平方平均值)
准确度变化量 =
火炬.
真实查看(
逐差)
梯度 =
火炬.
真实查看(
研究生)
平方平均值.mul_(
拉欧).
加减乘(
研究生,
研究生,
值=1 -
拉欧)
std = 平方平均值.
添加(eps).sqrt_()
delta = acc_delta.添加(eps).sqrt_()
如果 differentiable:
delta = Δ.
克隆()
Δ.div_(
标准的).mul_(
研究生)
acc_delta.mul_(拉欧).addcmul_(
Δ,
Δ,
值=1 -
拉欧)
如果
火炬.
是复杂的(
参数):
delta = 火炬.
以复数视图查看(
Δ)
参数.
加_(
Δ,
阿尔法=-lr)
def _多张量 adadelta(
参数:
列表[
张量
]
梯度:
列表[
张量
]
平方平均值:
列表[
张量
]
acc_deltas: 列表[
张量
]
状态步骤:
列表[
张量
]
*,
学习率: float,
拉欧: float,
eps: float,
权重衰减: float,
最大化:
布尔,
可微分的:
布尔,
可捕捉的:
布尔,
有复杂的:
布尔,
):
断言
不
可微,
"_foreach 操作不支持自动微分"
# 如果正在编译,编译器将处理 cudagraph 检查,参见注解[torch.compile x capturable]
如果
不
火炬.
编译器.
正在编译()
和
可捕获的:
支持的设备 =
_获取支持的设备(
支持 XLA=
假
)
断言
所有(
p.设备.
类型 ==
步长.
设备.
类型
和 p.
设备.
类型
在
可捕获支持的设备
为 p,
步骤
在 zip(
参数,
状态步骤)
), f如果 capturable=True,则 params 和 state_steps 必须在支持的设备上:{
capturable 支持的设备}
。
如果
长度(
参数) == 0:
返回
分组张量 =
优化器.
按设备类型和数据类型分组张量(
[参数,
梯度,
平方平均值,
累加差分,
状态步骤] # type: ignore[list-item]
)
为 (
设备参数_,
设备梯度_,
设备平方平均值_,
设备加速度变化量_,
设备状态步骤_,
), _ 在
分组张量.
值():
设备参数 =
角色(
列表[
张量
]
设备参数_)
设备梯度 =
角色(
列表[
张量
] device_grads_)
device_square_avgs = 角色(
列表[
张量
] device_square_avgs_)
device_acc_deltas = 角色(
列表[
张量
]
设备加速度增量_)
设备状态步数 =
角色(
列表[
张量
]
设备状态步数_)
如果
是否复杂:
真实查看(
设备参数,
设备梯度,
设备平方平均值,
设备加速度变化
)
更新步骤
如果步骤在 CPU 上,foreach 将回退到慢速路径,即调用 t.add(1)的 for 循环,一次又一次地
1 将被一次又一次地包裹成 Tensor,这比如果我们只是
现已包裹一次。alpha 是必需的,以确保我们进入正确的重载。
如果
不
火炬.
编译器.is_compiling()
和
设备状态步骤[0].
是 CPU:
火炬._foreach_add_(
设备状态步骤,
火炬.
张量(1.0,
设备="cpu"),
阿尔法=1.0
)
else:
火炬._foreach_add_(
设备状态步骤, 1)
如果
最大化:
设备梯度 =
火炬._foreach_neg(
设备梯度)
# 类型:忽略[赋值]
如果
权重衰减 != 0:
重新使用为最大化分配的中间内存(device_grads)
如果
最大化:
火炬._foreach_add_(device_grads,
设备参数,
阿尔法=
权重衰减)
else:
设备梯度 =
火炬._foreach_add(
# 类型:忽略[赋值]
设备梯度,
设备参数,
阿尔法=
权重衰减
)
火炬._foreach_mul_(
设备平方平均值,
拉欧)
火炬._foreach_addcmul_(
设备平方平均值,
设备梯度,
设备梯度,
值=1 -
拉索
)
std = 火炬.
_foreach_add_(
设备平方平均值, eps)
火炬.
_foreach_sqrt__(
标准的)
跨度 =
火炬.
_foreach_add_(
设备加速度跨度, eps)
火炬.
_foreach_sqrt__(
跨度)
火炬._foreach_div_(
跨度,
标准的)
火炬._foreach_mul_(
跨度,
设备梯度)
火炬._foreach_mul_(
设备加速度跨度,
拉欧)
火炬._foreach_addcmul_(device_acc_deltas, deltas, deltas,
值=1 -
拉欧)
如果 LR 是一个张量,else 分支将内部调用 item()
这将导致在捕获时出现无声的错误
如果
可捕获的
和 isinstance(lr,
火炬.
张量):
火炬._foreach_mul_(deltas, -lr)
火炬._foreach_add_(
设备参数,
跨度)
else:
火炬._foreach_add_(
设备参数,
跨度,
阿尔法=-lr)
@_disable_dynamo_if_unsupported(单一张量函数=
_单一张量_adadelta)
def adadelta(
参数:
列表[
张量
]
梯度:
列表[
张量
]
平方平均值:
列表[
张量
]
累加差分:
列表[
张量
]
状态步数:
列表[
张量
]
使用 torchscript 编译的函数不支持带默认值的只写关键字参数问题 #70627
现由 torch/distributed/optim 编译的函数 API 参数
可捕获的:
布尔值 =
错误,
foreach: 可选[
布尔] =
无,
可微分的:
布尔值 =
错误,
具有复杂的:
布尔值 =
错误,
*,
lr: float,
拉欧: float,
eps: float,
权重衰减: float,
最大化:
布尔,
):
r执行 Adadelta 算法计算的函数 API。
请参阅:class:`~torch.optim.Adadelta` 以获取详细信息。
"文档"
此检查在编译期间较慢,因此我们跳过它。
如果确实需要,我们可以在 dynamo 中添加此检查。
如果
不
火炬.
编译器.
正在编译()
和
不
所有(
isinstance(t, 火炬.
张量)
为 t
在
状态步骤
):
提升
运行时错误(
"API 已更改,`state_steps`参数必须包含一个单例张量列表"
)
# 我们仍然尊重用户对 foreach 输入 False 的情况。
如果 foreach is
无:
_, foreach = _default_to_fused_or_foreach(
参数,
可微分的,
使用融合的=
假
)
如果 foreach
和
火炬.
算子.
是否正在脚本化():
提升
运行时错误(
"torch.jit.script 不支持 foreach 优化器")
如果 foreach
和
不
火炬.
算子.
是否正在脚本化():
函数 = _multi_tensor_adadelta
else:
函数 =
单个张量_adadelta
函数(
参数,
梯度,
平方平均值,
累积梯度,
状态步数,
lr=lr,
拉欧=
拉欧,
eps=eps,
权重衰减=
权重衰减,
最大化=
最大化,
可微分的=
可微分的,
可捕捉的=
可捕捉的,
有复杂的=
有复杂的,
)