尧图精选

动手学深度学习:AdaGrad算法全解析——从稀疏特征学习率难题到逐坐标自适应优化

🕒 发布时间:2026/10/1 2:07:22 📁 来源:尧图网络
人工智能深度学习机器学习教程【免费下载链接】d2l-zh《动手学深度学习》面向中文读者、能运行、可讨论。中英文版被70多个国家的500多所大学用于教学。项目地址https://gitcode.com/GitHub_Trending/d2/d2l-zh点击查看免费下载AdaGradAdaptive Gradient是《动手学深度学习》优化算法章节chapter_optimization/adagrad.md讲解的一种经典自适应学习率算法它通过累加历史梯度平方为每个坐标独立地缩放学习率从而天然地解决稀疏特征训练中的学习率困境。读完本文你将掌握 AdaGrad 的数学原理、条件数与预处理视角下的设计动机并能在 MXNet、PyTorch、TensorFlow、PaddlePaddle 四种框架下从零实现和直接调用该优化器。从稀疏特征与学习率难题说起训练语言模型时我们通常希望在学习过程中以 $\mathcal{O}(t^{-\frac{1}{2}})$ 或更低的速度降低学习率。然而现实中的特征往往稀疏——比如预先条件precondition一词出现的频率远低于学习learning。这种稀疏性在自然语言处理中十分常见在计算广告学、个性化协同过滤等领域同样普遍。问题在于只有在不常见特征出现时与其相关的参数才会得到有意义的更新。而学习率在持续下降这会导致两种极端对常见特征而言学习率下降得太慢参数迟迟无法收敛到最优值附近对不常见特征而言学习率下降得太快在特征还缺乏足够观测时参数就已经冻结无法确定其最佳值。一个朴素的想法是记录每个特征出现的次数并据此为每个特征单独设定学习率$$\eta_i \frac{\eta_0}{\sqrt{s(i, t) c}}$$其中 $s(i, t)$ 统计截至时刻 $t$ 特征 $i$ 被观测到的次数。这个方案实现简单且几乎没有额外开销但它仍需要人为决定计数如何随时间累积。AdaGrad 的核心思想用梯度平方替代计数器AdaGrad 算法见 d2l.bib 中的文献条目Duchi.Hazan.Singer.2011将粗略的计数器 $s(i, t)$ 替换为先前观测梯度的平方之和$$s(i, t1) s(i, t) \left(\partial_i f(\mathbf{x})\right)^2$$这样替换有两个好处我们不再需要决定梯度何时算足够大——阈值判断被自动累积的梯度平方所取代缩放会随梯度的大小自动变化通常对应较大梯度的坐标会被显著缩小而梯度较小的坐标则得到更平滑的处理。这一机制在实际应用中促成了计算广告学及其相关问题中非常有效的优化程序。不过要理解 AdaGrad 的全部优势最好先走进预处理preconditioning的理论视角。预处理视角条件数与坐标扭曲凸优化问题有助于分析算法的特性——虽然深度学习中的绝大多数问题都是非凸的但凸问题上获得的直觉与洞察往往能够延续。考虑最小化问题$$f(\mathbf{x}) \frac{1}{2} \mathbf{x}^\top \mathbf{Q} \mathbf{x} \mathbf{c}^\top \mathbf{x} b$$利用特征分解 $\mathbf{Q} \mathbf{U}^\top \boldsymbol{\Lambda} \mathbf{U}$$\boldsymbol{\Lambda}$ 是对角矩阵包含 $\mathbf{Q}$ 的特征值通过坐标变换 $\mathbf{x} \mathbf{U} \bar{\mathbf{x}}$可以将问题改写为每个坐标可独立求解的简化形式$$f(\mathbf{x}) \bar{f}(\bar{\mathbf{x}}) \frac{1}{2} \bar{\mathbf{x}}^\top \boldsymbol{\Lambda} \bar{\mathbf{x}} \bar{\mathbf{c}}^\top \bar{\mathbf{x}} b$$此时最优解为 $\bar{\mathbf{x}} -\boldsymbol{\Lambda}^{-1} \bar{\mathbf{c}}$最小值是 $-\frac{1}{2} \bar{\mathbf{c}}^\top \boldsymbol{\Lambda}^{-1} \bar{\mathbf{c}} b$。但这里藏着一个关键现象如果稍微扰动 $\mathbf{c}$$f$ 的最小化器可能发生剧烈变化。当特征值 $\boldsymbol{\Lambda}_i$ 很大时$\bar{x}_i$ 和 $\bar{f}$ 的最小值只发生微小变化而当 $\boldsymbol{\Lambda}_i$ 很小时$\bar{x}_i$ 的变化可能非常剧烈。最大与最小特征值之比定义了优化问题的条件数condition number$$\kappa \frac{\boldsymbol{\Lambda}_1}{\boldsymbol{\Lambda}_d}$$条件数 $\kappa$ 越大精确求解优化问题就越困难。一个理论上完美的修复方式是利用 $\mathbf{Q}$ 的特征值和特征向量将变量变换到 $\mathbf{z} : \boldsymbol{\Lambda}^{\frac{1}{2}} \mathbf{U} \mathbf{x}$使所有特征值都变成 1。但计算特征值与特征向量通常比解决原问题本身还要昂贵这个想法并不现实。折中方案是使用 $\mathbf{Q}$ 的对角线条目做重缩放开销远小于完整特征分解$$\tilde{\mathbf{Q}} \mathrm{diag}^{-\frac{1}{2}}(\mathbf{Q}) \mathbf{Q} ,\mathrm{diag}^{-\frac{1}{2}}(\mathbf{Q})$$此时 $\tilde{\mathbf{Q}}{ij} \mathbf{Q}{ij} / \sqrt{\mathbf{Q}{ii} \mathbf{Q}{jj}}$且对所有 $i$ 都有 $\tilde{\mathbf{Q}}_{ii} 1$。在大多数情况下这能大幅简化条件数——例如对轴对齐的问题它可以完全消除病态。然而深度学习中还有另一重障碍我们通常无法计算目标函数的二阶导数。对 $\mathbf{x} \in \mathbb{R}^d$即使只在小批量上二阶导数Hessian也可能需要 $\mathcal{O}(d^2)$ 的空间几乎不可行。AdaGrad 的巧妙之处在于用梯度信息作为 Hessian 对角线的廉价代理。为什么可行对 $\bar{f}(\bar{\mathbf{x}})$ 有$$\partial_{\bar{\mathbf{x}}} \bar{f}(\bar{\mathbf{x}}) \boldsymbol{\Lambda} \bar{\mathbf{x}} \bar{\mathbf{c}} \boldsymbol{\Lambda} \left(\bar{\mathbf{x}} - \bar{\mathbf{x}}_0\right)$$即梯度的大小取决于 $\boldsymbol{\Lambda}$ 和与最优值的差值。由于 AdaGrad 是随机梯度下降算法即使在最优值附近我们也会观察到具有非零方差的梯度因此梯度的方差可以放心地作为 Hessian 比例的廉价替代。完整的理论分析篇幅较长可参考 d2l.bib 中的原始论文。AdaGrad 算法公式与直觉正式地AdaGrad 用变量 $\mathbf{s}_t$ 累加过去的梯度方差$$\begin{aligned} \mathbf{g}t \partial{\mathbf{w}} l(y_t, f(\mathbf{x}_t, \mathbf{w})), \ \mathbf{s}t \mathbf{s}{t-1} \mathbf{g}_t^2, \ \mathbf{w}t \mathbf{w}{t-1} - \frac{\eta}{\sqrt{\mathbf{s}_t \epsilon}} \cdot \mathbf{g}_t. \end{aligned}$$其中所有操作都按坐标逐元素进行$\mathbf{v}^2$ 的条目是 $v_i^2$$\frac{1}{\sqrt{v}}$ 的条目是 $\frac{1}{\sqrt{v_i}}$$\mathbf{u} \cdot \mathbf{v}$ 的条目是 $u_i v_i$。$\eta$ 是学习率$\epsilon$ 是维持数值稳定性的常数避免除以 0初始化 $\mathbf{s}_0 \mathbf{0}$。要点解读与动量法需要跟踪一个辅助变量类似AdaGrad 为每个坐标单独维护学习率相比普通 SGDAdaGrad并未明显增加计算代价——主要计算量仍集中在 $l(y_t, f(\mathbf{x}_t, \mathbf{w}))$ 及其导数上由于 $\mathbf{s}_t$ 累加平方梯度它基本以线性速率增长梯度衰减后实际略慢于线性从而产生整体 $\mathcal{O}(t^{-\frac{1}{2}})$ 的学习率衰减但在单个坐标层面做了自适应调整对于凸问题这种衰减完全够用但在深度学习中我们往往希望更缓慢地降低学习率这催生了后续的 RMSProp、AdaDelta、Adam 等变体详见 chapter_optimization/rmsprop.md 与 chapter_optimization/adam.md。二维凸问题可视化实验以经典的非均匀目标函数为例$$f(\mathbf{x}) 0.1 x_1^2 2 x_2^2$$$f$ 在 $x_1$ 方向上非常平坦、在 $x_2$ 方向上陡峭与 chapter_optimization/momentum.md 中梯度下降演示使用的是同一函数族。使用学习率 $\eta 0.4$ 运行 AdaGrad#tab all def adagrad_2d(x1, x2, s1, s2): eps 1e-6 g1, g2 0.2 * x1, 4 * x2 s1 g1 ** 2 s2 g2 ** 2 x1 - eta / math.sqrt(s1 eps) * g1 x2 - eta / math.sqrt(s2 eps) * g2 return x1, x2, s1, s2 def f_2d(x1, x2): return 0.1 * x1 ** 2 2 * x2 ** 2 eta 0.4 d2l.show_trace_2d(f_2d, d2l.train_2d(adagrad_2d))可以观察到自变量的迭代轨迹较平滑不像普通梯度下降那样在 $x_2$ 方向来回震荡但由于 $\mathbf{s}_t$ 的累加效果使学习率不断衰减自变量在迭代后期的移动幅度变小。若把学习率提高到 $\eta 2$表现会更好——这表明即使在无噪声的情况下AdaGrad 的学习率衰减也可能相当剧烈需要确保参数能够适当收敛。这里的train_2d与show_trace_2d是仓库在四个框架下提供的可视化辅助函数例如 d2l/torch.py 中train_2d从 $(-5, -2)$ 出发迭代 20 步并记录轨迹show_trace_2d则在等高线上绘制优化轨迹d2l/mxnet.py 中提供了等价实现。从零实现 AdaGrad四种框架与动量法相同AdaGrad 需要为每个自变量维护一个与其形状相同的状态变量 $\mathbf{s}$。下面是本书在四个深度学习框架下的完整实现截取自 chapter_optimization/adagrad.md。MXNet 实现def init_adagrad_states(feature_dim): s_w d2l.zeros((feature_dim, 1)) s_b d2l.zeros(1) return (s_w, s_b) def adagrad(params, states, hyperparams): eps 1e-6 for p, s in zip(params, states): s[:] np.square(p.grad) p[:] - hyperparams[lr] * p.grad / np.sqrt(s eps)PyTorch 实现def init_adagrad_states(feature_dim): s_w d2l.zeros((feature_dim, 1)) s_b d2l.zeros(1) return (s_w, s_b) def adagrad(params, states, hyperparams): eps 1e-6 for p, s in zip(params, states): with torch.no_grad(): s[:] torch.square(p.grad) p[:] - hyperparams[lr] * p.grad / torch.sqrt(s eps) p.grad.data.zero_()TensorFlow 实现def init_adagrad_states(feature_dim): s_w tf.Variable(d2l.zeros((feature_dim, 1))) s_b tf.Variable(d2l.zeros(1)) return (s_w, s_b) def adagrad(params, grads, states, hyperparams): eps 1e-6 for p, s, g in zip(params, states, grads): s[:].assign(s tf.math.square(g)) p[:].assign(p - hyperparams[lr] * g / tf.math.sqrt(s eps))PaddlePaddle 实现def init_adagrad_states(feature_dim): s_w d2l.zeros((feature_dim, 1)) s_b d2l.zeros(shape(1, )) return (s_w, s_b) def adagrad(params, states, hyperparams): a [] eps 1e-6 for p, s in zip(params, states): with paddle.no_grad(): s[:] paddle.square(p.grad) p[:] - hyperparams[lr] * p.grad / paddle.sqrt(s eps) p.grad.zero_() a.append(p) return a实现细节要点eps 1e-6是数值稳定常数防止 $\sqrt{s}$ 为零时除零状态更新是**就地in-place**完成的s[:] g^2、p[:] - ...与算法公式逐条对应PyTorch / PaddlePaddle 版本在更新后显式调用p.grad.zero_()或p.grad.data.zero_()清零梯度这是与 MXNet / TensorFlow 在梯度管理方式上的差异。在真实数据集上训练与 chapter_optimization/minibatch-sgd.md 一节的小批量 SGD 实验相比这里需要使用更大的学习率因为 AdaGrad 的坐标级缩放会稀释有效步长#tab all data_iter, feature_dim d2l.get_data_ch11(batch_size10) d2l.train_ch11(adagrad, init_adagrad_states(feature_dim), {lr: 0.1}, data_iter, feature_dim);这里的get_data_ch11加载的是归一化后的 airfoil 自噪声数据集前 1500 条样本train_ch11负责初始化线性回归模型、迭代训练并绘制损失曲线具体见 d2l/torch.py 与 d2l/mxnet.py。本书在此数据集上统一使用该实验框架对比各优化算法因此观察到的收敛速度差异可以直接归因于算法本身。简洁实现直接调用框架优化器实际工程中无需手写更新逻辑直接使用各深度学习框架内置的 AdaGrad 优化器即可MXNetd2l.train_concise_ch11(adagrad, {learning_rate: 0.1}, data_iter)PyTorchtrainer torch.optim.Adagrad d2l.train_concise_ch11(trainer, {lr: 0.1}, data_iter)TensorFlowtrainer tf.keras.optimizers.Adagrad d2l.train_concise_ch11(trainer, {learning_rate : 0.1}, data_iter)PaddlePaddletrainer paddle.optimizer.Adagrad d2l.train_concise_ch11(trainer, {learning_rate: 0.1}, data_iter)train_concise_ch11内部使用框架原生的优化器对象封装训练循环PyTorch 版本见 d2l/torch.py省去了手动管理状态变量的工作。注意 TensorFlow 与 PaddlePaddle 的超参数键为learning_rate而 PyTorch 为lr这是各框架 API 约定差异容易踩坑。AdaGrad 的适用场景与局限小结 AdaGrad 的核心特性与适用范围逐坐标动态学习率AdaGrad 会在单个坐标层面动态降低学习率以梯度大小作为调节手段用较小的学习率补偿拥有较大梯度的坐标二阶信息的廉价代理在深度学习中受内存与计算限制精确计算二阶导数通常不可行梯度平方累积是一个有效替代缓解非均匀问题当优化问题的结构相当不均匀条件数大时AdaGrad 有助于缓解坐标扭曲对稀疏特征特别有效对于不常出现的特征学习率需要更慢地降低AdaGrad 恰好满足这一需求。主要局限在深度学习非凸问题上AdaGrad 有时降低学习率过于剧烈——因为 $\mathbf{s}_t$ 从初始值持续累加、单调不减学习率只会越变越小。缓解这一缺点的策略是后续章节讨论的 RMSProp用泄漏平均值 $\mathbf{s}t \leftarrow \gamma \mathbf{s}{t-1} (1-\gamma)\mathbf{g}_t^2$ 替代无界累加见 chapter_optimization/rmsprop.md与 Adam见 chapter_optimization/adam.md。延伸练习附思路提示原文档在末尾给出了六道练习这里附上简要思路供读者自查正交变换保持范数证明 $|\mathbf{c} - \mathbf{\delta}|_2 |\mathbf{U}\mathbf{c} - \mathbf{U}\mathbf{\delta}|_2$利用 $\mathbf{U}^\top \mathbf{U} \mathbf{I}$。这说明正交变量变换不会改变扰动的幅度从而论证旋转问题再求解与原问题难度等价。旋转 45 度的对比实验对 $f(\mathbf{x}) 0.1 x_1^2 2 x_2^2$ 及其旋转版本 $f(\mathbf{x}) 0.1 (x_1 x_2)^2 2 (x_1 - x_2)^2$ 分别运行 AdaGrad观察轨迹差异——AdaGrad 的坐标级缩放对轴对齐问题更友好旋转后条件数信息被打散到各坐标中。格什戈林圆盘定理证明矩阵 $\mathbf{M}$ 的每个特征值 $\lambda_i$ 都位于某个以 $\mathbf{M}{jj}$ 为圆心、$\sum{k \neq j} |\mathbf{M}_{jk}|$ 为半径的圆盘内。对角预处理的圆盘解读结合格什戈林定理分析 $\mathrm{diag}^{-\frac{1}{2}}(\mathbf{M}) \mathbf{M} ,\mathrm{diag}^{-\frac{1}{2}}(\mathbf{M})$ 的特征值分布——对角预处理将圆盘中心归一到 1通常使特征值分布更紧凑。深度网络实战对 chapter_convolutional-neural-networks/lenet.md 中应用于 Fashion-MNIST 的 LeNet 网络改用 AdaGrad 训练比较收敛曲线与学习率敏感度。衰减不那么激进的改造思考用梯度平方的滑动平均替代全量累加这正是 RMSProp 的出发点或者对 $\mathbf{s}_t$ 做指数衰减/有界截断以减缓学习率的持续下降。关键参考文献算法原始论文Duchi, John and Hazan, Elad and Singer, Yoram (2011),Adaptive Subgradient Methods for Online Learning and Stochastic Optimization条目记录在仓库 d2l.bib 中。配套章节chapter_optimization/momentum.md动量法与条件数、chapter_optimization/minibatch-sgd.md实验基准框架、chapter_optimization/rmsprop.md 与 chapter_optimization/adam.mdAdaGrad 的后续演进。赞分享人工智能深度学习机器学习教程【免费下载链接】d2l-zh《动手学深度学习》面向中文读者、能运行、可讨论。中英文版被70多个国家的500多所大学用于教学。项目地址https://gitcode.com/GitHub_Trending/d2/d2l-zh点击查看免费下载相关推荐D2L 优化算法实战Adagrad 自适应梯度算法——稀疏特征、预调节与逐坐标学习率D2L 优化算法实战Adagrad 自适应梯度算法——稀疏特征、预调节与逐坐标学习率 AdagradAdaptive Gradient自适应梯度算法是《文档教程人工智能深度学习NLP计算机视觉强化学习《动手学深度学习》AdaGrad 算法全解析逐坐标自适应学习率的前沿原理与多框架实战《动手学深度学习》AdaGrad 算法全解析逐坐标自适应学习率的前沿原理与多框架实战 AdaGradAdaptive Subgradient Methods人工智能深度学习机器学习教程深度学习优化利器AdaGrad自适应学习率算法完整指南深度学习优化利器AdaGrad自适应学习率算法完整指南 《动手学深度学习》d2l zh是面向中文读者的深度学习教程被70多个国家的500多所大学用于教学人工智能深度学习机器学习教程上一篇React Native SegmentedControl 常见问题清单解决高度、padding 与文字消失等 7 大坑下一篇Buck边缘计算让边缘设备构建速度提升50%的实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →