Appearance
Adadelta算法
Adadelta 是 RMSProp 的 “全自动升级版”—— 彻底抛弃了全局学习率的设置,用参数本身的变化率来自动调整步长,就像登山者完全根据之前的步幅自动调整下一步的大小,不用预先设定步长,是 “零学习率参数” 的自适应优化算法。
一、核心逻辑:为啥不需要 “预设步长”?
1. RMSProp 的小痛点
RMSProp 解决了 Adagrad 学习率衰减太快的问题,但还是需要手动设置全局学习率 :
如果 太大,前期步长太大容易震荡;
如果 太小,后期步长太小收敛慢;
不同任务的最优 不一样,需要手动调试,很麻烦。
这就像登山时需要预先设定步长大小,遇到陡坡和平路都要手动调整,很费精力。
2. Adadelta 的解决方案
Adadelta 给登山者加了 “全自动步长调整” 的能力:用参数的变化率来替代全局学习率,不需要手动设置 ,完全自适应:
先记录梯度的二阶导数的泄漏平均值(和 RMSProp 一样),知道路况的崎岖程度;
再记录参数变化的二阶导数的泄漏平均值,知道之前的步幅大小;
用之前的步幅大小来调整当前的步长,自动适配路况。
简单说:Adadelta 让登山者 “根据之前走的步幅,自动调整下一步的大小”,不用预先设定步长,全自动适配路况。
二、Adadelta 的核心原理
1. 核心公式
Adadelta 需要维护两个状态变量,实现完全自适应的步长调整:
其中:
:梯度平方的泄漏平均值,和 RMSProp 的 一样,记录路况的崎岖程度;
:参数变化平方的泄漏平均值,记录之前的步幅大小;
:遗忘系数,常用值 0.9,控制保留的历史长度,和 RMSProp 的 一样;
:极小常数(比如 ),防止除以 0;
:按元素相乘,每个参数用自己的自适应步长更新。
2. 公式解读
Adadelta 的核心是用 替代了 RMSProp 中的全局学习率 :
是之前参数变化的均方根,相当于之前的平均步幅;
用之前的平均步幅来调整当前的梯度,相当于 “用过去的步长来适配当前的路况”,自动确定合适的步长;
当 时,相当于保留最近 10 步的梯度和参数变化的平均值。
3. 与 RMSProp 的核心区别
| 特性 | RMSProp | Adadelta |
|---|---|---|
| 学习率设置 | 需要手动设置全局学习率 | 不需要手动设置学习率,用参数变化率自动适配 |
| 状态变量 | 只需要维护一个状态变量 (梯度平方的泄漏平均值) | 需要维护两个状态变量 和 (梯度和参数变化的泄漏平均值) |
| 步长计算 | ||
| 适用场景 | 需要精细调学习率的场景 | 不想手动调学习率的快速上手场景 |
三、实战对比:Adadelta vs RMSProp
用二维函数 测试:
RMSProp:需要设置 , ,才能收敛;
Adadelta:只需要设置 ,不需要设置学习率,就能自动收敛到最小值,步长会自动适配路况。
这就像 RMSProp 登山者需要预先设定步长,而 Adadelta 登山者能自动根据路况调整步长,不用手动干预。
四、PyTorch 实战:全自动登山流程
1. 从零开始实现
手动实现 Adadelta 的参数更新逻辑,适合理解原理:
python
import torch
from torch import nn
from d2l import torch as d2l
# 1. 初始化Adadelta状态(每个参数需要两个状态变量:梯度平方平均值、参数变化平方平均值)
def init_adadelta_states(feature_dim):
s_w = torch.zeros((feature_dim, 1)) # 权重的梯度平方平均值
delta_w = torch.zeros((feature_dim, 1)) # 权重的参数变化平方平均值
s_b = torch.zeros(1) # 偏置的梯度平方平均值
delta_b = torch.zeros(1) # 偏置的参数变化平方平均值
return ((s_w, delta_w), (s_b, delta_b))
# 2. Adadelta更新函数
def adadelta(params, states, hyperparams):
rho, eps = hyperparams['rho'], 1e-5
for p, (s, delta) in zip(params, states):
with torch.no_grad():
# 计算梯度平方的泄漏平均值
s[:] = rho * s + (1 - rho) * torch.square(p.grad)
# 计算调整后的梯度(用参数变化的平均值替代学习率)
g = (torch.sqrt(delta + eps) / torch.sqrt(s + eps)) * p.grad
# 更新参数
p[:] -= g
# 计算参数变化平方的泄漏平均值
delta[:] = rho * delta + (1 - rho) * torch.square(g)
p.grad.data.zero_() # 清空梯度
# 3. 训练函数
def train_adadelta(rho, num_epochs=2):
# 加载数据
data_iter, feature_dim = d2l.get_data_ch11(batch_size=10)
# 定义模型
net = nn.Sequential(nn.Linear(feature_dim, 1))
nn.init.normal_(net[0].weight, std=0.01)
# 训练
d2l.train_ch11(
adadelta,
init_adadelta_states(feature_dim),
{'rho': rho},
data_iter, feature_dim, num_epochs
)
# 启动训练(只需要设置rho=0.9,不需要设置学习率)
train_adadelta(rho=0.9)2. 框架简洁实现
用 PyTorch 内置的optim.Adadelta直接调用,更简洁:
python
# 直接使用框架内置的Adadelta
trainer = torch.optim.Adadelta
d2l.train_concise_ch11(
trainer,
{'rho': 0.9}, # 只需要设置rho,不需要设置lr
data_iter
)五、优缺点:什么时候用 Adadelta?
1. 优点
完全自适应:不需要手动设置全局学习率,避免了学习率调试的麻烦;
解决 Adagrad 的痛点:和 RMSProp 一样,用泄漏平均值替代累加,学习率不会一直衰减;
适应性强:不同任务都能自动适配步长,快速上手。
2. 缺点
计算量略大:需要维护两个状态变量,比 RMSProp 多一个状态变量的计算;
选择敏感: 太大(比如 0.99),泄漏平均值更新太慢,步长调整不及时; 太小(比如 0.5),噪声太大,步长不稳定;
收敛速度略慢:因为步长是自动调整的,有时候比手动调优的 RMSProp 收敛慢一点。
3. 适用场景
不想手动调学习率的场景:比如快速上手的小任务,或者对学习率不熟悉的新手;
对学习率敏感的任务:比如一些难以调学习率的非凸任务;
替代 RMSProp 的场景:当你觉得 RMSProp 的学习率调试太麻烦时,用 Adadelta 替代。
六、常见误区:避开这 2 个坑
设置太大: 时,保留的历史太长,步长调整不及时,会像 Adagrad 一样后期步长太小;
认为 Adadelta 不需要调参:虽然不需要调学习率,但 还是需要调整,默认 0.9 是比较通用的选择。
七、核心总结
Adadelta 本质:全自动自适应的 RMSProp,用参数变化的平均值替代全局学习率,不需要手动设置学习率;
关键参数: (遗忘系数,默认 0.9),控制保留的历史长度;
核心优势:不需要手动调学习率,完全自适应,适合快速上手的场景;
一句话记忆:登山时不用预设步长,根据之前的步幅自动调整,全自动适配路况,轻松下山~
(注:文档部分内容可能由 AI 生成)