我想最小化带有边界和约束的区域上的凸函数,因此我尝试将scipy.optimize.minimize
与SLSQP
选项一起使用。但是我的功能只在离散点定义。线性插值似乎不是一个选项,因为在所有值中计算我的函数会占用太多时间。作为一个最小的工作示例我有:
from scipy.optimize import minimize
import numpy as np
f=lambda x : x**2
N=1000000
x_vals=np.sort(np.random.random(N))*2-1
y_vals=f(x_vals)
def f_disc(x, x_vals, y_vals):
return y_vals[np.where(x_vals<x)[-1][-1]]
print(minimize(f_disc, 0.5, method='SLSQP', bounds = [(-1,1)], args = (x_vals, y_vals)))
产生以下输出:
fun: 0.24999963136767756
jac: array([ 0.])
message: 'Optimization terminated successfully.'
nfev: 3
nit: 1
njev: 1
status: 0
success: True
x: array([ 0.5])
我们当然知道它是假的,但f_disc
的定义欺骗优化器相信它在给定索引处是常量。对于我的问题,我只有f_disc
且无法访问f
。此外,拨打f_disc
的电话可能需要一分钟。
答案 0 :(得分:2)
如果您的功能不顺畅,基于梯度的优化技术将失败。当然,您可以使用不基于渐变的方法,但这些方法通常需要更多的功能评估。
以下两个选项可以发挥作用。
nelder-mead method不需要渐变,但它的缺点是无法处理边界或约束:
print(minimize(f_disc, 0.5, method='nelder-mead', args = (x_vals, y_vals)))
# final_simplex: (array([[ -4.44089210e-16], [ 9.76562500e-05]]), array([ 2.35756658e-12, 9.03710082e-09]))
# fun: 2.3575665763730149e-12
# message: 'Optimization terminated successfully.'
# nfev: 32
# nit: 16
# status: 0
# success: True
# x: array([ -4.44089210e-16])
differential_evolution
是一个优化器,不对平滑度做任何假设。它不仅可以处理边界;它需要他们。但是,它需要比nelder-mead更多的功能评估。
print(differential_evolution(f_disc, bounds = [(-1,1)], args = (x_vals, y_vals)))
# fun: 5.5515134011907119e-13
# message: 'Optimization terminated successfully.'
# nfev: 197
# nit: 12
# success: True
# x: array([ 2.76298719e-06])