一句话版:最速下降法 是在"给定度量(范数)下下降最快 的方向",本质是"带预条件的梯度下降 ";动量法 像"带惯性的球往谷底滚",用历史方向的累积抑制之字形、加速下山。
1. 从"下山"直觉到两把扳手
-
只有梯度(坡度)不够:峡谷又长又窄时,普通 GD 会在两壁间来回横跳。
-
两个补救思路:
- 换度量 :在你关心的"单位步长"定义下,挑最陡 的方向(最速下降 )→ 相当于给梯度加预条件。
- 加惯性 :别每次都急刹,允许一点"冲劲"(动量 )→ 把上一步的方向平均进来,抗噪又提速。
2. 最速下降法(Steepest Descent):把"最陡"说清楚
2.1 定义:在给定范数下的"最陡方向"
在点 xxx,用一阶近似 f(x+d)≈f(x)+∇f(x)⊤df(x+d)\approx f(x)+\nabla f(x)^\top df(x+d)≈f(x)+∇f(x)⊤d。
最速下降方向定义为
d⋆ = argmin∥d∥=1 ∇f(x)⊤d, d^\star \;=\; \arg\min_{\|d\|=1}\ \nabla f(x)^\top d, d⋆=arg∥d∥=1min ∇f(x)⊤d,
其中 ∥⋅∥\|\cdot\|∥⋅∥ 是你选定的范数(可不是必须的欧氏范数)。
-
若 ∥d∥=∥d∥2\|d\|=\|d\|_2∥d∥=∥d∥2(欧氏范数)→ d⋆=−∇f∥∇f∥2d^\star=-\frac{\nabla f}{\|\nabla f\|_2}d⋆=−∥∇f∥2∇f,方向就是负梯度 (GD 就是它的实例)。
-
若 ∥d∥=∥d∥M=d⊤Md\|d\|=\|d\|_M=\sqrt{d^\top M d}∥d∥=∥d∥M=d⊤Md (马氏范数 ,M≻0M\succ0M≻0):
d⋆ ∥ −M−1∇f(x), d^\star \;\parallel\; -M^{-1}\nabla f(x), d⋆∥−M−1∇f(x),
即先乘 M−1M^{-1}M−1 再向下走------这就是预条件梯度。
直觉:你规定"走一步"的尺度(范数),最速就会相应改变。选得好,就像把坑"拉圆",好走多了。
2.2 线搜索与步长
方向确定后,用步长 α\alphaα 更新:x+=x+αd⋆x^+ = x + \alpha d^\starx+=x+αd⋆。
常见做法:回溯线搜索 (Armijo 条件)或精确线搜索(二次目标时有闭式)。
二次型特例 :f(x)=12x⊤Qx−b⊤xf(x)=\tfrac12 x^\top Q x - b^\top xf(x)=21x⊤Qx−b⊤x(Q⪰0Q\succeq0Q⪰0),令 g=∇f=Qx−bg=\nabla f=Qx-bg=∇f=Qx−b。
-
欧氏最速下降(即普通 GD)的最优步长:
KaTeX parse error: Undefined control sequence: \* at position 9: \alpha^\̲*̲=\frac{g^\top g...
-
QQQ-范数最速下降 给出方向 −Q−1g-Q^{-1}g−Q−1g,这就是一次牛顿步的方向(差在是否做二阶步长)。
2.3 与自然梯度 / 预条件的关系
- 若选 MMM 为曲率近似 (如 Fisher 信息或 Hessian 的近似),就得到自然梯度/二阶预条件。
- 实务里 M−1M^{-1}M−1 用对角、块对角、L-BFGS 近似等实现,既提速又省算力。
当前点
选择范数或度量
计算梯度
最速方向: 预条件后取负向
步长: 回溯或精确线搜索
更新参数
说明:最速下降的循环 = 选度量 → 算梯度 → 预条件方向 → 线搜索 → 更新。
3. 动量法(Momentum):让"惯性"帮你少拐弯
3.1 Heavy-Ball(Polyak 动量)
速度变量 vvv 累积历史梯度:
vk+1=β vk+∇f(xk),xk+1=xk−η vk+1, \begin{aligned} v_{k+1} &= \beta\, v_k + \nabla f(x_k),\\ x_{k+1} &= x_k - \eta\, v_{k+1}, \end{aligned} vk+1xk+1=βvk+∇f(xk),=xk−ηvk+1,
等价写法(更直观):
xk+1=xk−η ∇f(xk)+β (xk−xk−1). x_{k+1} = x_k - \eta\,\nabla f(x_k) + \beta\,(x_k - x_{k-1}). xk+1=xk−η∇f(xk)+β(xk−xk−1).
- η\etaη:基础步长(学习率),β∈[0,1)\beta\in[0,1)β∈[0,1):惯性系数(常取 0.8--0.99)。
- 物理类比:球在黏性地面上滚,β\betaβ 越大,阻尼越小 ,更容易跨过浅沟 、减小之字形。
二次问题的参数经验 (已知 μ\muμ 与 LLL)
对 μ\muμ-强凸、LLL-光滑二次函数,常用
η=4(L+μ)2,β=(L−μL+μ) 2, \eta=\frac{4}{(\sqrt{L}+\sqrt{\mu})^2},\qquad \beta=\left(\frac{\sqrt{L}-\sqrt{\mu}}{\sqrt{L}+\sqrt{\mu}}\right)^{\!2}, η=(L +μ )24,β=(L +μ L −μ )2,
可获得较优的收敛速度(仅作调参参考 ,真实任务未知 L,μL,\muL,μ 时按经验网格寻优)。
3.2 Nesterov 动量(NAG,前瞻梯度)
与 Heavy-Ball 近似,但把梯度在前瞻点计算:
yk=xk+β (xk−xk−1),xk+1=yk−η ∇f(yk). \begin{aligned} y_k &= x_k + \beta\,(x_k - x_{k-1}),\\ x_{k+1} &= y_k - \eta\,\nabla f(y_k). \end{aligned} ykxk+1=xk+β(xk−xk−1),=yk−η∇f(yk).
在凸光滑 问题上有更佳的理论上界(O(1/k2)O(1/k^2)O(1/k2))。深度学习里两者都常见。
初始化 x,v
计算梯度
更新速度 v := β v + ∇f
更新参数 x := x - η v
说明 :动量循环 = 梯度 → 速度 → 参数;Nesterov 只是在更新前先做一步"前瞻"。
4. 谁更能救"之字形"?------最速 vs 动量
- 最速下降(预条件) :从几何 上把细长峡谷"拉圆",让梯度方向更对路;
- 动量 :从时间 上把多步方向平均平滑,压抑左右摇摆。
- 实务里可叠加:先做简单预条件(如对角缩放、标准化),再上动量(或自适应方法)。
5. 与机器学习的连接(从凸到大模型)
-
凸模型(逻辑回归、Lasso):
- 预条件(特征标准化、近端分解) + 动量(或 Nesterov)→ 训练更稳更快。
-
非凸深度网络:
- **SGD + 动量(0.9)**是经典配置(尤其在 CNN);
- LLM 等更常用 AdamW (下节自适应优化),但动量思想仍是核心(一阶动量)。
6. 实战参数与调度小抄
-
动量 β\betaβ :0.9 是通用起点;出现过冲震荡 → 降 β\betaβ 或降 η\etaη。
-
学习率 η\etaη :配合热身 + 退火 (Step / 余弦);大批量用线性缩放再微调。
-
预条件:
- 最简:特征标准化、对角缩放(把梯度按尺度"拉齐");
- 进阶:L-BFGS (小内存二阶信息)、分块对角(卷积通道/层级别)。
-
线搜索 :最速下降配 Armijo 回溯常有效;深度网络通常不用线搜索,靠训练曲线调 η\etaη/β\betaβ。
7. 常见坑与排错
- 震荡不收敛 :η\etaη 大或 β\betaβ 大。→ 同时稍降二者;或只降 η\etaη。
- 进展很慢(之字形严重):未做缩放/归一化。→ 标准化输入、对角预条件、分层学习率。
- 极坐标"打圈" :Heavy-Ball 在强非凸区可出现周期轨道。→ 减 β\betaβ、引入衰减或换 Nesterov。
- 线搜索代价太大 :每步评估多次 fff。→ 只在初期用,后期固定步长/调度。
- 梯度爆炸 :RNN/Transformer。→ 梯度裁剪 + 合理初始化 + 归一化层。
8. 迷你代码(NumPy)
最速下降(带回溯) vs 动量(Heavy-Ball),以二次型为例:
python
import numpy as np
def backtracking(f, grad, x, d, alpha0=1.0, c=1e-4, tau=0.5):
alpha = alpha0
fx = f(x); g = grad(x)
while f(x + alpha*d) > fx + c*alpha*np.dot(g, d):
alpha *= tau
return alpha
def steepest_descent(f, grad, x0, M=None, iters=200):
x = x0.copy()
n = len(x)
if M is None:
Minv = lambda v: v
else:
# 只示意:假设给出对称正定 M 的解算器
Minv = lambda v: np.linalg.solve(M, v)
for _ in range(iters):
g = grad(x)
d = - Minv(g)
a = backtracking(f, grad, x, d)
x = x + a*d
return x
def momentum_hb(f, grad, x0, eta=1e-2, beta=0.9, iters=200):
x = x0.copy()
v = np.zeros_like(x)
for _ in range(iters):
g = grad(x)
v = beta*v + g
x = x - eta*v
return x
观察:条件数大的二次型上,最速下降(带预条件)和动量相较普通 GD 收敛显著加快。
9. 两种方法的"工作机理"
按欧氏范数
按马氏范数
普通梯度
方向: 负梯度
方向: 预条件后取负
线搜索步长
更新参数
说明:左支是"换度量"(最速下降);右支是"原始欧氏"(普通 GD)。
当前参数
计算梯度
更新速度: v := β v + 梯度
更新参数: x := x - η v
说明 :动量把"速度"当作历史梯度的指数加权平均,让更新更平滑。
10. 练习(含提示)
- 推导最速方向 :在 ∥d∥M≤1\|d\|_M\le 1∥d∥M≤1 下最小化 ∇f⊤d\nabla f^\top d∇f⊤d,用拉格朗日法证明 d⋆∥−M−1∇fd^\star \parallel -M^{-1}\nabla fd⋆∥−M−1∇f。
- 二次型线搜索 :对 f(x)=12x⊤Qx−b⊤xf(x)=\tfrac12 x^\top Qx-b^\top xf(x)=21x⊤Qx−b⊤x,推导欧氏最速下降的 KaTeX parse error: Undefined control sequence: \* at position 8: \alpha^\̲*̲。
- 预条件的收益 :随机生成条件数不同的 QQQ,比较无预条件 vs 对角预条件收敛步数。
- η,β\eta,\betaη,β 调参 :在同一任务上网格搜索 η∈{1e − 3,3e − 3,1e − 2}\eta\in\{1e\!-\!3, 3e\!-\!3, 1e\!-\!2\}η∈{1e−3,3e−3,1e−2}、β∈{0.8,0.9,0.95}\beta\in\{0.8,0.9,0.95\}β∈{0.8,0.9,0.95},画收敛曲线。
- Nesterov 对比:实现 NAG,比较 Heavy-Ball 在凸与非凸玩具问题上的表现差异。
- 叠加策略:在逻辑回归上做"标准化 + 动量",与"无标准化 + 动量"对比收敛速度。
11. 小结(带走三句话)
- 最速下降 = 预条件 + 线搜索:换个"步长尺子",方向就对了。
- 动量 = 方向平滑 + 抗噪:把历史信息装进"速度",少拐弯、快下山。
- 实战 :先做缩放/预条件,再上动量 (或自适应),配合合适的学习率调度 与梯度裁剪,稳且快。