You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Basinhopping(双阶段)的多元值函数优化问题咨询

用SciPy BasinHopping实现带自定义范数的多元值函数全局优化

要解决Basinhopping要求标量目标函数,但又要保留原多元值函数f给局部最小化器的问题,核心思路是通过包装类或闭包拆分范数计算与原函数逻辑,既满足Basinhopping的标量输出要求,又能让局部最小化器直接访问原函数f。

方案一:用包装类封装原函数与范数逻辑

通过自定义类同时实现标量输出(供Basinhopping使用)和原函数存储(供局部最小化器调用):

import numpy as np
from scipy.optimize import basinhopping, least_squares

# 包装类:封装原多元值函数和范数计算
class LeastSquaresWrapper:
    def __init__(self, fun, norm='l2'):
        self.fun = fun  # 保存原函数f: R^n -> R^m
        self.norm = norm

    def __call__(self, x):
        # 返回范数值,满足Basinhopping的标量要求
        residuals = self.fun(x)
        if self.norm == 'l2':
            return np.sum(residuals ** 2)
        elif self.norm == 'l1':
            return np.sum(np.abs(residuals))
        elif self.norm == 'linf':
            return np.max(np.abs(residuals))
        else:
            raise ValueError(f"不支持的范数类型: {self.norm}")

# 自定义局部最小化器:从包装器中取出原函数调用least_squares
def custom_minimizer(fun_wrapper, x0, *args, **kwargs):
    return least_squares(fun_wrapper.fun, x0, **kwargs)

# 示例多元值函数
def f(x):
    return np.array([x[0]**2 - 2, x[1]**3 - 3*x[1]])

# 初始化参数
x0 = np.array([1.0, 1.0])
fun_wrapper = LeastSquaresWrapper(f, norm='l2')

# 运行全局优化
ret = basinhopping(
    fun_wrapper,
    x0,
    minimizer_kwargs={"method": custom_minimizer},
    niter=100  # 根据问题复杂度调整迭代次数
)

print("全局优化最优解:", ret.x)
print("最小范数值:", ret.fun)

方案二:用闭包实现轻量封装

如果不想用类,也可以用闭包给包装函数添加属性存储原函数:

import numpy as np
from scipy.optimize import basinhopping, least_squares

# 创建闭包包装器
def create_least_squares_wrapper(fun, norm='l2'):
    def wrapper(x):
        residuals = fun(x)
        if norm == 'l2':
            return np.sum(residuals ** 2)
        elif norm == 'l1':
            return np.sum(np.abs(residuals))
        elif norm == 'linf':
            return np.max(np.abs(residuals))
        else:
            raise ValueError(f"不支持的范数类型: {norm}")
    # 给包装函数添加属性,保存原函数
    wrapper.original_fun = fun
    return wrapper

# 自定义局部最小化器
def custom_minimizer(fun_wrapper, x0, *args, **kwargs):
    return least_squares(fun_wrapper.original_fun, x0, **kwargs)

# 示例使用
def f(x):
    return np.array([x[0]**2 - 2, x[1]**3 - 3*x[1]])

x0 = np.array([1.0, 1.0])
fun_wrapper = create_least_squares_wrapper(f, norm='l2')

ret = basinhopping(
    fun_wrapper,
    x0,
    minimizer_kwargs={"method": custom_minimizer},
    niter=100
)

print("全局优化最优解:", ret.x)
print("最小范数值:", ret.fun)

扩展说明

  • 范数扩展:可以在包装逻辑中添加任意自定义范数的计算,只需在__call__或闭包函数中补充对应分支即可。
  • 局部最小化器参数传递:如果需要给least_squares传递额外参数(如边界bounds、雅可比矩阵jac等),只需在minimizer_kwargs中添加kwargs字段,示例:
    minimizer_kwargs={
        "method": custom_minimizer,
        "kwargs": {"bounds": ([0, -2], [2, 2]), "jac": "3-point"}
    }
    
  • Basinhopping参数调优:通过调整niter(全局迭代次数)、stepsize(随机步长)等参数,可以平衡全局搜索的效率与精度。

内容的提问来源于stack exchange,提问作者TrakJohnson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 12:58:09