如何让scipy的fmin_cg
使用一个返回cost
和gradient
作为元组的函数?成本f
和渐变fprime
的问题在于我可能需要执行两次(非常昂贵)的操作,通过该操作计算grad
和cost
。此外,在它们之间共享变量可能很麻烦。
然而,在Matlab中,fmin_cg
使用一个函数来返回成本和渐变作为元组。我不明白为什么scipy的fmin_cg
无法提供这样的便利。
提前致谢...
答案 0 :(得分:6)
您可以将scipy.optimize.minimize
与jac=True
一起使用。如果出于某种原因这不是一个选项,那么您可以查看how it handles this situation:
class MemoizeJac(object):
""" Decorator that caches the value gradient of function each time it
is called. """
def __init__(self, fun):
self.fun = fun
self.jac = None
self.x = None
def __call__(self, x, *args):
self.x = numpy.asarray(x).copy()
fg = self.fun(x, *args)
self.jac = fg[1]
return fg[0]
def derivative(self, x, *args):
if self.jac is not None and numpy.alltrue(x == self.x):
return self.jac
else:
self(x, *args)
return self.jac
此类包装一个返回函数值和渐变的函数,保留单元素缓存并检查它是否已知道其结果。用法:
fmemo = MemoizeJac(f, fprime)
xopt = fmin_cg(fmemo, x0, fmemo.derivative)
此代码的一个奇怪之处在于它假定f
之前始终会调用fprime
(但不是每个f
调用都会跟fprime
调用)。我不确定scipy.optimize
是否真正保证了这一点,但代码可以很容易地适应不做出这个假设。以上的强大版本(未经测试):
class MemoizeJac(object):
def __init__(self, fun):
self.fun = fun
self.value, self.jac = None, None
self.x = None
def _compute(self, x, *args):
self.x = numpy.asarray(x).copy()
self.value, self.jac = self.fun(x, *args)
def __call__(self, x, *args):
if self.value is not None and numpy.alltrue(x == self.x):
return self.value
else:
self._compute(x, *args)
return self.value
def derivative(self, x, *args):
if self.jac is not None and numpy.alltrue(x == self.x):
return self.jac
else:
self._compute(x, *args)
return self.jac