通俗易懂讲透BFGS优化算法

通俗易懂讲透BFGS优化算法(本科生/研究生都能看懂)

本文用大白话+形象比喻+公式拆解+可运行代码+对比总结,把BFGS从原理、流程、优缺点到适用场景讲得清清楚楚,适合数值优化、机器学习复习、课程笔记与面试。


一、先搞懂:我们为什么需要BFGS?

在机器学习/深度学习里,我们的目标是最小化损失函数,找到最优参数
常见的优化方法有:

  • 梯度下降(GD):只看一阶导数(坡度),走得慢、震荡多
  • 牛顿法:用二阶导数(曲率/Hessian),收敛极快,但计算Hessian矩阵代价太高,高维场景根本跑不动

于是就有了BFGS

不用算真实Hessian,只用梯度信息,迭代构造近似Hessian逆,实现超线性收敛

一句话总结:
BFGS = 拟牛顿法的王者,比梯度下降快百倍,比牛顿法省算力。


二、BFGS 是什么?(超形象比喻)

BFGS(Broyden–Fletcher–Goldfarb–Shanno)是最经典的拟牛顿算法

你可以把优化过程比作下山找谷底

  • 梯度下降:蒙着眼,只看脚下坡度,一步一步挪,容易绕路、震荡
  • 牛顿法:带着完整地形图(Hessian),一步到位,但地图太重、太贵
  • BFGS边走边画简易地图,不用提前画全,每走一步就修正地图,又快又省资源

核心逻辑:
用历史位置差和梯度差,迭代更新近似Hessian逆矩阵,不用直接计算二阶导数。


三、BFGS 核心思想(不用公式也能懂)

  1. 初始假设:最开始把地形当成平地,Hessian逆用单位矩阵
  2. 计算方向:结合当前梯度 + 近似Hessian逆,得到更优的下降方向
  3. 线搜索:在这个方向上找最合适的步长
  4. 更新近似矩阵:用新走的位移和梯度变化,修正“简易地图”
  5. 重复迭代:直到梯度接近0(到达谷底)

四、BFGS 公式一步步拆解(详细易懂)

1. 先看牛顿法(对照)

xk+1=xk−[∇2f(xk)]−1∇f(xk)x_{k+1} = x_k - [\nabla^2f(x_k)]^{-1}\nabla f(x_k)xk+1=xk[2f(xk)]1f(xk)

  • ∇2f\nabla^2f2f:Hessian矩阵(二阶导),计算/求逆代价极大
  • 优点:二阶收敛,超快
  • 缺点:高维算不动,可能不正定

2. BFGS 核心变量

  • xkx_kxk:当前位置
  • gk=∇f(xk)g_k=\nabla f(x_k)gk=f(xk):当前梯度
  • HkH_kHk近似Hessian逆矩阵(BFGS真正维护的东西)
  • sk=xk+1−xks_k = x_{k+1}-x_ksk=xk+1xk:位置变化
  • yk=gk+1−gky_k = g_{k+1}-g_kyk=gk+1gk:梯度变化
  • ρk=1/(ykTsk)\rho_k=1/(y_k^Ts_k)ρk=1/(ykTsk):简化系数

3. 搜索方向

pk=−Hkgkp_k = -H_k g_kpk=Hkgk
这一步融合了梯度二阶近似,方向比纯梯度更准。


4. BFGS 逆Hessian更新公式(最常用)

Hk+1=(I−ρkskykT)Hk(I−ρkykskT)+ρkskskTH_{k+1} = \left(I-\rho_k s_k y_k^T\right) H_k \left(I-\rho_k y_k s_k^T\right) + \rho_k s_k s_k^THk+1=(IρkskykT)Hk(IρkykskT)+ρkskskT

✅ 直白解释:

  • 保留上一轮的近似矩阵
  • 用新的位移sss和梯度差yyy修正
  • 保证矩阵对称正定,确保是下降方向

5. 参数更新

xk+1=xk+αkpkx_{k+1} = x_k + \alpha_k p_kxk+1=xk+αkpk
αk\alpha_kαk由线搜索(Armijo/Wolfe条件)得到。


五、BFGS 完整算法流程(7步背会)

  1. 初始化:x0x_0x0H0=IH_0=IH0=I(单位矩阵),阈值ϵ\epsilonϵ
  2. 计算梯度gkg_kgk,若∥gk∥<ϵ\|g_k\|<\epsilongk<ϵ,停止
  3. 计算搜索方向pk=−Hkgkp_k=-H_k g_kpk=Hkgk
  4. 线搜索求最优步长αk\alpha_kαk
  5. 计算sks_kskyky_kykρk\rho_kρk
  6. 用BFGS公式更新Hk+1H_{k+1}Hk+1
  7. 更新xk+1x_{k+1}xk+1,回到步骤2

六、代码实战:BFGS 优化 Rosenbrock 函数

直接复制可运行,包含BFGS实现 + 梯度下降对比 + 可视化

import numpy as np
import matplotlib.pyplot as plt
import time
from mpl_toolkits.mplot3d import Axes3D

# ===================== 1. 定义测试函数:Rosenbrock(香蕉函数)=====================
def rosenbrock(x):
    return 100 * (x[1] - x[0]**2)**2 + (1 - x[0])**2

def grad_rosenbrock(x):
    dx = -400 * x[0] * (x[1] - x[0]**2) - 2 * (1 - x[0])
    dy = 200 * (x[1] - x[0]**2)
    return np.array([dx, dy])

# ===================== 2. 线搜索(Armijo 条件)=====================
def line_search(f, grad, x, p, alpha=1.0, rho=0.8, c=1e-4):
    fx = f(x)
    gx = grad(x)
    while f(x + alpha * p) > fx + c * alpha * np.dot(gx, p):
        alpha *= rho
    return alpha

# ===================== 3. BFGS 算法实现 =====================
def bfgs(f, grad, x0, tol=1e-6, max_iter=1000):
    x = x0.copy()
    n = len(x)
    H = np.eye(n)  # 初始近似Hessian逆
    path = [x.copy()]
    f_val = [f(x)]
    
    for _ in range(max_iter):
        g = grad(x)
        if np.linalg.norm(g) < tol:
            break
        # 搜索方向
        p = -H @ g
        # 线搜索
        alpha = line_search(f, grad, x, p)
        # 更新
        s = alpha * p
        x_new = x + s
        y = grad(x_new) - g
        # BFGS更新
        rho = 1.0 / (y @ s)
        I = np.eye(n)
        H = (I - rho * np.outer(s, y)) @ H @ (I - rho * np.outer(y, s)) + rho * np.outer(s, s)
        # 记录
        x = x_new
        path.append(x.copy())
        f_val.append(f(x))
    return np.array(path), f_val

# ===================== 4. 梯度下降(对比用)=====================
def gradient_descent(f, grad, x0, lr=1e-3, tol=1e-6, max_iter=50000):
    x = x0.copy()
    path = [x.copy()]
    f_val = [f(x)]
    for _ in range(max_iter):
        g = grad(x)
        if np.linalg.norm(g) < tol:
            break
        x = x - lr * g
        path.append(x.copy())
        f_val.append(f(x))
    return np.array(path), f_val

# ===================== 5. 运行对比 =====================
x0 = np.array([-1.5, 1.5])

start = time.time()
path_bfgs, f_bfgs = bfgs(rosenbrock, grad_rosenbrock, x0)
t_bfgs = time.time() - start

start = time.time()
path_gd, f_gd = gradient_descent(rosenbrock, grad_rosenbrock, x0)
t_gd = time.time() - start

print(f"BFGS 迭代:{len(f_bfgs)-1} 次,时间:{t_bfgs:.4f}s")
print(f"GD 迭代:{len(f_gd)-1} 次,时间:{t_gds:.4f}s")

# ===================== 6. 可视化:优化路径 =====================
X = np.linspace(-2, 2, 400)
Y = np.linspace(-1, 3, 400)
XX, YY = np.meshgrid(X, Y)
ZZ = 100 * (YY - XX**2)**2 + (1 - XX)**2

plt.figure(figsize=(10, 6))
plt.contour(XX, YY, ZZ, levels=np.logspace(-0.5, 3.5, 20), cmap="viridis")
plt.plot(path_bfgs[:,0], path_bfgs[:,1], "ro-", label="BFGS", markersize=4)
plt.plot(path_gd[:,0], path_gd[:,1], "bx--", label="Gradient Descent", markersize=2)
plt.title("BFGS vs GD 优化路径")
plt.xlabel("x")
plt.ylabel("y")
plt.legend()
plt.grid(True)
plt.show()

# ===================== 7. 收敛曲线 =====================
plt.figure(figsize=(10, 6))
plt.plot(f_bfgs, label="BFGS", linewidth=2)
plt.plot(f_gd, label="GD", linewidth=2)
plt.yscale("log")
plt.title("收敛曲线对比")
plt.xlabel("迭代次数")
plt.ylabel("函数值")
plt.legend()
plt.grid(True)
plt.show()

七、BFGS 优点(面试必背)

  1. 超线性收敛:比梯度下降快几十~几百倍
  2. 不用计算真实Hessian:避开O(n3)O(n^3)O(n3)求逆噩梦
  3. 稳定可靠:自动保持矩阵对称正定,保证下降方向
  4. 中小维度最优:参数维度几百~几千时效果最好
  5. 实现简单:只需线搜索 + 矩阵更新

八、BFGS 缺点(必须知道)

  1. 内存开销大:要存n×nn×nn×n矩阵,高维(>1000)吃不消
  2. 不适合随机梯度:深度学习批量SGD噪声大,BFGS容易崩
  3. 依赖线搜索:步长没选好会不收敛
  4. 非凸场景不稳定:鞍点多、地形复杂时容易失效

九、BFGS 家族对比(速记表)

算法二阶信息内存收敛速度适用场景
梯度下降O(n)O(n)O(n)慢(线性)大规模/深度学习
牛顿法完整HessianO(n2)O(n^2)O(n2)极快(二阶)低维、Hessian好算
BFGS近似Hessian逆O(n2)O(n^2)O(n2)快(超线性)中小规模、光滑凸优化
L-BFGS有限记忆近似O(mn)O(mn)O(mn)高维大规模(机器学习常用)

十、什么时候用 BFGS?

推荐用 BFGS

  • 无约束、光滑、接近凸的优化问题
  • 维度:几十 ~ 几千(n ≤ 1000)
  • 梯度可以精确计算,无噪声
  • 追求快速收敛 + 高精度

不要用 BFGS

  • 深度学习(CNN/Transformer)→ 用 Adam / SGD
  • 维度极高(n > 10^4)→ 用 L-BFGS
  • 梯度带噪声 → 用一阶自适应方法
  • 强非凸、鞍点多 → 用信赖域方法

十一、一句话总结

BFGS 是拟牛顿法的标杆,用梯度构造近似二阶信息,不计算真实Hessian却能超线性收敛,是中小规模光滑优化的首选算法。
高维场景请用它的升级版 L-BFGS

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeepModel

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值