在 scipy.optimize 中恢复优化?
Resuming an optimization in scipy.optimize?
scipy.optimize 介绍了许多不同的方法来对多变量系统进行局部和全局优化。然而,我有一个很长的优化需要 运行 可能会被打断(在某些情况下我可能想故意打断它)。有什么办法可以重新启动……好吧,其中任何一个?我的意思是,显然可以提供最后一组最优化的参数作为初始猜测,但这并不是唯一的参数——例如,还有梯度(例如雅可比矩阵)、差分进化中的种群等.我显然不希望这些也必须重新开始。
我看不出有什么方法可以向 scipy 证明这些,也没有办法保存它的状态。对于以 jacobian 为例的函数,有一个 jacobian 参数 ("jac"),但它要么是一个布尔值(表明你的评估函数 returns 是一个 jacobian,而我的不是),或者一个可调用函数(我只会得到最后一个 运行 提供的单一结果)。没有什么只需要最后一个可用的 jacobian 数组。并且随着差异进化,人口的减少对于性能和收敛来说是可怕的。
有什么解决办法吗?有什么方法可以恢复优化吗?
一般的答案是否定的,除了如你所说,从上次运行.
的最后估计开始,没有一般的解决方案。
不过,对于差异进化而言,您可以实例化 DifferentialEvolutionSolver
,您可以在检查点对其进行 pickle,然后 unpickle 以恢复。
(建议来自https://github.com/scipy/scipy/issues/6517)
以下可以保存并从上一个x
重新开始,
但我知道你想保存并重新启动更多状态,例如渐变也是;你能澄清一下吗?
另见 basinhopping,
它有一个漂亮的图形用户界面 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="..." )
scipy.optimize 介绍了许多不同的方法来对多变量系统进行局部和全局优化。然而,我有一个很长的优化需要 运行 可能会被打断(在某些情况下我可能想故意打断它)。有什么办法可以重新启动……好吧,其中任何一个?我的意思是,显然可以提供最后一组最优化的参数作为初始猜测,但这并不是唯一的参数——例如,还有梯度(例如雅可比矩阵)、差分进化中的种群等.我显然不希望这些也必须重新开始。
我看不出有什么方法可以向 scipy 证明这些,也没有办法保存它的状态。对于以 jacobian 为例的函数,有一个 jacobian 参数 ("jac"),但它要么是一个布尔值(表明你的评估函数 returns 是一个 jacobian,而我的不是),或者一个可调用函数(我只会得到最后一个 运行 提供的单一结果)。没有什么只需要最后一个可用的 jacobian 数组。并且随着差异进化,人口的减少对于性能和收敛来说是可怕的。
有什么解决办法吗?有什么方法可以恢复优化吗?
一般的答案是否定的,除了如你所说,从上次运行.
的最后估计开始,没有一般的解决方案。不过,对于差异进化而言,您可以实例化 DifferentialEvolutionSolver
,您可以在检查点对其进行 pickle,然后 unpickle 以恢复。
(建议来自https://github.com/scipy/scipy/issues/6517)
以下可以保存并从上一个x
重新开始,
但我知道你想保存并重新启动更多状态,例如渐变也是;你能澄清一下吗?
另见 basinhopping, 它有一个漂亮的图形用户界面 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="..." )