如何将成本,grad作为scipy的fmin_cg函数的元组返回

时间:2013-07-02 16:38:27

标签: python scipy fminsearch

如何让scipy的fmin_cg使用一个返回costgradient作为元组的函数?成本f和渐变fprime的问题在于我可能需要执行两次(非常昂贵)的操作,通过该操作计算gradcost 。此外,在它们之间共享变量可能很麻烦。

然而,在Matlab中,fmin_cg使用一个函数来返回成本和渐变作为元组。我不明白为什么scipy的fmin_cg无法提供这样的便利。

提前致谢...

1 个答案:

答案 0 :(得分:6)

您可以将scipy.optimize.minimizejac=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