深度学习中的优化器之Shampoo算法原理与二阶优化机制
我将为您讲解Shampoo优化器算法。这是一个基于二阶优化思想的深度学习优化算法,特别适合大规模深度学习任务。
1. 算法背景与核心思想
问题背景:传统的随机梯度下降(SGD)及其变体(如Adam)都是一阶优化方法,只使用梯度的一阶矩信息。二阶优化方法(如牛顿法)使用Hessian矩阵(二阶导数),具有更快的收敛速度,但计算Hessian矩阵及其逆的计算复杂度是O(n²)甚至O(n³),对深度学习模型来说完全不现实。
Shampoo的核心创新:将参数矩阵的Hessian矩阵近似为两个较小矩阵的Kronecker积,从而大幅降低计算复杂度。具体来说:
- 对于权重矩阵W ∈ ℝ^(m×n),不直接计算完整的Hessian矩阵H ∈ ℝ^(mn×mn)
- 而是计算左预条件矩阵L ∈ ℝ^(m×m)和右预条件矩阵R ∈ ℝ^(n×n)
- 使得H ≈ L ⊗ R(Kronecker积)
2. 数学推导与算法细节
2.1 Kronecker积近似原理
设损失函数为L(W),梯度矩阵为G = ∇W L ∈ ℝ^(m×n)。
理想情况下,牛顿法更新为:
ΔW = H⁻¹G
但H是mn×mn矩阵,计算不可行。Shampoo的关键假设是:Hessian矩阵可以近似分解为:
H ≈ L ⊗ R
根据Kronecker积的性质,(L ⊗ R)⁻¹ = L⁻¹ ⊗ R⁻¹,且对于任意矩阵X:
(L ⊗ R)vec(X) = vec(LXR^T)
因此,更新规则可以近似为:
vec(ΔW) ≈ (L ⊗ R)⁻¹ vec(G) = vec(L⁻¹ G R⁻¹)
这就将O(m³n³)的计算复杂度降低到了O(m³ + n³)。
2.2 预条件矩阵的构造
如何得到L和R?Shampoo采用统计估计的方法:
-
计算梯度的外积:
L_t = β L_{t-1} + (1-β) GG^T
R_t = β R_{t-1} + (1-β) G^TG -
这里β是动量参数,类似Adam中的β₂
-
L估计的是梯度行之间的协方差结构
-
R估计的是梯度列之间的协方差结构
2.3 完整的更新公式
对于第t次迭代:
- 计算梯度:G_t = ∇W L(W_t)
- 更新预条件矩阵:
L_t = β L_{t-1} + (1-β) G_t G_t^T + εI
R_t = β R_{t-1} + (1-β) G_t^T G_t + εI - 计算矩阵的p次方根:
L_t^{-1/4} 和 R_t^{-1/4}(实际中使用-1/(2p)次方,p=2时为-1/4) - 参数更新:
W_{t+1} = W_t - η L_t^{-1/4} G_t R_t^{-1/4}
3. 计算优化与实现技巧
3.1 矩阵指数根的计算
计算矩阵的-1/4次方是算法的关键步骤。Shampoo采用以下方法:
- 特征值分解:L = QΛQ^T,则L^{-1/4} = QΛ^{-1/4}Q^T
- 但由于需要频繁计算,使用迭代方法:
- 牛顿-舒尔迭代法
- 或使用SVD分解的近似方法
3.2 内存优化
直接存储L和R需要O(m² + n²)内存,可能很大。Shampoo采用:
- 低秩近似:只存储特征值和主要特征向量
- 分块对角近似:假设L和R是块对角矩阵
- 动量压缩:使用移动平均的压缩格式
3.3 分布式计算优化
对于大规模分布式训练:
- 每个设备计算本地梯度
- 对L和R进行AllReduce聚合
- 分布式计算矩阵指数根
4. 收敛性分析
4.1 理论保证
Shampoo的收敛性基于以下理论结果:
- 在强凸函数上,收敛速度为O(1/T)
- 条件数降低:预条件处理实际上降低了优化问题的条件数
- 对于深度学习中的非凸问题,虽然没有严格的理论保证,但实验显示收敛更快
4.2 与一阶优化器的比较
设原问题的条件数为κ,则:
- SGD的收敛速度:O(κ/T)
- 带预条件的Shampoo:O(√κ/T)
5. 实际应用与变体
5.1 自适应学习率版本
将Shampoo与自适应学习率结合:
W_{t+1} = W_t - η_t L_t^{-1/4} G_t R_t^{-1/4}
η_t = η₀ / √(1 + ∑_{i=1}^t ||G_i||²)
5.2 与动量结合
加入Nesterov动量:
M_t = γ M_{t-1} + L_t^{-1/4} G_t R_t^{-1/4}
W_{t+1} = W_t - η M_t
5.3 针对卷积层的扩展
对于卷积核K ∈ ℝ^(c_out×c_in×h×w):
- 将卷积核重塑为矩阵:K' ∈ ℝ^(c_out hw × c_in)
- 计算L ∈ ℝ^(c_out hw × c_out hw) 和 R ∈ ℝ^(c_in × c_in)
- 更新后再reshape回原形状
6. 实验效果与适用场景
6.1 优势
- 收敛速度显著快于Adam、SGD
- 对学习率不太敏感
- 在语言模型、图像分类等任务上表现优异
- 特别适合参数矩阵较大的层(如全连接层、嵌入层)
6.2 缺点
- 计算开销较大(尽管比完整牛顿法小得多)
- 需要额外的内存存储预条件矩阵
- 对小规模模型可能不划算
6.3 实现建议
# 简化的Shampoo更新步骤
def shampoo_update(W, G, L, R, beta=0.9, epsilon=1e-8, lr=0.001):
# 更新预条件矩阵
L = beta * L + (1-beta) * G @ G.T + epsilon * eye(m)
R = beta * R + (1-beta) * G.T @ G + epsilon * eye(n)
# 计算矩阵的-1/4次方
L_inv_sqrt = matrix_power(L, -0.25)
R_inv_sqrt = matrix_power(R, -0.25)
# 参数更新
W = W - lr * L_inv_sqrt @ G @ R_inv_sqrt
return W, L, R
7. 算法总结
Shampoo算法的核心贡献在于将二阶优化思想可行地应用于深度学习。通过Kronecker积分解,它将不可行的完整Hessian逆计算转化为两个较小矩阵的操作。虽然计算和内存开销仍高于一阶方法,但在许多任务中,其更快的收敛速度足以弥补这一开销,特别适合计算资源充足、模型规模大的场景。
这个算法代表了深度学习优化器发展的一个重要方向:在保持可计算性的前提下,引入更多的曲率信息来加速训练。后续的许多工作(如AdaHessian、Sophia等)都在此基础上进行了改进和优化。