Python 使用scipy.optimize.minimize查找全局最小值

Python 使用scipy.optimize.minimize查找全局最小值,python,algorithm,scipy,minimize,Python,Algorithm,Scipy,Minimize,给定一个2D点p,我试图计算该点和函数曲线之间的最小距离,也就是说,在曲线上找到给我到p最小距离的点,然后计算该距离。我使用的示例函数是 f(x) = 2*sin(x) 某个点p与提供的函数之间的距离的My distance函数为 def dist(p, x, func): x = np.append(x, func(x)) return sum([[i - j]**2 for i,j in zip(x,p)]) 它将点p、函数上的位置x和函数手柄func作为输入。注意这是一

给定一个2D点
p
,我试图计算该点和函数曲线之间的最小距离,也就是说,在曲线上找到给我到
p
最小距离的点,然后计算该距离。我使用的示例函数是

f(x) = 2*sin(x)
某个点
p
与提供的函数之间的距离的My distance函数为

def dist(p, x, func):
    x = np.append(x, func(x))
    return sum([[i - j]**2 for i,j in zip(x,p)])
它将点
p
、函数上的位置
x
和函数手柄
func
作为输入。注意这是一个平方欧几里德距离(因为在欧几里德空间中最小化与在平方欧几里德空间中最小化相同)

这其中的关键部分是,我希望能够为我的函数提供边界,这样我才能找到离函数段最近的距离。对于这个例子,我的界限是

bounds = [0, 2*np.pi]
我正在使用
scipy.optimize.minimize
函数来最小化距离函数,使用边界。上述过程的结果如下图所示

这是一个等高线图,显示了与sin函数的距离。请注意,轮廓中似乎存在不连续性。为了方便起见,我在不连续点周围画了几个点,以及它们映射到的曲线上的“密室”点

这里实际发生的是,scipy函数正在寻找局部最小值(给出一些初始猜测),而不是全局最小值,这导致了不连续性。我知道找到任何函数的全局最小值是不可能的,但我正在寻找一种更可靠的方法来找到全局最小值

寻找全局最小值的可能方法如下:

  • 选择一个聪明的初始猜测,但这相当于大致知道全局最小值从何处开始,即使用问题的解决方案来解决它
  • 使用多个初始猜测,并选择达到最佳最小值的答案。然而,这似乎是一个糟糕的选择,尤其是当我的函数变得更复杂(更高维)时
  • 找到最小值,然后扰动解,再次找到最小值,希望我能把它推到一个更好的最小值。我希望有一种方法可以简单地做到这一点,而不需要使用复杂的MCMC算法或类似的东西。速度是这个过程的关键

  • 任何关于实现这一点的最佳方法的建议,或者关于可能解决此问题的有用函数的方向的建议都将是非常好的

    正如评论中所建议的,您可以尝试一种全局优化算法,例如
    scipy.optimize.differential\u evolution
    。然而,在这种情况下,如果您有一个定义良好且分析上易于处理的目标函数,您可以使用半分析方法,利用最小值的一阶必要条件


    在下文中,第一个函数是距离度量,第二个函数是其导数w.r.t.
    x
    ,如果在某个
    04处出现最小值,则该值应为零。使用模拟退火算法(或任何其他元启发式)。也许将优化调用限制在非常低的迭代次数内,获取解决方案并让SA决定是否接受该解决方案。再次优化5。使用不同的优化算法(随机选择、并行或竞争)。6.尝试像ipopt、bonmin、couenne这样的重元素(最后一个是全局解算器)
    
    import numpy as np    
    def d(x, p):
        return np.sum((p-np.array([x,2*np.sin(x)]))**2)
    
    def diff_d(x, p):
        return -2 * p[0] + 2 * x - 4 * p[1] * np.cos(x) + 4 * np.sin(2*x)
    
    import pychebfun
    def min_dist(p):
        f_cheb = pychebfun.Chebfun.from_function(lambda x: diff_d(x, p), domain = (0,2*np.pi))
        potential_minimizers = np.r_[0, f_cheb.roots(), 2*np.pi]
        return np.min([d(x, p) for x in potential_minimizers])