首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >拟牛顿法BFGS算法与实现代码

拟牛顿法BFGS算法与实现代码

原创
作者头像
用户10150864
修改2025-09-22 18:31:59
修改2025-09-22 18:31:59
2720
举报
文章被收录于专栏:统计学统计学机器学习

一、定义

BFGS公式由拟牛顿法的DFP方法而来,又称变尺度法,在这种方法中,定义的校正矩阵为:

二、实现代码

代码语言:txt
复制
import numpy as np
from scipy.optimize import minimize  # 用于对比验证

def bfgs_optimize(f, grad_f, x0, max_iter=1000, tol=1e-6):
    """
    BFGS 优化算法实现
    
    参数:
        f: 目标函数
        grad_f: 目标函数的梯度
        x0: 初始点
        max_iter: 最大迭代次数
        tol: 收敛容忍度(当梯度范数小于该值时停止)
    
    返回:
        x: 最优解
        history: 迭代历史记录(可选)
    """
    n = len(x0) 
    x = x0.copy()  # 浅拷贝  
    Hk = np.eye(n)  # 初始 Hessian 逆(即(B^(-1)_{k+1})的近似 (即公式 1.5 中 的 Hk 取单位矩阵); 
    history = [x.copy()]  # 记录迭代历史 第一个值; 
    
    for k in range(max_iter):
    
        gk = grad_f(x)  # 计算梯度
        
        if np.linalg.norm(gk) < tol:  # 检查是否收敛
            break
        
        dk = -np.dot(Bk, gk)  # 计算搜索方向  
        
        # 线搜索(这里采用简单的 Armijo 线搜索) 
        alpha = 1.0
        
        c = 0.25  # Armijo 条件参数   
        
        rho = 0.5  # 步长缩减因子  
        
        while f(x + alpha * dk) > f(x) + c * alpha * np.dot(gk, dk):
            alpha *= rho
        
        pk = alpha * dk  # 计算步长   n * 1 ; 
        x_new = x + sk   # sk 为 迭代变量差   dk | n* 1 
        
        # 计算新梯度
        gk_new = grad_f(x_new)
        qk = gk_new - gk   # qk 为 梯度差   q 
        
        # 更新 Hessian 逆的近似 H_{k+1} 公式 1.5 
        
        Hk_qk = np.dot(Hk, qk)           #  n * n , n * 1 ;  对于二维矩阵 计算矩阵积;
        qk_T_Hk_qk = np.dot(qk, Hk_qk)   #  对于一维矩阵计算内积   1 * n , n * 1; 
        pk_pkT = np.outer(pk, pk)        #  计算外积,outer里的矩阵都将展开为一维矩阵 得到 二维的n*n 矩阵;
        # Hk_pk_pkT_Hk = np.outer(Hk_qk, Hk_qk) / qk_T_Hk_qk  # 
        
        # BFGS 更新公式
        Hk = Hk + (1 + qk_T_Hk_qk / np.dot(qk, pk)) * (pk_pkT / np.dot(qk, pk)) - ( np.outer(pk, Hk_qk)+ np.outer(Hk_qk, pk)) / np.dot(qk, pk)
        # 根据公式1.5 
        x = x_new 
        
        history.append(x.copy())
    
    return x, history

# ===== 测试案例:Rosenbrock 函数优化 =====
def rosenbrock(x):
    """Rosenbrock 函数(经典优化测试函数)"""
    return (1 - x[0])**2 + 100 * (x[1] - x[0]**2)**2

def rosenbrock_grad(x):
    """Rosenbrock 函数的梯度"""
    return np.array([
        -2 * (1 - x[0]) - 400 * x[0] * (x[1] - x[0]**2),
        200 * (x[1] - x[0]**2)
    ])

# ===== 测试案例:Rosenbrock 函数优化 =====
def rosenbrock(x):
    """Rosenbrock 函数(经典优化测试函数)"""
    return (1 - x[0])**2 + 100 * (x[1] - x[0]**2)**2

def rosenbrock_grad(x):
    """Rosenbrock 函数的梯度"""
    return np.array([
        -2 * (1 - x[0]) - 400 * x[0] * (x[1] - x[0]**2),
        200 * (x[1] - x[0]**2)
    ])



# 初始点
x0 = np.array([-3.5, 3.5])

# 手动 BFGS 优化
x_opt, history = bfgs_optimize(rosenbrock, rosenbrock_grad, x0)
print("BFGS 手动优化结果:", x_opt)

# 用 SciPy 的 BFGS 验证。
res = minimize(rosenbrock, x0, method='BFGS', jac=rosenbrock_grad)
print("SciPy BFGS 优化结果:", res.x)

x1= np.array([-1,1])


代码语言:txt
复制
结果:
BFGS 手动优化结果: [1. 1.]
SciPy BFGS 优化结果: [0.99999998 0.99999995]

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 [email protected] 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 [email protected] 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档