Scipy全局优化结合Jacobian信息的实现难题与替代方案问询
全局优化中结合Jacobian加速的解决方案
问题背景
当前处理一个全局优化问题,目标函数具备可微性,计划用PyTorch自动微分提供Jacobian信息加速局部优化。现有局部优化代码通过Scipy的minimize配合jac=True,让函数同时返回目标值和Jacobian,示例代码如下:
import numpy import scipy.optimize import torch def minim(obs, f, p0): """Fit function f to observations "obs" starting at p0""" def fitfn(pars): pars = torch.tensor(pars, requires_grad=True) y = f(pars) # 最小二乘损失 res = ((obs - y)**2).sum() res.backward() return res.data.cpu().numpy(), pars.grad.data.cpu().numpy() res = scipy.optimize.minimize( fitfn, p0, method="BFGS", jac=True # 告知优化器函数返回包含Jacobian ) return res # 观测点 X = torch.arange(100) def exfn(p): y = torch.sin(p[0]*X) + torch.cos(p[1]*X) return y # 生成观测数据 yp = exfn(torch.tensor([0.3, 0])) # 局部优化测试 minim(yp, exfn, numpy.array([0.34, 0.01]))
但使用Scipy全局优化器(如dual_annealing)时,无法直接复用这种返回Jacobian的函数模式:
dual_annealing(f, bounds, args=(x,y0), minimizer_kwargs={'jac':True})
minimizer_kwargs仅对内部调用的局部优化器生效,外层全局优化器本身不需要Jacobian,因此传入返回值+Jacobian的函数会报错。
解决办法
1. 适配Scipy全局优化的函数拆分
Scipy全局优化器(如dual_annealing)只要求目标函数返回标量损失值,局部优化阶段的Jacobian需求仅在内部minimize调用中处理。因此可以拆分函数:
- 给全局优化器的函数:仅计算并返回损失值
- 给局部优化器的函数:同时返回损失值和Jacobian
修改后的代码示例:
import numpy import scipy.optimize import torch # 全局优化用的损失函数(仅返回值) def global_loss_fn(pars, obs, f): pars = torch.tensor(pars) y = f(pars) return ((obs - y)**2).sum().cpu().numpy() # 局部优化用的带Jacobian的函数 def local_fitfn(pars, obs, f): pars = torch.tensor(pars, requires_grad=True) y = f(pars) res = ((obs - y)**2).sum() res.backward() return res.data.cpu().numpy(), pars.grad.data.cpu().numpy() # 全局优化+局部Jacobian加速 def global_minim(obs, f, bounds): res = scipy.optimize.dual_annealing( global_loss_fn, bounds=bounds, args=(obs, f), minimizer_kwargs={ 'method': 'BFGS', 'jac': True, 'args': (obs, f), 'fun': local_fitfn # 指定局部优化用带Jacobian的函数 } ) return res # 测试 X = torch.arange(100) def exfn(p): return torch.sin(p[0]*X) + torch.cos(p[1]*X) yp = exfn(torch.tensor([0.3, 0])) # 参数边界:比如p0∈[0,1], p1∈[-0.5,0.5] bounds = [(0, 1), (-0.5, 0.5)] global_minim(yp, exfn, bounds)
这样外层全局搜索只用标量损失,内部局部精炼时用带Jacobian的函数加速,完美适配Scipy的接口。
2. 替代框架选择
如果不想拆分函数,也可以选择原生支持全局优化+自动微分的框架:
- Nevergrad:支持全局优化算法,可直接兼容PyTorch张量,自动利用梯度信息加速局部优化,无需手动处理Jacobian返回格式
- Optuna:虽然主打超参数调优,但也支持连续参数的全局优化,可集成PyTorch自动微分实现梯度加速的局部搜索
- PyTorch Lightning Bolts:提供部分优化工具,可结合PyTorch的自动微分能力实现全局+局部优化的结合
内容的提问来源于stack exchange,提问作者tbolind
相关产品推荐
相关产品推荐

