scipy 如何使用盆跳跃来写参数的界限?

7tofc5zh  于 2022-11-10  发布在  其他
关注(0)|答案(3)|浏览(269)

我在编写basinhopping中的参数边界时遇到了困难。

(x0)=(a, b, c )

a = (0, 100)

b = (0, 0.100)

c = (0, 10)

from scipy.optimize import basinhopping

minimizer_kwargs = { "method": "Nelder-Mead" }

min = basinhopping(rmse, x0, minimizer_kwargs=minimizer_kwargs, T=0.5, stepsize=0.1, niter=200, disp=True)
ws51t4hk

ws51t4hk1#

有多种方法可以解决这个问题,每种方法的表现都可能不同(在非凸全局优化中很常见)。最好的方法总是考虑关于优化问题的先验信息!

最稳健的一般方法(在我看来也是最好的方法)是以下方法的组合:
***A:**内层:有界约束局部搜索
***B:**外部级别:有界约束步骤

这个优化器的原作者说,只依赖于A(就像现在在其他两个答案中所做的那样)might fail
编码:

import numpy as np
from scipy.optimize import basinhopping

""" Example problem
    https://docs.scipy.org/doc/scipy-0.19.1/reference/generated/scipy.optimize.basinhopping.html
"""
def func2d(x):
    f = np.cos(14.5 * x[0] - 0.3) + (x[1] + 0.2) * x[1] + (x[0] + 0.2) * x[0]
    df = np.zeros(2)
    df[0] = -14.5 * np.sin(14.5 * x[0] - 0.3) + 2. * x[0] + 0.2
    df[1] = 2. * x[1] + 0.2
    return f, df

""" Example bounds """
bx0 = (-0.175, 1.)
bx1 = (-0.09, 1.)
bounds = [bx0, bx1]

""" Solve without bounds """
minimizer_kwargs = {"method":"L-BFGS-B", "jac":True}
x0 = [1.0, 1.0]
ret = basinhopping(func2d, x0, minimizer_kwargs=minimizer_kwargs, niter=200)
print(ret.message)
print("unconstrained minimum: x = [%.4f, %.4f], f(x0) = %.4f" % (ret.x[0], ret.x[1],ret.fun))

""" Custom step-function """
class RandomDisplacementBounds(object):
    """random displacement with bounds:  see: https://stackoverflow.com/a/21967888/2320035
        Modified! (dropped acceptance-rejection sampling for a more specialized approach)
    """
    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 """
        min_step = np.maximum(self.xmin - x, -self.stepsize)
        max_step = np.minimum(self.xmax - x, self.stepsize)

        random_step = np.random.uniform(low=min_step, high=max_step, size=x.shape)
        xnew = x + random_step

        return xnew

bounded_step = RandomDisplacementBounds(np.array([b[0] for b in bounds]), np.array([b[1] for b in bounds]))

""" Custom optimizer """
minimizer_kwargs = {"method":"L-BFGS-B", "jac":True, "bounds": bounds}

""" Solve with bounds """
x0 = [1.0, 1.0]
ret = basinhopping(func2d, x0, minimizer_kwargs=minimizer_kwargs, niter=200, take_step=bounded_step)
print(ret.message)
print("constrained minimum: x = [%.4f, %.4f], f(x0) = %.4f" % (ret.x[0], ret.x[1],ret.fun))

输出量:

['requested number of basinhopping iterations completed successfully']
unconstrained minimum: x = [-0.1951, -0.1000], f(x0) = -1.0109
['requested number of basinhopping iterations completed successfully']
constrained minimum: x = [-0.1750, -0.0900], f(x0) = -0.9684
ttygqcqt

ttygqcqt2#

您应该在minimizer_kwargs中使用"bounds"参数,该参数将传递给scipy.optimize.minimize()。以下是一个示例:

bnds = ((1, 100), (1, 100), (1,100))# your bounds

def rmse(X):# your function
    a,b,c = X[0],X[1],X[2]
    return a**2+b**2+c**2

x0 = [10., 10., 10.]
minimizer_kwargs = { "method": "L-BFGS-B","bounds":bnds }
ret = basinhopping(rmse, x0, minimizer_kwargs=minimizer_kwargs,niter=10)
print("global minimum: a = %.4f, b = %.4f c = %.4f | f(x0) = %.4f" % (ret.x[0], ret.x[1], ret.x[2], ret.fun))

其结果是
全局最小值:a = 1.0000,B = 1.0000,c = 1.0000| f(x0)= 3.0000
没有边界它是(清晰的)0,0,0

e4eetjau

e4eetjau3#

我知道这个问题是旧的(公认的答案是从大约5年前),我希望我可以评论它,而不是提供一个新的“答案”(我缺乏这样做的声誉,不幸的是),但我想要求一些澄清的公认答案提供的@sascha 11月1日,2017.
具体地说,通过查看class RandomDisplacementBounds(object)的函数__call__的代码,我不明白为什么 x_new 被定义为xnew = x + random_step而不是简单地定义为xnew = random_step
我的推理是,如果传递给函数__init__xminxmax确实是向量 x 的上界和下界,并且random_step是从xminxmax之间的均匀分布中随机抽取的点,那么所谓的random_step就是本地优化例程的新点。这是真的吗?我将非常感谢任何关于这方面的帮助。

相关问题