Scipy.optimize.l_bfgs_b:为什么它多次计算相同的函数值?
我现在正在尝试使用scipy.optimize来找到一个模拟的参数,这个模拟是为了拟合一些数据。我创建了一个函数,这个函数可以计算我的模型与数据之间的卡方值,这样scipy.optimize就可以最小化这个函数。
我遇到的一个主要问题是,这个模拟过程,以及调用的函数,耗时非常长。我发现L-BFGS_B(或者说BFGS)这个方法在同一个点上多次计算函数的值!!!我不明白为什么会这样,这让我很困扰。
这里有一个非常简单的函数的例子:
from scipy.optimize import minimize
def f3(x):
print x
return x[0]*x[0] + x[1]*x[1] + x[2]*x[2]
x0 = [3, -5, 7]
minimize(f3, x0, method = 'L-BFGS-B')
它会返回:
[ 3. -5. 7.]
[ 3. -5. 7.]
[ 3.00000001 -5. 7. ]
[ 3. -4.99999999 7. ]
[ 3. -5. 7.00000001]
[ 2.67070726 -4.45117871 6.23165016]
[ 2.67070726 -4.45117871 6.23165016]
[ 2.67070727 -4.45117871 6.23165016]
[ 2.67070726 -4.4511787 6.23165016]
[ 2.67070726 -4.45117871 6.23165017]
[ -1.72315050e-06 1.66152263e-06 -1.59989476e-06]
[ -1.72315050e-06 1.66152263e-06 -1.59989476e-06]
[ -1.71315050e-06 1.66152263e-06 -1.59989476e-06]
[ -1.72315050e-06 1.67152263e-06 -1.59989476e-06]
[ -1.72315050e-06 1.66152263e-06 -1.58989476e-06]
status: 0
success: True
nfev: 15
fun: 8.2895683293030033e-12
x: array([ -1.72315050e-06, 1.66152263e-06, -1.59989476e-06])
message: 'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
jac: array([ -3.43630101e-06, 3.33304526e-06, -3.18978951e-06])
nit: 2
从函数调用的打印结果中可以看到,minimize
在同一个x值上多次调用了f3。
这让我很沮丧,因为我觉得这样浪费了很多时间。
如果有人能给我一些启发,我会非常感激。谢谢。
2 个回答
0
它正在计算一个有限差分法来近似梯度。
3
之所以会这样,是因为它没有像你希望的那样小心。这种不足已经被记录在scipy的错误追踪系统中,具体可以查看这里。正如我在那边提到的,你可以通过自己缓存之前的值来解决这个问题。或者,你可以在调用minimize
时使用jac=True
,并让你的函数同时返回当前点的值和梯度。第一个方法的例子是:
import numpy as np
from scipy import optimize
class CacheLast(object):
def __init__(self, f):
self.f = f
self.last_x = None
self.last_f = None
self.ncall = 0
def __call__(self, x):
if np.all(x == self.last_x):
return self.last_f
else:
self.last_x = x
self.last_f = self.f(x)
self.ncall += 1
return self.last_f
def f3(x):
return x[0]*x[0] + x[1]*x[1] + x[2]*x[2]
x0 = [3, -5, 7]
func = CacheLast(f3)
res = optimize.minimize(func, x0, method='L-BFGS-B')
print 'total function calls: ', res.nfev
print 'actual function evals: ', func.ncall
这样会得到:
total function calls: 15
actual function evals: 12