1

私はscipy.optimize.minimizeをデフォルトメソッド(Neldear-Mead)で使用しています。 私が最小化しようとする関数は厳密に凸ではありません。いくつかの重要な領域で同じ値にとどまります。Nelder-Meadで非凸関数を最小化する

私が持っている問題は、アルゴリズムの手順が小さすぎることです。たとえば、私の出発点は最初の座標が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 
+0

純粋なPython実装を試すことができ、彼らは凸問題でうまく動作しますが、汎用の非凸問題のために適していません。あなたがNelder Meadを使う予定のパラメータ空間を正確に知らなければ、それを0.05だけずらすことで常に解決策が得られるかどうかは言い難いでしょう。 – Spinor8

+0

それは理にかなっています。非凸関数の提案がありますか? – DevShark

+0

この関数は、あなたが定義するためのものです。あなたの説明から、少なくとも平らなプラトーがある地域があります。地元の最低基準はありますか? Nelder Meadの大きな点は、それが非常に物理的であることです。文字通り、物理的な景色を流れる水と考えることができます。 – Spinor8

答えて

1

、私はあなたがpoints.Youのdidnを開始する異なるから開始する場合は、別の極小値を見つけることを覚えています「tは私達にあなたの機能を与えるので、我々は唯一のyou.Youもこの

http://www.webpages.uidaho.edu/~fuchang/res/ANMS.pdf

をお読みくださいための最善の戦略はどうあるべきかを推測できました

は、その後、あなたがネルダミードとの私の経験から

https://github.com/fchollet/nelder-mead/blob/master/nelder_mead.py

+0

あなたのお手伝いをありがとうございます。私は異なった極小を持っていることを認識しており、私はそれを世話します。私はあなたのリンクを通過します。 – DevShark

関連する問題