7

如何让 scipyfmin_cg使用一个返回costgradient作为元组的函数?具有f成本和fprime梯度的问题是,我可能必须执行两次计算gradand的操作(非常昂贵) cost。此外,在它们之间共享变量可能很麻烦。

然而,在 Matlab 中,fmin_cg使用一个将成本和梯度作为元组返回的函数。我不明白为什么 scipyfmin_cg不能提供这样的便利。

提前致谢...

4

1 回答 1

6

您可以scipy.optimize.minimize使用jac=True. 如果由于某种原因这不是一个选项,那么您可以查看它如何处理这种情况

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
于 2013-07-02T17:12:15.377 回答