深度学习中的优化器之SGD with Hessian Averaging算法原理与实现细节
字数 2716 2025-12-06 16:53:07

深度学习中的优化器之SGD with Hessian Averaging算法原理与实现细节

题目描述
在深度学习的优化过程中,随机梯度下降(SGD)是广泛使用的方法,但它在处理非光滑、高曲率或噪声敏感的问题时,可能收敛缓慢或不稳定。一种改进方向是引入二阶信息(Hessian矩阵)的近似,以调整更新方向。然而,直接计算Hessian矩阵在深度学习里计算开销巨大。SGD with Hessian Averaging算法旨在通过平均历史梯度外积来近似Hessian矩阵的逆,从而在几乎不增加计算成本的前提下,模拟类似牛顿法的二阶优化效果。本题目将详细解释该算法的动机、数学原理、迭代步骤及实现细节。


解题过程循序渐进讲解

步骤1:理解问题的本质与动机
在深度学习中,损失函数 \(L(\theta)\) 的优化通常使用一阶梯度信息。标准的SGD更新规则为:

\[\theta_{t+1} = \theta_t - \eta \nabla L(\theta_t) \]

其中 \(\eta\) 是学习率。然而,梯度只包含一阶变化信息,如果损失函数曲面在不同方向曲率差异大(例如峡谷状),SGD会沿陡峭方向震荡,收敛缓慢。

  • 牛顿法利用了Hessian矩阵 \(H(\theta)\)(二阶导数矩阵)来调整更新步长:

\[ \theta_{t+1} = \theta_t - H^{-1} \nabla L(\theta_t) \]

它能自动在曲率小的方向走大步,曲率大的方向走小步,收敛更快。但问题在于:

  1. 计算 \(H\) 需要 \(O(n^2)\) 内存(n为参数量),深度学习模型参数动辄数百万,不可行。
  2. 计算 \(H^{-1}\) 需要 \(O(n^3)\) 计算量,更不可能。
  • 因此,我们需要一种低代价近似 \(H^{-1}\) 的方法。SGD with Hessian Averaging 的核心思想是:用历史梯度外积的平均来估计Hessian矩阵,再利用在线平均技巧避免存储所有历史梯度。

步骤2:从梯度外积到Hessian近似
对于一个平滑函数,Hessian矩阵是二阶导数。但在随机优化中,我们可以利用以下观察:

  • 在损失函数的极小点附近,梯度服从均值为0的分布,其协方差矩阵与Hessian矩阵有一定关系。
  • 更直接的思路:考虑梯度 \(g_t = \nabla L(\theta_t)\),其外积 \(g_t g_t^T\) 的期望在一定条件下可关联到Hessian(例如,当损失为平方误差时)。但更常用的是采用经验费雪信息矩阵(Empirical Fisher) 作为近似:

\[ F_t = \frac{1}{t} \sum_{i=1}^t g_i g_i^T \]

在一定的正则条件下,当梯度噪声均值为0时,\(F_t\) 趋近于Hessian的平均。

  • 但直接存储 \(F_t\) 仍需要 \(O(n^2)\) 内存。为了压缩,算法通常采用对角近似低秩近似。这里我们重点讲对角近似(即假设Hessian是对角矩阵),这在实践中常用且有效。

步骤3:对角Hessian平均的迭代公式
我们维护一个向量 \(h_t\)(维度与参数 \(\theta\) 相同),作为对角Hessian近似的运行平均。迭代过程:

  1. 在每一步 t,计算当前小批量梯度 \(g_t\)
  2. 更新对角Hessian近似 \(h_t\) 为历史梯度平方的指数移动平均(EMA):

\[ h_t = \beta h_{t-1} + (1-\beta) (g_t \odot g_t) \]

其中 \(\odot\) 表示逐元素乘法(即 \(g_t^2\) ), \(\beta \in (0,1)\) 是平均系数(通常取0.9~0.99)。这相当于近似对角Hessian矩阵 \(H_t\) 的第 j 个对角元为 \(h_{t,j}\)
3. 用 \(h_t\) 调整更新步长:

\[ \theta_{t+1} = \theta_t - \eta \frac{g_t}{\sqrt{h_t} + \epsilon} \]

这里 \(\epsilon\) 是为数值稳定加的小常数(如1e-8)。

这形式看起来很像RMSpropAdaGrad,但注意它们的目的不同:

  • AdaGrad/RMSprop 是为了自适应调整学习率,使每个参数更新幅度平衡。
  • Hessian Averaging 的目标是模拟牛顿法,用 \(h_t\) 估计曲率,因此理论上 \(h_t\) 应逼近二阶信息,而不仅仅是梯度平方的平均。但实践中,由于深度学习的高维非凸性,直接用梯度平方平均作为曲率估计是一种有效启发式。

步骤4:算法伪代码

输入:初始参数 θ₀,学习率 η,平均系数 β,小批量大小 m,常数 ε
初始化:h₀ = 0
for t = 1, 2, ... do
    采样小批量样本 B_t
    计算梯度 g_t = ∇L(θ_{t-1}; B_t)
    更新对角Hessian近似:h_t = β h_{t-1} + (1-β) (g_t ⊙ g_t)
    计算调整后的更新:Δθ_t = -η * g_t / (sqrt(h_t) + ε)
    更新参数:θ_t = θ_{t-1} + Δθ_t
end for

步骤5:与现有优化器的联系

  • 若 β 接近1,h_t 是长期梯度平方的加权平均,类似RMSprop。
  • 若 β 很小,h_t 更关注近期梯度,能快速适应曲率变化。
  • AdaHessian(2019年提出的显式Hessian近似优化器)的区别:AdaHessian 通过Hutchinson随机估计计算Hessian对角,计算成本更高但更精确;而SGD with Hessian Averaging 仅用梯度外积,成本极低。

步骤6:实现细节与注意事项

  1. 初始化 h₀:通常设为0,避免初始步长过大。
  2. 偏差校正:由于 h_t 是EMA,初期 h_t 偏向0。可做偏差校正:

\[ \hat{h}_t = \frac{h_t}{1 - \beta^t} \]

然后用 \(\hat{h}_t\) 代替 h_t 在更新中使用,这与Adam的偏差校正类似。
3. 与动量结合:可额外加入一阶动量(动量法),形成类似Adam的变体,但此时 h_t 仍作为二阶矩估计。
4. 适用场景:适合损失曲面曲率变化明显的问题,如训练循环神经网络或Transformer的后期微调。但对噪声大的任务,梯度平方平均可能引入过估计,需调小 β。

步骤7:代码示例(PyTorch风格)

import torch

def sgd_hessian_averaging(params, lr=0.01, beta=0.9, eps=1e-8):
    # params: 模型参数列表
    # 初始化h字典
    h = {p: torch.zeros_like(p.data) for p in params}
    for p in params:
        if p.grad is None:
            continue
        grad = p.grad.data
        # 更新对角Hessian近似
        h[p] = beta * h[p] + (1 - beta) * (grad * grad)
        # 计算调整后的更新
        denom = torch.sqrt(h[p]) + eps
        p.data.addcdiv_(-lr, grad, denom)

总结
SGD with Hessian Averaging 通过历史梯度平方的平均来近似对角Hessian,以调整每个参数方向的步长,模拟牛顿法的缩放效果。它在几乎不增加计算负担的前提下,提供了比普通SGD更稳定的收敛,尤其适用于曲率变化较大的优化问题。

深度学习中的优化器之SGD with Hessian Averaging算法原理与实现细节 题目描述 : 在深度学习的优化过程中,随机梯度下降(SGD)是广泛使用的方法,但它在处理非光滑、高曲率或噪声敏感的问题时,可能收敛缓慢或不稳定。一种改进方向是引入二阶信息(Hessian矩阵)的近似,以调整更新方向。然而,直接计算Hessian矩阵在深度学习里计算开销巨大。SGD with Hessian Averaging算法旨在通过 平均历史梯度外积来近似Hessian矩阵的逆 ,从而在几乎不增加计算成本的前提下,模拟类似牛顿法的二阶优化效果。本题目将详细解释该算法的动机、数学原理、迭代步骤及实现细节。 解题过程循序渐进讲解 步骤1:理解问题的本质与动机 在深度学习中,损失函数 \( L(\theta) \) 的优化通常使用一阶梯度信息。标准的SGD更新规则为: \[ \theta_ {t+1} = \theta_ t - \eta \nabla L(\theta_ t) \] 其中 \(\eta\) 是学习率。然而,梯度只包含一阶变化信息,如果损失函数曲面在不同方向曲率差异大(例如峡谷状),SGD会沿陡峭方向震荡,收敛缓慢。 牛顿法 利用了Hessian矩阵 \( H(\theta) \)(二阶导数矩阵)来调整更新步长: \[ \theta_ {t+1} = \theta_ t - H^{-1} \nabla L(\theta_ t) \] 它能自动在曲率小的方向走大步,曲率大的方向走小步,收敛更快。但问题在于: 计算 \( H \) 需要 \( O(n^2) \) 内存(n为参数量),深度学习模型参数动辄数百万,不可行。 计算 \( H^{-1} \) 需要 \( O(n^3) \) 计算量,更不可能。 因此,我们需要一种 低代价近似 \( H^{-1} \) 的方法。SGD with Hessian Averaging 的核心思想是:用历史梯度外积的平均来估计Hessian矩阵,再利用在线平均技巧避免存储所有历史梯度。 步骤2:从梯度外积到Hessian近似 对于一个平滑函数,Hessian矩阵是二阶导数。但在随机优化中,我们可以利用以下观察: 在损失函数的极小点附近,梯度服从均值为0的分布,其协方差矩阵与Hessian矩阵有一定关系。 更直接的思路:考虑梯度 \( g_ t = \nabla L(\theta_ t) \),其外积 \( g_ t g_ t^T \) 的期望在一定条件下可关联到Hessian(例如,当损失为平方误差时)。但更常用的是采用 经验费雪信息矩阵(Empirical Fisher) 作为近似: \[ F_ t = \frac{1}{t} \sum_ {i=1}^t g_ i g_ i^T \] 在一定的正则条件下,当梯度噪声均值为0时,\( F_ t \) 趋近于Hessian的平均。 但直接存储 \( F_ t \) 仍需要 \( O(n^2) \) 内存。为了压缩,算法通常采用 对角近似 或 低秩近似 。这里我们重点讲对角近似(即假设Hessian是对角矩阵),这在实践中常用且有效。 步骤3:对角Hessian平均的迭代公式 我们维护一个向量 \( h_ t \)(维度与参数 \( \theta \) 相同),作为对角Hessian近似的运行平均。迭代过程: 在每一步 t,计算当前小批量梯度 \( g_ t \)。 更新对角Hessian近似 \( h_ t \) 为历史梯度平方的指数移动平均(EMA): \[ h_ t = \beta h_ {t-1} + (1-\beta) (g_ t \odot g_ t) \] 其中 \( \odot \) 表示逐元素乘法(即 \( g_ t^2 \) ), \( \beta \in (0,1) \) 是平均系数(通常取0.9~0.99)。这相当于近似对角Hessian矩阵 \( H_ t \) 的第 j 个对角元为 \( h_ {t,j} \)。 用 \( h_ t \) 调整更新步长: \[ \theta_ {t+1} = \theta_ t - \eta \frac{g_ t}{\sqrt{h_ t} + \epsilon} \] 这里 \( \epsilon \) 是为数值稳定加的小常数(如1e-8)。 这形式看起来很像 RMSprop 或 AdaGrad ,但注意它们的目的不同: AdaGrad/RMSprop 是为了自适应调整学习率,使每个参数更新幅度平衡。 Hessian Averaging 的目标是模拟牛顿法,用 \( h_ t \) 估计曲率,因此理论上 \( h_ t \) 应逼近二阶信息,而不仅仅是梯度平方的平均。但实践中,由于深度学习的高维非凸性,直接用梯度平方平均作为曲率估计是一种有效启发式。 步骤4:算法伪代码 步骤5:与现有优化器的联系 若 β 接近1,h_ t 是长期梯度平方的加权平均,类似RMSprop。 若 β 很小,h_ t 更关注近期梯度,能快速适应曲率变化。 与 AdaHessian (2019年提出的显式Hessian近似优化器)的区别:AdaHessian 通过Hutchinson随机估计计算Hessian对角,计算成本更高但更精确;而SGD with Hessian Averaging 仅用梯度外积,成本极低。 步骤6:实现细节与注意事项 初始化 h₀ :通常设为0,避免初始步长过大。 偏差校正 :由于 h_ t 是EMA,初期 h_ t 偏向0。可做偏差校正: \[ \hat{h}_ t = \frac{h_ t}{1 - \beta^t} \] 然后用 \(\hat{h}_ t\) 代替 h_ t 在更新中使用,这与Adam的偏差校正类似。 与动量结合 :可额外加入一阶动量(动量法),形成类似 Adam 的变体,但此时 h_ t 仍作为二阶矩估计。 适用场景 :适合损失曲面曲率变化明显的问题,如训练循环神经网络或Transformer的后期微调。但对噪声大的任务,梯度平方平均可能引入过估计,需调小 β。 步骤7:代码示例(PyTorch风格) 总结 : SGD with Hessian Averaging 通过历史梯度平方的平均来近似对角Hessian,以调整每个参数方向的步长,模拟牛顿法的缩放效果。它在几乎不增加计算负担的前提下,提供了比普通SGD更稳定的收敛,尤其适用于曲率变化较大的优化问题。