数值优化 | 详解拟牛顿法之SR1、DFP、BFGS、L-BFGS(附案例分析与Python实现)
0 专栏介绍
🔥课设、毕设、创新竞赛必备!🔥本专栏涉及更高阶的运动规划算法轨迹优化实战,包括:曲线生成、碰撞检测、安全走廊、优化建模(QP、SQP、NMPC、iLQR等)、轨迹优化(梯度法、曲线法等),每个算法都包含代码实现加深理解
🚀详情:运动规划实战进阶:轨迹优化篇
1 拟牛顿法框架
在数值优化 | 图解牛顿法、阻尼牛顿法与高斯牛顿法(附案例分析与Python实现)中我们介绍了经典牛顿法的迭代公式
x k + 1 = x k − H − 1 ( x k ) ∇ F ( x k ) \boldsymbol{x}_{k+1}=\boldsymbol{x}_k-\boldsymbol{H}^{-1}\left( \boldsymbol{x}_k \right) \nabla F\left( \boldsymbol{x}_k \right) xk+1=xk−H−1(xk)∇F(xk)
可以看到,经典牛顿法需要对目标函数求Hessian矩阵的逆矩阵,矩阵求逆的时间复杂度是 O ( n 3 ) O(n^3) O(n3),其中 n n n为矩阵维度,因此牛顿法计算复杂度高、数值稳定性较差。同时,无法保证对于任意 f ( x ) f\left( \boldsymbol{x} \right) f(x)的Hessian矩阵可逆且正定。
为了克服牛顿法的缺陷,引入拟牛顿法(quasi-Newton method):根据迭代点处的梯度信息求 H ( x ) \boldsymbol{H}\left( \boldsymbol{x} \right) H(x)的近似值 B k ( x ) \boldsymbol{B}_k\left( \boldsymbol{x} \right) Bk(x)或 H − 1 ( x ) \boldsymbol{H}^{-1}\left( \boldsymbol{x} \right) H−1(x)的近似值 H k ( x ) \boldsymbol{H}_k\left( \boldsymbol{x} \right) Hk(x)来降低计算量,算法流程如图所示。根据近似矩阵更新算法的不同,拟牛顿法有若干子算法
2 SR1算法推导
秩一公式(Symmetric Rank-One, SR1)是结构最简单的拟牛顿矩阵更新算法,考虑
H k + 1 = H k + Δ H k \boldsymbol{H}_{k+1}=\boldsymbol{H}_k+\varDelta \boldsymbol{H}_k Hk+1=Hk+ΔHk
期望 H k + 1 ≈ H ( x k + 1 ) \boldsymbol{H}_{k+1}\approx \boldsymbol{H}\left( \boldsymbol{x}_{k+1} \right) Hk+1≈H(xk+1)、 H k ≈ H ( x k ) \boldsymbol{H}_k\approx \boldsymbol{H}\left( \boldsymbol{x}_k \right) Hk≈H(xk),所以 Δ H k ≈ H ( x k + 1 ) − H ( x k ) \varDelta \boldsymbol{H}_k\approx \boldsymbol{H}\left( \boldsymbol{x}_{k+1} \right) -\boldsymbol{H}\left( \boldsymbol{x}_k \right) ΔHk≈H(xk+1)−H(xk)。由于Hessian矩阵对称,所以 Δ H k \varDelta \boldsymbol{H}_k ΔHk也应对称,不妨令 Δ H k = β u u T \varDelta \boldsymbol{H}_k=\beta \boldsymbol{uu}^T ΔHk=βuuT;接着,对 ∇ F ( x ) \nabla F\left( \boldsymbol{x} \right) ∇F(x)在 x k + 1 \boldsymbol{x}_{k+1} xk+1处一阶泰勒展开可得
∇ F ( x ) = ∇ F ( x k + 1 ) + H ( x k + 1 ) ( x − x k + 1 ) \nabla F\left( \boldsymbol{x} \right) =\nabla F\left( \boldsymbol{x}_{k+1} \right) +\boldsymbol{H}\left( \boldsymbol{x}_{k+1} \right) \left( \boldsymbol{x}-\boldsymbol{x}_{k+1} \right) ∇F(x)=∇F(xk+1)+H(xk+1)(x−xk+1)
记 s k = x k + 1 − x k \boldsymbol{s}_k=\boldsymbol{x}_{k+1}-\boldsymbol{x}_k sk=xk+1−xk, y k = ∇ F ( x k + 1 ) − ∇ F ( x k ) \boldsymbol{y}_k=\nabla F\left( \boldsymbol{x}_{k+1} \right) -\nabla F\left( \boldsymbol{x}_k \right) yk=∇F(xk+1)−∇F(xk),则
y k = B k + 1 s k ⇒ H k + 1 y k = s k \boldsymbol{y}_k=\boldsymbol{B}_{k+1}\boldsymbol{s}_k\Rightarrow \boldsymbol{H}_{k+1}\boldsymbol{y}_k=\boldsymbol{s}_k yk=Bk+1sk⇒Hk+1yk=sk
注意到 s k T B k + 1 s k = s k T y k \boldsymbol{s}_{k}^{T}\boldsymbol{B}_{k+1}\boldsymbol{s}_k=\boldsymbol{s}_{k}^{T}\boldsymbol{y}_k skTBk+1sk=skTyk,为了使 H k \boldsymbol{H}_k Hk或 B k \boldsymbol{B}_k Bk正定,需要在迭代过程中保证 s k T y k > 0 \boldsymbol{s}_{k}^{T}\boldsymbol{y}_k>0 skTyk>0。基于上式,在 Δ H k = β u u T \varDelta \boldsymbol{H}_k=\beta \boldsymbol{uu}^T ΔHk=βuuT两边同时右乘 y k \boldsymbol{y}_k yk
u = γ ( s k − H k y k ) \boldsymbol{u}=\gamma \left( \boldsymbol{s}_k-\boldsymbol{H}_k\boldsymbol{y}_k \right) u=γ(sk−Hkyk)
其中
γ = 1 β u T y k \gamma =\frac{1}{\beta \boldsymbol{u}^T\boldsymbol{y}_k} γ=βuTyk1
将 u = γ ( s k − H k y k ) \boldsymbol{u}=\gamma \left( \boldsymbol{s}_k-\boldsymbol{H}_k\boldsymbol{y}_k \right) u=γ(sk−Hkyk)反代回 H k + 1 y k = H k y k + β u u T y k \boldsymbol{H}_{k+1}\boldsymbol{y}_k=\boldsymbol{H}_k\boldsymbol{y}_k+\beta \boldsymbol{uu}^T\boldsymbol{y}_k Hk+1yk=Hkyk+βuuTyk可得
s k − H k y k = β γ 2 ( s k − H k y k ) T y k ( s k − H k y k ) \boldsymbol{s}_k-\boldsymbol{H}_k\boldsymbol{y}_k=\beta \gamma ^2\left( \boldsymbol{s}_k-\boldsymbol{H}_k\boldsymbol{y}_k \right) ^T\boldsymbol{y}_k\left( \boldsymbol{s}_k-\boldsymbol{H}_k\boldsymbol{y}_k \right) sk−Hkyk=βγ2(sk−Hkyk)Tyk(sk−Hkyk)
显见 β γ 2 = 1 / ( s k − H k y k ) T y k \beta \gamma ^2={{1}/{\left( \boldsymbol{s}_k-\boldsymbol{H}_k\boldsymbol{y}_k \right) ^T\boldsymbol{y}_k}} βγ2=1/(sk−Hkyk)Tyk,从而得到SR1的更新公式
H k + 1 = H k + ( s k − H k y k ) ( s k − H k y k ) T ( s k − H k y k ) T y k \boldsymbol{H}_{k+1}=\boldsymbol{H}_k+\frac{\left( \boldsymbol{s}_k-\boldsymbol{H}_k\boldsymbol{y}_k \right) \left( \boldsymbol{s}_k-\boldsymbol{H}_k\boldsymbol{y}_k \right) ^T}{\left( \boldsymbol{s}_k-\boldsymbol{H}_k\boldsymbol{y}_k \right) ^T\boldsymbol{y}_k} Hk+1=Hk+(sk−Hkyk)Tyk(sk−Hkyk)(sk−Hkyk)T
代码实现为
gx = g_func(x)
d = (H @ gx).squeeze()
alpha = self.line_searcher_.search(func, g_func, x, -d)
x_next = x - alpha * d
s = x_next - x
y = g_func(x_next) - gx
item = s - H @ y
H = H + item @ item.T / (item.T @ y)
3 DFP算法推导
DFP算法是SR1算法的拓展版本,引入了更大的自由度
H k + 1 = H k + β u u T + γ v v T \boldsymbol{H}_{k+1}=\boldsymbol{H}_k+\beta \boldsymbol{uu}^T+\gamma \boldsymbol{vv}^T Hk+1=Hk+βuuT+γvvT
与SR1算法推导类似,方程两边同时右乘 y k \boldsymbol{y}_k yk得到
s k = H k + 1 y k = H k y k + β u u T y k + γ v v T y k \boldsymbol{s}_k=\boldsymbol{H}_{k+1}\boldsymbol{y}_k=\boldsymbol{H}_k\boldsymbol{y}_k+\beta \boldsymbol{uu}^T\boldsymbol{y}_k+\gamma \boldsymbol{vv}^T\boldsymbol{y}_k sk=Hk+1yk=Hkyk+βuuTyk+γvvTyk
令 u = s k \boldsymbol{u}=\boldsymbol{s}_k u=sk、 v = H k y k \boldsymbol{v}=\boldsymbol{H}_k\boldsymbol{y}_k v=Hkyk,则 s k − H k y k = β s k s k T y k + γ H k y k y k T H k T y k \boldsymbol{s}_k-\boldsymbol{H}_k\boldsymbol{y}_k=\beta \boldsymbol{s}_k\boldsymbol{s}_{k}^{T}\boldsymbol{y}_k+\gamma \boldsymbol{H}_k\boldsymbol{y}_k\boldsymbol{y}_{k}^{T}\boldsymbol{H}_{k}^{T}\boldsymbol{y}_k sk−Hkyk=βskskTyk+γHkykykTHkTyk,从而
{ β = 1 s k T y k γ = − 1 y k T H k T y k \begin{cases} \beta =\frac{1}{\boldsymbol{s}_{k}^{T}\boldsymbol{y}_k}\\ \gamma =-\frac{1}{\boldsymbol{y}_{k}^{T}\boldsymbol{H}_{k}^{T}\boldsymbol{y}_k}\\\end{cases} {β=skTyk1γ=−ykTHkTyk1
得到DFP的更新公式
H k + 1 = H k + s k s k T s k T y k − H k y k y k T H k T y k T H k T y k \boldsymbol{H}_{k+1}=\boldsymbol{H}_k+\frac{\boldsymbol{s}_k\boldsymbol{s}_{k}^{T}}{\boldsymbol{s}_{k}^{T}\boldsymbol{y}_k}-\frac{\boldsymbol{H}_k\boldsymbol{y}_k\boldsymbol{y}_{k}^{T}\boldsymbol{H}_{k}^{T}}{\boldsymbol{y}_{k}^{T}\boldsymbol{H}_{k}^{T}\boldsymbol{y}_k} Hk+1=Hk+skTykskskT−ykTHkTykHkykykTHkT
代码实现为
gx = g_func(x)
d = (H @ gx).squeeze()
alpha = self.line_searcher_.search(func, g_func, x, -d)
x_next = x - alpha * d
s = x_next - x
y = g_func(x_next) - gx
sTy = float(s.T @ y)
H = H + s @ s.T / sTy - H @ y @ y.T @ H.T / float(y.T @ H.T @ y)
4 BFGS算法推导
BFGS算法是DFP的对偶版本,假设
B k + 1 = B k + β u u T + γ v v T \boldsymbol{B}_{k+1}=\boldsymbol{B}_k+\beta \boldsymbol{uu}^T+\gamma \boldsymbol{vv}^T Bk+1=Bk+βuuT+γvvT
类比DFP推导过程可得到
B k + 1 = B k + y k y k T y k T s k − B k s k s k T B k T s k T B k T s k \boldsymbol{B}_{k+1}=\boldsymbol{B}_k+\frac{\boldsymbol{y}_k\boldsymbol{y}_{k}^{T}}{\boldsymbol{y}_{k}^{T}\boldsymbol{s}_k}-\frac{\boldsymbol{B}_k\boldsymbol{s}_k\boldsymbol{s}_{k}^{T}\boldsymbol{B}_{k}^{T}}{\boldsymbol{s}_{k}^{T}\boldsymbol{B}_{k}^{T}\boldsymbol{s}_k} Bk+1=Bk+ykTskykykT−skTBkTskBkskskTBkT
为了进一步计算 H k = B k − 1 \boldsymbol{H}_k=\boldsymbol{B}_{k}^{-1} Hk=Bk−1,应用下面的引理
Shermann-Morrison-Woodbury公式 设 A \boldsymbol{A} A是 n × n n\times n n×n可逆矩阵,向量 u \boldsymbol{u} u、 v ∈ R n \boldsymbol{v}\in \mathbb{R} ^n v∈Rn ,则 A + u v T \boldsymbol{A}+\boldsymbol{uv}^T A+uvT可逆当且仅当 1 + v T A − 1 u ≠ 0 1+\boldsymbol{v}^T\boldsymbol{A}^{-1}\boldsymbol{u}\ne 0 1+vTA−1u=0,且
( A + u v T ) − 1 = A − 1 − A − 1 u v T A − 1 1 + v T A − 1 u \left( \boldsymbol{A}+\boldsymbol{uv}^T \right) ^{-1}=\boldsymbol{A}^{-1}-\frac{\boldsymbol{A}^{-1}\boldsymbol{uv}^T\boldsymbol{A}^{-1}}{1+\boldsymbol{v}^T\boldsymbol{A}^{-1}\boldsymbol{u}} (A+uvT)−1=A−1−1+vTA−1uA−1uvTA−1
从而得到BFGS更新公式
H k + 1 = ( I − s k y k T s k T y k ) H k ( I − y k s k T s k T y k ) + s k s k T s k T y k \boldsymbol{H}_{k+1}=\left( \boldsymbol{I}-\frac{\boldsymbol{s}_k\boldsymbol{y}_{k}^{T}}{\boldsymbol{s}_{k}^{T}\boldsymbol{y}_k} \right) \boldsymbol{H}_k\left( \boldsymbol{I}-\frac{\boldsymbol{y}_k\boldsymbol{s}_{k}^{T}}{\boldsymbol{s}_{k}^{T}\boldsymbol{y}_k} \right) +\frac{\boldsymbol{s}_k\boldsymbol{s}_{k}^{T}}{\boldsymbol{s}_{k}^{T}\boldsymbol{y}_k} Hk+1=(I−skTykskykT)Hk(I−skTykykskT)+skTykskskT
代码实现为
gx = g_func(x)
d = (H @ gx).squeeze()
alpha = self.line_searcher_.search(func, g_func, x, -d)
x_next = x - alpha * d
s = x_next - x
y = g_func(x_next) - gx
sTy = float(s.T @ y)
H = (I - s @ y.T / sTy) @ H @ (I - y @ s.T / sTy) + s @ s.T / sTy
5 L-BFGS算法推导
在BFGS算法中,每次迭代需要上一轮的 H k \boldsymbol{H}_k Hk,而保存 H k \boldsymbol{H}_k Hk至少需要 O ( n 2 ) O(n^2) O(n2)的空间复杂度,这对于大规模数值优化问题而言无法接受。L-BFGS对BFGS的内存占用率进行了限制,记 ρ k = 1 / s k T y k \rho _k={{1}/{\boldsymbol{s}_{k}^{T}\boldsymbol{y}_k}} ρk=1/skTyk、 V k = I − ρ k y k s k T \boldsymbol{V}_k=\boldsymbol{I}-\rho _k\boldsymbol{y}_k\boldsymbol{s}_{k}^{T} Vk=I−ρkykskT,则递推地
H k + 1 = V k T H k V k + ρ k s k s k T = ( V k T ⋯ V 0 T ) H 0 ( V 0 ⋯ V k ) + ( V k T ⋯ V 1 T ) ρ 1 s 1 s 1 T ( V 1 ⋯ V k ) + ⋯ + ρ k s k s k T \begin{aligned}\boldsymbol{H}_{k+1}&=\boldsymbol{V}_{k}^{T}\boldsymbol{H}_k\boldsymbol{V}_k+\rho _k\boldsymbol{s}_k\boldsymbol{s}_{k}^{T}\\&=\left( \boldsymbol{V}_{k}^{T}\cdots \boldsymbol{V}_{0}^{T} \right) \boldsymbol{H}_0\left( \boldsymbol{V}_0\cdots \boldsymbol{V}_k \right) +\left( \boldsymbol{V}_{k}^{T}\cdots \boldsymbol{V}_{1}^{T} \right) \rho _1\boldsymbol{s}_1\boldsymbol{s}_{1}^{T}\left( \boldsymbol{V}_1\cdots \boldsymbol{V}_k \right) +\cdots +\rho _k\boldsymbol{s}_k\boldsymbol{s}_{k}^{T}\end{aligned} Hk+1=VkTHkVk+ρkskskT=(VkT⋯V0T)H0(V0⋯Vk)+(VkT⋯V1T)ρ1s1s1T(V1⋯Vk)+⋯+ρkskskT
仅保留最近 m m m步的结果
H k + 1 = ( V k T ⋯ V k − m + 1 T ) H 0 ( V k − m + 1 ⋯ V k ) + ( V k T ⋯ V k − m + 2 T ) ρ k − m + 1 s k − m + 1 s k − m + 1 T ( V k − m + 2 ⋯ V k ) + ⋯ + ρ k s k s k T \begin{aligned}\boldsymbol{H}_{k+1}&=\left( \boldsymbol{V}_{k}^{T}\cdots \boldsymbol{V}_{k-m+1}^{T} \right) \boldsymbol{H}_0\left( \boldsymbol{V}_{k-m+1}\cdots \boldsymbol{V}_k \right) \\\,\, &+\left( \boldsymbol{V}_{k}^{T}\cdots \boldsymbol{V}_{k-m+2}^{T} \right) \rho _{k-m+1}\boldsymbol{s}_{k-m+1}\boldsymbol{s}_{k-m+1}^{T}\left( \boldsymbol{V}_{k-m+2}\cdots \boldsymbol{V}_k \right) \\\,\, &+\cdots \\\,\, &+\rho _k\boldsymbol{s}_k\boldsymbol{s}_{k}^{T}\end{aligned} Hk+1=(VkT⋯Vk−m+1T)H0(Vk−m+1⋯Vk)+(VkT⋯Vk−m+2T)ρk−m+1sk−m+1sk−m+1T(Vk−m+2⋯Vk)+⋯+ρkskskT
因此在L-BFGS算法中无需保留完整的 H k \boldsymbol{H}_k Hk,只需存储向量序列 { s i } i = k − m k \left\{ \boldsymbol{s}_i \right\} _{i=k-m}^{k} {si}i=k−mk、 { y i } i = k − m k \left\{ \boldsymbol{y}_i \right\} _{i=k-m}^{k} {yi}i=k−mk,占用存储空间 2 m n 2mn 2mn,空间复杂度为 O ( n ) O(n) O(n),下降了一个量级
代码实现为
gx = g_func(x)
# two-iteration
a = []
d = g_func(x).reshape(-1, 1)
for i in range(len(S) - 1, -1, -1):
s_i, y_i, p_i = S[i], Y[i], P[i]
a_i = p_i * s_i.T @ d
d = d - a_i * y_i
a.append(a_i)
for i in range(len(S)):
s_i, y_i, p_i = S[i], Y[i], P[i]
a_i = a[len(S) - i - 1]
beta = p_i * y_i.T @ d
d = d + s_i * (a_i - beta)
d = d.squeeze()
alpha = self.line_searcher_.search(func, g_func, x, -d)
x_next = x - alpha * d
s = (x_next - x).reshape(-1, 1)
y = (g_func(x_next) - gx).reshape(-1, 1)
if len(S) == self.m:
S.pop(0)
S.append(s)
if len(Y) == self.m:
Y.pop(0)
Y.append(y)
if len(P) == self.m:
P.pop(0)
P.append(1.0 / (s.T @ y))
6 案例分析
以曲线拟合为例展示三种牛顿类优化算法的效果
考虑如下方程:
y = e a x 2 + b x + c + w \boldsymbol{y}=e^{a\boldsymbol{x}^2+b\boldsymbol{x}+c}+\boldsymbol{w} y=eax2+bx+c+w
其中 a a a、 b b b、 c c c是待估计的曲线参数, w \boldsymbol{w} w是高斯噪声,假设有 n n n个观测样本 ( x i , y i ) (x_i,y_i) (xi,yi),希望根据这组样本得到最佳的曲线参数,构造如下的优化问题
F ( θ ) = min 1 2 n ∑ i = 1 n ( y i − e a x i 2 + b x i + c ) 2 F(\boldsymbol{\theta})=\min \frac{1}{2n}\sum_{i=1}^{n}{(y_i-e^{ax_i^2+bx_i+c})^2} F(θ)=min2n1i=1∑n(yi−eaxi2+bxi+c)2
下面来看结果
- SR1算法
=========================================================== Method: SR1 Iterations: 10, Using time: 0.27718114852905273 Start Point: [ 2 -1 5] Start Value: 16427.297702943684 End Point: [1.58470727 1.19606329 1.24535202] End Value: 0.492582013221927 ===========================================================
-
DFP算法
=========================================================== Method: DFP Iterations: 68, Using time: 1.8977277278900146 Start Point: [ 2 -1 5] Start Value: 16427.297702943684 End Point: [1.32228464 1.58602539 1.11512083] End Value: 0.4622062689277505 ===========================================================
-
BFGS算法
=========================================================== Method: BFGS Iterations: 19, Using time: 0.5240802764892578 Start Point: [ 2 -1 5] Start Value: 16427.297702943684 End Point: [1.32275944 1.58517781 1.11542359] End Value: 0.46220542143350907 ===========================================================
-
L-BFGS
=========================================================== Method: LBFGS Iterations: 19, Using time: 0.5343437194824219 Start Point: [ 2 -1 5] Start Value: 16427.297702943684 End Point: [1.32204779 1.58592409 1.11533423] End Value: 0.46220620676321367 ===========================================================
从结果来看,由于LBFGS在内存和计算上都有显著优势,因此它在许多实际问题中(如大规模数据优化、深度学习训练等)得到了广泛应用。它是许多优化库(如SciPy
、TensorFlow
、PyTorch
等)中常用的优化算法之一
完整工程代码请联系下方博主名片获取
🔥 更多精彩专栏:
原文地址:https://blog.csdn.net/FRIGIDWINTER/article/details/144013803
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!