Python 用Nelder-Mead最小化非凸函数

Python 用Nelder-Mead最小化非凸函数,python,python-2.7,scipy,mathematical-optimization,nonlinear-optimization,Python,Python 2.7,Scipy,Mathematical Optimization,Nonlinear Optimization,我正在使用默认方法('Neldear-Mead')使用scipy.optimize.minimize。 我试图最小化的函数不是严格凸的。它在一些重要区域保持相同的值 我遇到的问题是,该算法所采取的步骤太小。例如,我的起点有一个第一坐标x0=0.2。我知道该函数只会对重要的一步产生不同的值,例如移动0.05。不幸的是,我可以看到该算法的步长非常小(移动了大约0.000001)。结果,我的函数返回相同的值,并且算法不收敛。我能改变这种行为吗 为方便起见,以下是scipy代码: def _minimi

我正在使用默认方法('Neldear-Mead')使用
scipy.optimize.minimize
。 我试图最小化的函数不是严格凸的。它在一些重要区域保持相同的值

我遇到的问题是,该算法所采取的步骤太小。例如,我的起点有一个第一坐标
x0=0.2
。我知道该函数只会对重要的一步产生不同的值,例如移动0.05。不幸的是,我可以看到该算法的步长非常小(移动了大约0.000001)。结果,我的函数返回相同的值,并且算法不收敛。我能改变这种行为吗

为方便起见,以下是scipy代码:

def _minimize_neldermead(func, x0, args=(), callback=None,
                         xtol=1e-4, ftol=1e-4, maxiter=None, maxfev=None,
                         disp=False, return_all=False,
                         **unknown_options):
    """
    Minimization of scalar function of one or more variables using the
    Nelder-Mead algorithm.

    Options for the Nelder-Mead algorithm are:
        disp : bool
            Set to True to print convergence messages.
        xtol : float
            Relative error in solution `xopt` acceptable for convergence.
        ftol : float
            Relative error in ``fun(xopt)`` acceptable for convergence.
        maxiter : int
            Maximum number of iterations to perform.
        maxfev : int
            Maximum number of function evaluations to make.

    This function is called by the `minimize` function with
    `method=Nelder-Mead`. It is not supposed to be called directly.
    """
    _check_unknown_options(unknown_options)
    maxfun = maxfev
    retall = return_all

    fcalls, func = wrap_function(func, args)
    x0 = asfarray(x0).flatten()
    N = len(x0)
    rank = len(x0.shape)
    if not -1 < rank < 2:
        raise ValueError("Initial guess must be a scalar or rank-1 sequence.")
    if maxiter is None:
        maxiter = N * 200
    if maxfun is None:
        maxfun = N * 200

    rho = 1
    chi = 2
    psi = 0.5
    sigma = 0.5
    one2np1 = list(range(1, N + 1))

    if rank == 0:
        sim = numpy.zeros((N + 1,), dtype=x0.dtype)
    else:
        sim = numpy.zeros((N + 1, N), dtype=x0.dtype)
    fsim = numpy.zeros((N + 1,), float)
    sim[0] = x0
    if retall:
        allvecs = [sim[0]]
    fsim[0] = func(x0)
    nonzdelt = 0.05
    zdelt = 0.00025
    for k in range(0, N):
        y = numpy.array(x0, copy=True)
        if y[k] != 0:
            y[k] = (1 + nonzdelt)*y[k]
        else:
            y[k] = zdelt

        sim[k + 1] = y
        f = func(y)
        fsim[k + 1] = f

    ind = numpy.argsort(fsim)
    fsim = numpy.take(fsim, ind, 0)
    # sort so sim[0,:] has the lowest function value
    sim = numpy.take(sim, ind, 0)

    iterations = 1

    while (fcalls[0] < maxfun and iterations < maxiter):
        if (numpy.max(numpy.ravel(numpy.abs(sim[1:] - sim[0]))) <= xtol and
                numpy.max(numpy.abs(fsim[0] - fsim[1:])) <= ftol):
            break

        xbar = numpy.add.reduce(sim[:-1], 0) / N
        xr = (1 + rho) * xbar - rho * sim[-1]
        fxr = func(xr)
        doshrink = 0

        if fxr < fsim[0]:
            xe = (1 + rho * chi) * xbar - rho * chi * sim[-1]
            fxe = func(xe)

            if fxe < fxr:
                sim[-1] = xe
                fsim[-1] = fxe
            else:
                sim[-1] = xr
                fsim[-1] = fxr
        else:  # fsim[0] <= fxr
            if fxr < fsim[-2]:
                sim[-1] = xr
                fsim[-1] = fxr
            else:  # fxr >= fsim[-2]
                # Perform contraction
                if fxr < fsim[-1]:
                    xc = (1 + psi * rho) * xbar - psi * rho * sim[-1]
                    fxc = func(xc)

                    if fxc <= fxr:
                        sim[-1] = xc
                        fsim[-1] = fxc
                    else:
                        doshrink = 1
                else:
                    # Perform an inside contraction
                    xcc = (1 - psi) * xbar + psi * sim[-1]
                    fxcc = func(xcc)

                    if fxcc < fsim[-1]:
                        sim[-1] = xcc
                        fsim[-1] = fxcc
                    else:
                        doshrink = 1

                if doshrink:
                    for j in one2np1:
                        sim[j] = sim[0] + sigma * (sim[j] - sim[0])
                        fsim[j] = func(sim[j])

        ind = numpy.argsort(fsim)
        sim = numpy.take(sim, ind, 0)
        fsim = numpy.take(fsim, ind, 0)
        if callback is not None:
            callback(sim[0])
        iterations += 1
        if retall:
            allvecs.append(sim[0])

    x = sim[0]
    fval = numpy.min(fsim)
    warnflag = 0

    if fcalls[0] >= maxfun:
        warnflag = 1
        msg = _status_message['maxfev']
        if disp:
            print('Warning: ' + msg)
    elif iterations >= maxiter:
        warnflag = 2
        msg = _status_message['maxiter']
        if disp:
            print('Warning: ' + msg)
    else:
        msg = _status_message['success']
        if disp:
            print(msg)
            print("         Current function value: %f" % fval)
            print("         Iterations: %d" % iterations)
            print("         Function evaluations: %d" % fcalls[0])

    result = OptimizeResult(fun=fval, nit=iterations, nfev=fcalls[0],
                            status=warnflag, success=(warnflag == 0),
                            message=msg, x=x)
    if retall:
        result['allvecs'] = allvecs
    return result
def\u minimize\u neldermead(func,x0,args=(),callback=None,
xtol=1e-4,ftol=1e-4,maxiter=None,maxfev=None,
disp=False,return\u all=False,
**未知选项):
"""
使用函数最小化一个或多个变量的标量函数
内尔德-米德算法。
Nelder-Mead算法的选项包括:
disp:bool
设置为True可打印聚合消息。
xtol:浮动
解“xopt”中的相对误差可接受收敛。
ftol:浮动
“fun(xopt)”中的相对误差可接受收敛。
maxiter:int
要执行的最大迭代次数。
maxfev:int
要进行的最大功能评估数。
此函数由带有
`method=Nelder-Mead`。不应该直接调用它。
"""
_检查未知选项(未知选项)
maxfun=maxfev
retail=返回所有
fcall,func=wrap_函数(func,args)
x0=asfarray(x0).展平()
N=len(x0)
秩=len(x0.shape)
如果不是-1if(numpy.max(numpy.ravel(numpy.abs(sim[1:]-sim[0]))我很久以前就用过Nelder-Mead,但我记得如果你从不同的起点出发,你会发现不同的局部极小值。你没有给我们你的函数,所以我们只能猜测什么应该是对你最好的策略。你也应该阅读这篇文章


http://www.webpages.uidaho.edu/~fuchang/res/ANMS.pdf
根据我对纳尔-米德的经验,它们很好地处理凸问题,但不适用于一般用途的非凸问题。如果不确切知道将要使用纳尔-米德的参数空间,很难说是否总是将其移动0.05一个解决方案。这很有意义。你对非凸函数有什么建议吗?这个函数由你来定义。从你的描述中,至少有一个区域有一个平坦的平台。也有局部极小值吗?内尔德-米德的伟大之处在于它是非常物理的。你可以毫不夸张地把它想象成沿着一个物理层流动的水ical景观。对不起,我不清楚。我肯定有我的非凸函数,有几个局部极小值(我不担心,我只会注入几个好的起点)。我的意思是你对最小化算法有什么建议吗?有两种主要方法:确定性和随机全局优化。这两个领域都包含许多非常有趣的想法/启发式。我不是专家,但如果我有全局优化问题,我会试着理解参数spac的总体布局e、 然后选择我希望如何解决这个问题。这可能是一种混合方法,将不同的技术/算法结合在一起。谢谢你的帮助。我知道有不同的局部极小值,我会处理好的。我会浏览你的链接。