非线性最小二乘:牛顿法、高斯—牛顿与 LM
1. 问题形式
非线性最小二乘问题写作:
\[ \min_x F(x),\qquad F(x)=\frac12\|r(x)\|^2 =\frac12\sum_{i=1}^m r_i(x)^2, \]
其中 \(x\in\mathbb R^n\) 是待估参数,\(r(x)\in\mathbb R^m\) 是残差向量。与线性最小二乘不同,\(r(x)\) 对 \(x\) 是非线性的,不能一次整理成固定的 \(Ax=b\) 后直接求解。
例如,用
\[ y=ae^{bt} \]
拟合数据 \((t_i,y_i)\)。令 \(x=[a,b]^T\),第 \(i\) 个残差为
\[ r_i(a,b)=ae^{bt_i}-y_i, \]
目标就是最小化这些残差的平方和。
2. 从牛顿法开始
对一般优化问题
\[ \min_x f(x), \]
在当前点 \(x_k\) 附近,用二阶泰勒展开建立局部模型:
\[ m(\Delta x) =f(x_k)+\nabla f(x_k)^T\Delta x +\frac12\Delta x^T H(x_k)\Delta x, \]
其中 \(H=\nabla^2f\) 是 Hessian。此时 \(x_k\) 已固定,未知量是“下一步往哪里走、走多远”的位移 \(\Delta x\)。
对 \(\Delta x\) 求梯度并令其为零:
\[ \nabla_{\Delta x}m =\nabla f+H\Delta x=0, \]
得到牛顿方程
\[ H\Delta x=-\nabla f, \]
再更新
\[ x_{k+1}=x_k+\Delta x. \]
实践中应解线性方程 \(H\Delta x=-\nabla f\),而不是显式计算 \(H^{-1}\)。
为什么一阶展开不够
一阶模型
\[ f(x+\Delta x)\approx f(x)+\nabla f(x)^T\Delta x \]
是一个平面,只能给出下降方向,不能独立确定有限步长。例如 \(f(x)=x^2\) 在 \(x=10\) 处的一阶模型为
\[ 100+20\Delta x. \]
若直接最小化这个线性模型,会得到 \(\Delta x\to-\infty\)。因此梯度下降需要另选学习率,而牛顿法用 Hessian 描述局部曲率,从二次模型中同时得到方向和步长。
3. 高斯—牛顿推导
高斯—牛顿专门利用最小二乘的平方结构。它不对目标函数 \(F\) 做二阶展开,而只对残差做一阶展开:
\[ r(x_k+\Delta x) \approx r(x_k)+J(x_k)\Delta x, \]
其中
\[ J=\frac{\partial r}{\partial x} \]
是残差关于参数的 Jacobian。简记当前的 \(r(x_k)\) 和 \(J(x_k)\) 为 \(r\)、\(J\),局部问题变为
\[ \min_{\Delta x}\frac12\|r+J\Delta x\|^2. \]
虽然残差只做了一阶展开,但代入平方损失后会自然产生二次项:
\[ \frac12(r+J\Delta x)^T(r+J\Delta x) =\frac12r^Tr +\Delta x^TJ^Tr +\frac12\Delta x^TJ^TJ\Delta x. \]
对 \(\Delta x\) 求梯度并令其为零:
\[ J^T(r+J\Delta x)=0, \]
因此高斯—牛顿方程为
\[ \boxed{J^TJ\Delta x=-J^Tr}. \]
求得增量后更新:
\[ \boxed{x_{k+1}=x_k+\Delta x}. \]
每轮重新计算 \(r\) 和 \(J\),直到步长、梯度或目标函数变化足够小。
整个过程可以概括为:
\[ x_k \longrightarrow (r,J) \longrightarrow \min_{\Delta x}\|r+J\Delta x\|^2 \longrightarrow \Delta x \longrightarrow x_{k+1}. \]
本质上,每次迭代都把一个非线性问题局部变成线性最小二乘问题。
4. 高斯—牛顿与牛顿法的关系
对
\[ F(x)=\frac12r(x)^Tr(x), \]
其梯度为
\[ \boxed{\nabla F=J^Tr}, \]
精确 Hessian 为
\[ \boxed{ \nabla^2F =J^TJ+\sum_{i=1}^m r_i\nabla^2r_i }. \]
将其代入牛顿方程,本应得到
\[ \left(J^TJ+\sum_i r_i\nabla^2r_i\right)\Delta x=-J^Tr. \]
高斯—牛顿忽略残差的二阶导数项,使用近似
\[ \boxed{\nabla^2F\approx J^TJ}, \]
于是得到
\[ J^TJ\Delta x=-J^Tr. \]
因此二者不是同一种方法,但关系很近:
\[ \boxed{ \text{高斯—牛顿} =\text{针对非线性最小二乘的近似牛顿法} }. \]
当解附近的残差较小,即 \(r_i\approx0\) 时,被忽略的
\[ \sum_i r_i\nabla^2r_i \]
通常也较小,因此 \(J^TJ\) 对真实 Hessian 的近似较好。即使残差不小,只要各 \(r_i\) 的非线性较弱,这个近似也可能有效。
5. 示例:指数曲线拟合
模型与残差为
\[ y=ae^{bt},\qquad r_i(a,b)=ae^{bt_i}-y_i. \]
两个偏导数是
\[ \frac{\partial r_i}{\partial a}=e^{bt_i}, \qquad \frac{\partial r_i}{\partial b}=at_i e^{bt_i}, \]
所以
\[ J= \begin{bmatrix} e^{bt_1} & at_1e^{bt_1}\\ e^{bt_2} & at_2e^{bt_2}\\ \vdots & \vdots\\ e^{bt_m} & at_me^{bt_m} \end{bmatrix}. \]
在当前参数 \((a,b)\) 处计算 \(r\) 和 \(J\),求解
\[ J^TJ \begin{bmatrix} \Delta a\\ \Delta b \end{bmatrix} =-J^Tr, \]
然后更新
\[ a\leftarrow a+\Delta a, \qquad b\leftarrow b+\Delta b. \]
一个用于理解算法的 NumPy 实现如下:
import numpy as np
t = np.array([0.0, 1.0, 2.0, 3.0])
y = np.array([2.0, 3.1, 5.5, 8.8])
x = np.array([1.0, 0.5]) # [a, b]
for _ in range(20):
a, b = x
r = a * np.exp(b * t) - y
J = np.column_stack([
np.exp(b * t),
a * t * np.exp(b * t),
])
# 直接解 J @ dx ≈ -r,避免构造逆矩阵。
dx = np.linalg.lstsq(J, -r, rcond=None)[0]
x += dx
if np.linalg.norm(dx) < 1e-8:
break数值计算时,通常不应显式使用
np.linalg.inv(J.T @ J) @ (-J.T @ r)因为构造 \(J^TJ\) 会放大条件数,而显式求逆也没有必要。直接用 QR 或 SVD 解 \(J\Delta x\approx-r\) 更稳定。
6. LM:给高斯—牛顿加入阻尼
Levenberg—Marquardt(LM)的典型形式为
\[ \boxed{(J^TJ+\lambda I)\Delta x=-J^Tr}, \]
其中 \(\lambda I\) 是阻尼项。
当 \(\lambda\) 很小时,LM 接近高斯—牛顿;当 \(\lambda\) 很大时,
\[ \Delta x\approx-\frac1\lambda J^Tr, \]
而 \(J^Tr\) 正是目标函数的梯度,所以此时更接近小步长梯度下降。
LM 的核心作用是:局部模型不可靠或 \(J^TJ\) 病态时走得更保守;局部模型可靠时逐渐采用快速的高斯—牛顿步。实际算法会根据试探步带来的真实下降与模型预测下降是否一致,动态调整阻尼,而不是固定使用一个 \(\lambda\)。
7. 初始值与收敛
高斯—牛顿及 LM 都是局部优化方法。它们依赖
\[ r(x+\Delta x)\approx r(x)+J(x)\Delta x \]
在当前点附近足够准确。因此:
- 初值较好时,通常能快速精修参数;
- 初值较差时,可能走向错误的局部极小值、震荡或发散;
- 非线性越强,对初值往往越敏感;
- LM 和信赖域方法能扩大可收敛区域,但不能消除初值问题。
常见工程流程是:
\[ \boxed{ \text{粗初始化或全局搜索} \longrightarrow \text{高斯—牛顿、LM 或信赖域方法精修} }. \]
8. 值得保留的问题与答案
Q1:只对残差做一阶展开,为什么能确定步长?
因为残差被放进平方损失后,一阶模型 \(r+J\Delta x\) 的平方会产生 \(\Delta x^TJ^TJ\Delta x\),自然形成一个关于 \(\Delta x\) 的二次模型。高斯—牛顿正是利用了这个特殊结构。
Q2:“对 \(\Delta x\) 求导”是什么意思?
当前点 \(x_k\) 已经固定,\(f(x_k)\)、梯度、Hessian、\(r(x_k)\) 和 \(J(x_k)\) 都视为常量。把下一步位移 \(\Delta x\) 当成局部模型中的未知变量,对它求梯度并令梯度为零,就是在寻找令局部模型最小的那一步。
Q3:LM 为什么通常比裸高斯—牛顿稳?
阻尼项 \(\lambda I\) 能改善线性系统的可解性,并限制不可靠的大步。LM 会根据局部模型的预测效果调节 \(\lambda\),在较稳的梯度型步伐和较快的高斯—牛顿步之间过渡。
Q4:实际计算该使用什么 API 和算法?
通用非线性最小二乘可使用
scipy.optimize.least_squares。只需提供残差函数,也可以额外提供
Jacobian:
import numpy as np
from scipy.optimize import least_squares
t = np.array([0.0, 1.0, 2.0, 3.0])
y = np.array([2.0, 3.1, 5.5, 8.8])
def residual(x):
a, b = x
return a * np.exp(b * t) - y
def jac(x):
a, b = x
return np.column_stack([
np.exp(b * t),
a * t * np.exp(b * t),
])
result = least_squares(
residual,
x0=[1.0, 0.5],
jac=jac,
method="trf",
)普通曲线拟合还可使用更高层的
scipy.optimize.curve_fit。NumPy
提供线性代数工具,但不提供完整的通用非线性最小二乘优化器;scikit-learn
的重点则是现成的机器学习估计器,而不是任意残差函数的非线性最小二乘。
least_squares 提供三种主要算法:
| 方法 | 核心思路 | 常见选择场景 |
|---|---|---|
trf |
Trust Region Reflective | 默认选择;支持参数边界;较通用,也适合较大问题 |
dogbox |
矩形信赖域中的 dogleg 步 | 小型且带边界的问题;Jacobian 秩亏时通常不优先 |
lm |
Levenberg—Marquardt | 无边界、小中型问题,且初值较好时常很快 |
信赖域方法的共同思想是:只在当前点附近的有限区域内信任局部模型。若一步的实际效果符合预测,就扩大信赖域;若效果较差,就缩小信赖域。
一个够用的选择原则是:有边界或没有明确偏好时用
trf;无边界、小中型且初值较好时可试
lm;dogbox 可作为小型带边界问题的备选。
Q5:好初值是不是必要条件?
严格说不是每次都“必须”,但它显著影响能否收敛以及收敛到哪个解。高斯—牛顿尤其适合“已经大致知道答案在哪里,再把参数估准”,不适合单独承担全局搜索。
9. 核心记忆
\[ \boxed{ \text{非线性残差} \xrightarrow{\text{一阶线性化}} r+J\Delta x \xrightarrow{\text{平方损失}} \text{二次局部模型} \xrightarrow{\text{最小化}} J^TJ\Delta x=-J^Tr } \]
牛顿法直接用二阶模型;高斯—牛顿借助最小二乘结构,用 \(J^TJ\) 近似 Hessian;LM 再通过阻尼控制高斯—牛顿步的激进程度。