【问题标题】:Resuming an optimization in scipy.optimize?恢复 scipy.optimize 中的优化?
【发布时间】:2017-02-21 11:11:25
【问题描述】:

scipy.optimize 为多元系统的局部和全局优化提供了许多不同的方法。但是,我需要很长时间的优化运行,可能会被中断(在某些情况下,我可能想故意中断它)。有没有办法重新启动......好吧,他们中的任何一个?我的意思是,显然可以提供最后一组最优化的参数作为初始猜测,但这不是唯一起作用的参数 - 例如,还有梯度(例如雅可比)、差异进化中的种群等. 我显然不希望这些也必须重新开始。

我看不到向 scipy 证明这些的方法,也没有办法保存它的状态。例如,对于采用 jacobian 的函数,有一个 jacobian 参数(“jac”),但它要么是一个布尔值(表示您的评估函数返回一个 jacobian,而我的没有),要么是一个可调用函数(我只会提供上次运行的单一结果)。没有什么只需要最后一个可用的雅可比数组。并且随着差异化进化,种群的损失对于性能和收敛性来说将是可怕的。

有什么解决办法吗?有什么办法可以恢复优化?

【问题讨论】:

  • 我想出的最好的方法几乎是难以想象的丑陋:fork 进程以创建一个或多个“断点”版本(具有当前运行的优化函数的精确副本的进程 - 以及整个应用程序在那!)并让断点版本挂在优化器的回调或评估调用中,直到通过某种 IPC 发出继续前进的信号,或者如果变得过时则被杀死。当然,您不能在“运行”之间更改参数,因为它们仍然是相同的运行!也不会通过重启持续存在。而且太丑了……
  • 1) 如果 jac 是您的函数,您可以很容易地告诉它在第一次调用时加载并返回 xx.jac,并带有 *kwarg。 2)具体是哪个优化器,差分进化? 3)你想要一个运行树,你想运行一段时间,单独打印/绘图/保存?大订单;示例命令序列:“A10 = 运行 10;A100 = 运行至 100;B = (A; params = ...;运行 100) ...”需要澄清。
  • 我还没有对不同的优化方法进行基准测试,以确定哪一种最适合我;我一直在调整我的评估函数以提高性能和准确性。例如,我不知道它会陷入多少局部最小值。 “jac”不是我的评估函数,它是最小化函数用来指定如何确定雅可比(一阶导数/梯度)的参数。一棵运行树会很好,但即使只维护一个检查点也很棒。如何在 scipy 中保留一个并“运行 100 次”迭代?
  • 我一直在尝试设计我的参数,以便可以以一种不会产生无意义结果的方式进行交叉(也就是尝试创建尽可能相互独立的参数)以防我需要使用差异进化。但是差分进化往往比局部最小值不成问题的梯度方法慢。所以这又取决于梯度方法收敛的好坏。我也希望能够并行运行,但 scipy 似乎也不支持...
  • 为了记录(刚刚碰到这个旧线程),我找到了一个非常简单的恢复方法:缓存最小化函数的所有结果,以函数参数为键。保存缓存并在重新启动时加载它。在最小化函数的开头添加一个检查,以查看它之前是否运行过。就是这样,完成了。给定相同的参数和相同的返回结果,最小化和差分进化将重新制定与以前完全相同的步骤,只是由于缓存而以闪电般的速度。 :)

标签: python scipy mathematical-optimization


【解决方案1】:

一般的答案是否定的,除了正如你所说的,从上次运行的最后估计开始,没有一般的解决方案。

不过,对于差分进化,您可以实例化DifferentialEvolutionSolver,您可以在检查点腌制并取消腌制以恢复。 (建议来自https://github.com/scipy/scipy/issues/6517

【讨论】:

    【解决方案2】:

    以下可以保存并从以前的x重新启动, 但我想你想保存并重新启动更多状态,例如渐变;你能澄清一下吗?

    另见basinhopping, 它有一个漂亮的 gui,pele-python

    #!/usr/bin/env python
    """ Funcgradmn: wrap f() and grad(), save all x[] f[] grad[] to plot or restart """
    
    from __future__ import division
    import numpy as np
    
    __version__ = "2016-10-18 oct denis"
    
    
    class Funcgradmon(object):
        """ Funcgradmn: wrap f() and grad(), save all x[] f[] grad[] to plot or restart
    
        Example: minimize, save, restart --
    
        fg = Funcgradmon( func, gradfunc, verbose=1 )
            # fg(x): f(x), g(x)  for minimize( jac=True )
    
            # run 100 iter (if linesearch, 200-300 calls of fg()) --
        options = dict( maxiter=100 )  # ... 
        min0 = minimize( fg, x0, jac=True, options=options )
        fg.savez( "0.npz", paramstr="..." )  # to plot or restart
    
            # restart from x[50] --
            # (won't repeat the previous path from 50
            # unless you save and restore the whole state of the optimizer)
        x0 = fg.restart( 50 )
        # change params ...
        min50 = minimize( fg, x0, jac=True, options=options )
        """
    
        def __init__( self, func, gradfunc, verbose=1 ):
            self.func = func
            self.gradfunc = gradfunc
            self.verbose = verbose
            self.x, self.f, self.g = [], [], []  # growing lists
            self.t = 0
    
        def __call__( self, x ):
            """ f, g = func(x), gradfunc(x); save them; return f, g """
            x = np.asarray_chkfinite( x )  # always
            f = self.func(x)
            g = self.gradfunc(x)
            g = np.asarray_chkfinite( g )
            self.x.append( np.copy(x) )
            self.f.append( _copy( f ))
            self.g.append( np.copy(g) )
            if self.verbose:
                print "%3d:" % self.t ,
                fmt = "%-12g" if np.isscalar(f)  else "%s\t"
                print fmt % f ,
                print "x: %s" % x ,  # with user's np.set_printoptions
                print "\tgrad: %s" % g
                    # better df dx dg
            # callback: plot
            self.t += 1
            return f, g
    
        def restart( self, n ):
            """ x0 = fg.restart( n )  returns x[n] to minimize( fg, x0 )
            """
            x0 = self.x[n]  # minimize from here
            del self.x[:n]
            del self.f[:n]
            del self.g[:n]
            self.t = n
            if self.verbose:
                print "Funcgradmon: restart from x[%d] %s" % (n, x0)
            return x0
    
        def savez( self, npzfile, **kw ):
            """ np.savez( npzfile, x= f= g= ) """
            x, f, g = map( np.array, [self.x, self.f, self.g] )
            if self.verbose:
                asum = "f: %s \nx: %s \ng: %s" % (
                    _asum(f), _asum(x), _asum(g) )
                print "Funcgradmon: saving to %s: \n%s \n" % (npzfile, asum)
            np.savez( npzfile, x=x, f=f, g=g, **kw )
    
        def load( self, npzfile ):
            load = np.load( npzfile )
            x, f, g = load["x"], load["f"], load["g"]
            if self.verbose:
                asum = "f: %s \nx: %s \ng: %s" % (
                    _asum(f), _asum(x), _asum(g) )
                print "Funcgradmon: load %s: \n%s \n" % (npzfile, asum)
            self.x = list( x )
            self.f = list( f )
            self.g = list( g )
            self.loaddict = load
            return self.restart( len(x) - 1 )
    
    
    def _asum( X ):
        """ one-line array summary: "shape type min av max" """
        if not hasattr( X, "dtype" ):
            return str(X)
        return "%s %s  min av max %.3g %.3g %.3g" % (
                X.shape, X.dtype, X.min(), X.mean(), X.max() )
    
    def _copy( x ):
        return x if x is None  or np.isscalar(x) \
            else np.copy( x )
    
    #...............................................................................
    if __name__ == "__main__":
        import sys
        from scipy.optimize import minimize, rosen, rosen_der
    
        np.set_printoptions( threshold=20, edgeitems=10, linewidth=140,
                formatter = dict( float = lambda x: "%.3g" % x ))  # float arrays %.3g
    
        dim = 3
        method = "cg"
        maxiter = 10  # 1 linesearch -> 2-3 calls of fg
    
        # to change these params, run this.py a=1 b=None 'c = ...'  in sh or ipython
        for arg in sys.argv[1:]:
            exec( arg )
    
        print "\n", 80 * "-"
        print "Funcgradmon: dim %d  method %s  maxiter %d \n" % (
                dim, method, maxiter )
        x0 = np.zeros( dim )
    
        #...........................................................................
        fg = Funcgradmon( rosen, rosen_der, verbose=1 )
        options = dict( maxiter=maxiter )  # ... 
    
        min0 = minimize( fg, x0, jac=True, method=method, options=options )
        fg.savez( "0.npz", paramstr="..." )  # to plot or restart
    
        x0 = fg.restart( 5 )  # = fg.x[5]
        # change params, print them all
        min5 = minimize( fg, x0, jac=True, method=method, options=options )
    
        fg.savez( "5.npz", paramstr="..." )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-22
      • 2012-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-05
      • 2020-05-16
      相关资源
      最近更新 更多