3、局部微调算法基础:梯度下降法、牛顿法、拟牛顿法的原理与对比
聊到局部微调,绕不开的就是那几样最基础的优化算法。说实话,我刚开始做 NLP 模型微调的时候,总觉得这些算法是数学课本里的东西,跟实际工程离得远。后来被几个 loss 不收敛的 bug 折磨过之后,才老老实实回头补课。
今天我们就掰开揉碎,把梯度下降、牛顿法、拟牛顿法这三兄弟讲清楚。你想想看,它们本质上都是在干同一件事——找一个能让损失函数最小的参数点。但怎么找,每一步往哪走、走多大,差别就大了。
3.1 梯度下降法:最朴素的“下山”策略
梯度下降法,说白了就是沿着最陡的方向往下滑。你站在一座山上,闭着眼睛,用脚探一探哪个方向最陡,就往那个方向迈一步。这就是梯度下降的直觉。
数学上,我们计算损失函数 L(θ) 对参数 θ 的梯度 ∇L(θ),然后沿着梯度的反方向更新参数:
θ_{t+1} = θ_t - η · ∇L(θ_t)
这里的 η 是学习率,也就是步长。我见过太多新手把学习率设得太大,结果 loss 直接飞了;设得太小,又半天不收敛。嗯,这里要注意,学习率是梯度下降法里最敏感的超参数。
3.1.1 三种变体
实际工程里,我们很少用最原始的梯度下降。根据每次更新用的数据量,分成三种:
| 变体 | 每次用多少数据 | 更新频率 | 收敛稳定性 |
|---|---|---|---|
| 批量梯度下降 (BGD) | 全部训练数据 | 慢(每 epoch 一次) | 稳定,但容易陷入局部最优 |
| 随机梯度下降 (SGD) | 1 个样本 | 快(每样本一次) | 震荡大,但有机会跳出局部最优 |
| 小批量梯度下降 (MBGD) | 一个小批量(如 32/64) | 适中 | 折中方案,工程中最常用 |
我个人习惯用 Mini-batch SGD,batch size 设在 32 或 64。为什么?因为 GPU 的并行计算能力能充分利用起来,而且每个 batch 的梯度噪声刚好起到一点正则化作用。
3.2 牛顿法:用二阶信息“抄近路”
梯度下降法只用了一阶导数信息,也就是梯度。它只知道哪个方向是下坡,但不知道这个坡的曲率——也就是坡是越来越陡还是越来越缓。
牛顿法就不一样了。它不光看梯度,还看海森矩阵(Hessian Matrix),也就是二阶导数。这相当于你不仅知道哪边是下坡,还知道这个坡的弯曲程度,从而能一步跨到谷底附近。
更新公式长这样:
θ_{t+1} = θ_t - [H(θ_t)]⁻¹ · ∇L(θ_t)
其中 H(θ_t) 是海森矩阵,[H(θ_t)]⁻¹ 是它的逆矩阵。
你想想看,梯度下降法是一阶的,牛顿法是二阶的。按理说二阶方法应该更厉害才对。但为什么实际工程里,大家还是用梯度下降居多?
原因很简单——海森矩阵太大了。假设你的模型有 1 亿个参数(这在今天的大模型里算小的),海森矩阵就是 1 亿 × 1 亿的矩阵,光存储就需要 4 × 10¹⁶ 字节,也就是 40 PB。这谁扛得住?
3.3 拟牛顿法:折中的智慧
既然直接算海森矩阵不现实,那能不能近似它?这就是拟牛顿法的思路。
拟牛顿法不直接计算海森矩阵,而是通过每次迭代的梯度变化,逐步构建一个海森矩阵的近似。最常用的两种是:
- DFP 算法:由 Davidon、Fletcher、Powell 提出,直接近似海森矩阵的逆。
- BFGS 算法:由 Broyden、Fletcher、Goldfarb、Shanno 提出,目前最流行的拟牛顿法。
- L-BFGS:Limited-memory BFGS,只保存最近几次迭代的信息,内存开销小,适合大规模问题。
BFGS 的更新公式看起来有点复杂,但核心思想很简单:用一阶梯度信息去逼近二阶曲率信息。
# 伪代码示意:BFGS 更新步骤
1. 计算当前梯度 g_t
2. 计算方向 d_t = -H_t · g_t (H_t 是海森逆的近似)
3. 线搜索确定步长 α_t
4. 更新参数 θ_{t+1} = θ_t + α_t · d_t
5. 计算新梯度 g_{t+1}
6. 根据梯度变化更新 H_{t+1}
我在做 CRF 序列标注模型的训练时,就常用 L-BFGS。因为 CRF 的损失函数是凸的,L-BFGS 收敛得又快又稳,比 SGD 省心多了。
3.4 三种方法的对比
我把它们放在一起对比,这样更直观:
| 维度 | 梯度下降法 | 牛顿法 | 拟牛顿法 (BFGS/L-BFGS) |
|---|---|---|---|
| 导数阶数 | 一阶 | 二阶 | 近似二阶 |
| 收敛速度 | 线性收敛 | 二次收敛 | 超线性收敛 |
| 每次迭代计算量 | O(n) | O(n³) | O(n²) 或 O(n) |
| 内存开销 | O(n) | O(n²) | O(n²) 或 O(m·n) |
| 适用场景 | 大规模深度学习 | 小规模、凸优化 | 中等规模、凸优化 |
| 对超参数敏感度 | 高(学习率) | 低 | 低 |
注意看那个 O(n³),这就是牛顿法在大模型上“死”的原因。n 是参数数量,三次方的复杂度,参数一多直接爆炸。
3.5 知识结构图
下面这张图把三种方法的关系和适用场景梳理清楚了:
3.6 实际工程中的选型建议
说了这么多理论,最后给点实在的。你在实际项目中到底该用哪个?
- 大模型微调(BERT/GPT 等):用 AdamW 或 SGD with Momentum。别碰牛顿法,也别碰 BFGS,参数太多了,内存扛不住。
- 传统机器学习模型(CRF/SVM 等):用 L-BFGS。收敛快,不用调学习率,省心。
- 小规模凸优化问题:可以考虑牛顿法,但要做好海森矩阵正则化,防止奇异。
- 非凸问题:梯度下降法配合动量或 Adam 是主流。拟牛顿法在非凸问题上效果一般。
好了,局部微调的基础算法就聊到这儿。梯度下降法、牛顿法、拟牛顿法,这三兄弟各有各的脾气。理解它们的本质区别,你就能在项目中做出更聪明的选择。