如何在有界python优化中找到全局最小值?

如何在有界python优化中找到全局最小值?,python,optimization,scipy,numeric,mathematical-optimization,Python,Optimization,Scipy,Numeric,Mathematical Optimization,我有一个包含64个变量的Python函数,我尝试在最小化函数中使用L-BFGS-B方法对其进行优化,但是该方法对初始猜测有很大的依赖性,并且未能找到全局最小值 但我喜欢它为变量设置边界的能力。有没有一种方法/函数可以在变量有边界的情况下找到全局最小值?一些关于调试和可视化任何优化器的常识性建议 关于你的职能: 您的目标函数和约束是否合理? 如果目标函数是一个和,比如说f()+g(), 分别为“fx opt.nptxt”(以下)中的所有x打印这些文件; 如果f()是总和的99%,而g()1%,则进

我有一个包含64个变量的Python函数,我尝试在最小化函数中使用L-BFGS-B方法对其进行优化,但是该方法对初始猜测有很大的依赖性,并且未能找到全局最小值


但我喜欢它为变量设置边界的能力。有没有一种方法/函数可以在变量有边界的情况下找到全局最小值?

一些关于调试和可视化任何优化器的常识性建议 关于你的职能:

您的目标函数和约束是否合理?
如果目标函数是一个和,比如说
f()+g()
, 分别为
“fx opt.nptxt”
(以下)中的所有
x
打印这些文件; 如果
f()
是总和的99%,而
g()
1%,则进行调查

约束条件:在
xfinal
中有多少组件
x_i
卡在边界上,
x_i=hi_i


您的功能在全球范围内有多不稳定?
使用多个随机起始点运行,并将结果保存到分析/绘图:

title = "%s  n %d  ntermhess %d  nsample %d  seed %d" % (  # all params!
    __file__, n, ntermhess, nsample, seed )
print title
...
np.random.seed(seed)  # for reproducible runs
np.set_printoptions( threshold=100, edgeitems=10, linewidth=100,
        formatter = dict( float = lambda x: "%.3g" % x ))  # float arrays %.3g

lo, hi = bounds.T  # vecs of numbers or +- np.inf
print "lo:", lo
print "hi:", hi

fx = []  # accumulate all the final f, x
for jsample in range(nsample):
        # x0 uniformly random in box lo .. hi --
    x0 = lo + np.random.uniform( size=n ) * (hi - lo)

    x, f, d = fmin_l_bfgs_b( func, x0, approx_grad=1,
                m=ntermhess, factr=factr, pgtol=pgtol )
    print "f: %g  x: %s  x0: %s" % (f, x, x0)
    fx.append( np.r_[ f, x ])

fx = np.array(fx)  # nsample rows, 1 + dim cols
np.savetxt( "fx-opt.nptxt", fx, fmt="%8.3g", header=title )  # to analyze / plot

ffinal = fx[:,0]
xfinal = fx[:,1:]
print "final f values, sorted:", np.sort(ffinal)
jbest = ffinal.argmin()
print "best x:", xfinal[jbest]
如果某些
ffinal
值看起来相当不错, 在这些点附近尝试更多随机起始点-- 这肯定比纯粹的随机好

如果
x
s是曲线或任何真实的,则绘制最好的几个
x0
xfinal

(经验法则是
d
维度中的5*d或10*d样本。 太慢,太多?减少
maxiter
/
maxeval
,减少
ftol
-- 这样的探索不需要
ftol
1e-6。)

如果你想得到可重复的结果, 然后必须在
标题中列出所有相关参数
在派生文件和绘图中。
否则,你会问“这是从哪里来的?”


你的函数在ε标度~10^-6上有多颠簸?
近似梯度的方法有时会返回其最后的估计值, 但如果不是:

from scipy.optimize._numdiff import approx_derivative  # 3-point, much better than
## from scipy.optimize import approx_fprime
for eps in [1e-3, 1e-6]:
    grad = approx_fprime( x, func, epsilon=eps )
    print "approx_fprime eps %g: %s" % (eps, grad)
但是,如果在优化器退出之前梯度估计值很差/不稳定, 你不会看到的。 然后您必须保存所有中间
[f,x,approx\u fprime]
也要看他们,;python很简单——如果不清楚,请询问

在某些问题区域,通常会从声称的
xmin
备份并重新启动。 例如,如果你在乡村公路上迷路, 首先找到一条主要道路,然后从那里重新开始


总结:
不要期望任何黑盒优化器在一个 大范围颠簸,或ε-尺度颠簸,或两者兼而有之。

投资于测试搭建,并以的方式查看优化器正在做什么。

非常感谢您的详细回复,但由于我对python相当陌生,我不太知道如何在我的程序中实现代码,但我尝试了以下优化:

x0=np.array((10, 13, f*2.5, 0.08,    10, f*1.5,  0.06, 20, 
             10, 14, f*2.5, 0.08,    10, f*1.75, 0.07, 20,
             10, 15, f*2.5, 0.08,    10, f*2,    0.08, 20,
             10, 16, f*2.5, 0.08,    10, f*2.25, 0.09, 20,
             10, 17, f*2.5, -0.08,    10, f*2.5, -0.06, 20,
             10, 18, f*2.5, -0.08,    10, f*2.75,-0.07, 20,
             10, 19, f*2.5, -0.08,    10, f*3,   -0.08, 20,
             10, 20, f*2.5, -0.08,    10, f*3.25,-0.09, 20))

# boundary for each variable, each element in this restricts the corresponding element     above
bnds=((1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35), 
  (1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35), 
  (1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35), 
  (1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35), 
  (1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35), 
  (1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35), 
  (1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35), 
  (1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35), )

from scipy.optimize import basinhopping
from scipy.optimize import minimize

merit=a*meritoflength + b*meritofROC + c*meritofproximity +d*(distancetoceiling+distancetofloor)+e*heightorder
minimizer_kwargs = {"method": "L-BFGS-B", "bounds": bnds, "tol":1e0}
ret = basinhopping(merit_function, x0, minimizer_kwargs=minimizer_kwargs, niter=10, T=0.01)

zoom = ret['x']
res = minimize(merit_function, zoom, method = 'L-BFGS-B', bounds=bnds, tol=1e-5)
print res
价值函数将x0与一些其他值结合起来,形成8条曲线的6个控制点,然后计算它们的长度、曲率半径等。它将最终价值作为这些参数与一些权重的线性组合返回

我使用低精度的
basinhopping
找到一些极小值,然后使用
minimize
提高最小值的精度


p、 我运行的平台是Enthoght canopy 1.3.0,numpy 1.8.0 scipy 0.13.2 mac 10.8.3

这可以通过
scipy.optimize.basinhoping
实现。Basinhoping是一个函数,用于寻找目标函数的全局最小值。它使用函数
scipy.optimize.minimize
重复最小化,并在每次最小化后在坐标空间中采取随机步骤。Basinhoping仍然可以通过使用实现边界的一个极小值(例如L-BFGS-B)来遵守边界。下面是一些代码,演示如何执行此操作

# an example function with multiple minima
def f(x): return x.dot(x) + sin(np.linalg.norm(x) * np.pi)

# the starting point
x0 = [10., 10.]

# the bounds
xmin = [1., 1.]
xmax = [11., 11.]

# rewrite the bounds in the way required by L-BFGS-B
bounds = [(low, high) for low, high in zip(xmin, xmax)]

# use method L-BFGS-B because the problem is smooth and bounded
minimizer_kwargs = dict(method="L-BFGS-B", bounds=bounds)
res = basinhopping(f, x0, minimizer_kwargs=minimizer_kwargs)
print res
上面的代码适用于一个简单的情况,但如果basinhopping随机置换例程将您带到那里,您仍然可以在禁止区域结束。幸运的是,通过使用关键字
take\u step

class RandomDisplacementBounds(object):
    """random displacement with bounds"""
    def __init__(self, xmin, xmax, stepsize=0.5):
        self.xmin = xmin
        self.xmax = xmax
        self.stepsize = stepsize

    def __call__(self, x):
        """take a random step but ensure the new position is within the bounds"""
        while True:
            # this could be done in a much more clever way, but it will work for example purposes
            xnew = x + np.random.uniform(-self.stepsize, self.stepsize, np.shape(x))
            if np.all(xnew < self.xmax) and np.all(xnew > self.xmin):
                break
        return xnew

# define the new step taking routine and pass it to basinhopping
take_step = RandomDisplacementBounds(xmin, xmax)
result = basinhopping(f, x0, niter=100, minimizer_kwargs=minimizer_kwargs,
                      take_step=take_step)
print result
class RandomDisplacementBounds(对象):
“”“带边界的随机位移”“”
定义初始值(self,xmin,xmax,步长=0.5):
self.xmin=xmin
self.xmax=xmax
self.stepsize=步长
定义调用(self,x):
“”“采取随机步骤,但确保新位置在范围内”“”
尽管如此:
#这可以用一种更聪明的方法来实现,但它可以用于其他目的
xnew=x+np.随机均匀(-自步长,自步长,np.形状(x))
如果np.all(xnewself.xmin):
打破
返回xnew
#定义新的步骤执行例程并将其传递给basinhopping
take_step=随机位移边界(xmin,xmax)
结果=基本海平面(f,x0,niter=100,minimizer_-kwargs=minimizer_-kwargs,
采取步骤=采取步骤)
打印结果

自从您提出这个问题以来,在全局优化方面已经取得了一些不错的进展,这些进展可能对您很有帮助。特别是,我要提请您注意SHGO算法(),它现在也作为标准选项之一出现在scipy.optimize中。然而,如果你真的无法降低搜索空间的维数,它可能会与你的搜索空间的维数发生冲突


您可以尝试一些经典的方法,如模式搜索,或代理方法,其中也包括。如果你真的陷入困境,你可以考虑像OptTa之类的东西,或者,如果你绝望了,Hyopopt。您也可以尝试一系列受自然启发的算法,不过您可以从我提供的链接中看到,这些算法并不总是像广告中所宣传的那样有效。

我认为这是一个更适合提出此类问题的地方。请您描述一下您的函数——平滑/渐变/黑森?如果可以将其表示为平方和,请参见。另请参见。我正在三维空间中设计8条贝塞尔曲线