我正在使用scipy.optimize.fmin_bfgs(f, init_theta, fprime)
to minimize f
,它有梯度fprime
。我在一个函数中计算f
和fprime
,因为大部分计算是相同的,所以不需要做两次。
有什么方法可以调用fmin_bfgs()
指定一个同时返回f
和的函数fprime
?
我正在使用scipy.optimize.fmin_bfgs(f, init_theta, fprime)
to minimize f
,它有梯度fprime
。我在一个函数中计算f
和fprime
,因为大部分计算是相同的,所以不需要做两次。
有什么方法可以调用fmin_bfgs()
指定一个同时返回f
和的函数fprime
?
如果您想节省计算时间而不是仅仅结合计算f
和f'
代码方便,似乎您需要一个额外的函数包装器来缓存值,因为fmin_bfgs
似乎不允许您传递这样的函数(与其他一些优化功能不同)。
这是一种方法,将最近评估的 10 个点保存在一个小缓存中。(我不确定对这个函数的调用是否需要是线程安全的:可能不需要,但如果是这样,你可能需要在这里添加一些锁定,我猜。)
def func_wrapper(f, cache_size=10):
evals = {}
last_points = collections.deque()
def get(pt, which):
s = pt.tostring() # get binary string of numpy array, to make it hashable
if s not in evals:
evals[s] = f(pt)
last_points.append(s)
if len(last_points) >= cache_size:
del evals[last_points.popleft()]
return evals[s][which]
return functools.partial(get, which=0), functools.partial(get, which=1)
如果我们这样做
>>> def f(x):
... print "evaluating", x
... return (x-3)**2, 2*(x-3)
>>> f_, fprime = func_wrapper(f)
>>> optimize.fmin_bfgs(f_, 1000, fprime)
evaluating [ 994.93480441]
evaluating [ 974.67402207]
evaluating [ 893.63089268]
evaluating [ 665.93446894]
evaluating [ 126.99931561]
evaluating [ 3.]
Optimization terminated successfully.
Current function value: 0.000000
Iterations: 4
Function evaluations: 7
Gradient evaluations: 7
array([ 3.])
我们可以看到我们没有重复任何评估。
假设你有一个 Python 函数f(x)
,它同时返回函数值和梯度:
In [20]: def f(x):
....: return (x-3)**2, 2*(x-3)
然后像这样单独传递输出:
In [21]: optimize.fmin_bfgs(lambda x: f(x)[0], 1000, lambda x: f(x)[1])
Optimization terminated successfully.
Current function value: 0.000000
Iterations: 4
Function evaluations: 7
Gradient evaluations: 7
Out[21]: array([ 3.])
似乎没有办法直接做到这一点。但scipy.optimize.minimize
确实让你这样做。您可以为 fprime 传递值 True 而不是函数。这表示 f 返回函数值和梯度的元组。您可以使用 method='BFGS' 调用minimize
以获得您想要的效果。
看看源代码是很有启发性的minimize
。it 和 fmin_bfgs 最终都会调用 _minimize_bfgs,它将 f 和 fprime 作为单独的函数参数。当 fprime 为布尔值时,minimize
巧妙地将 fprime 构造为一个对象,该对象记住 f 返回的最后一个值,并缓存梯度信息。