基于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
相关产品推荐
相关产品推荐

