可以将目标函数和导数函数作为一个函数传递给scipy.optimize.minimize吗?
我正在尝试使用 scipy.optimize.minimize
来最小化一个复杂的函数。回想起来,我发现 minimize
这个函数需要把目标函数和导数函数作为两个不同的参数传入。不过,我已经定义了一个函数,它同时返回目标函数的值和一阶导数的值,因为这两个值是在一个 for
循环中同时计算的。我觉得要把我的这个函数分成两个部分,可能会导致程序实际上要运行同一个 for
循环两次,这样效率就不高了。
有没有办法把这个合并的函数传给 minimize
呢?
(顺便说一下,我正在写一个人工神经网络的反向传播算法,所以这个 for
循环是用来遍历训练数据的。目标函数和导数是同时累加的。)
2 个回答
是的,你可以在一个函数里同时传入它们:
import numpy as np
from scipy.optimize import minimize
def f(x):
return np.sin(x) + x**2, np.cos(x) + 2*x
sol = minimize(f, [0], jac=True, method='L-BFGS-B')
可能有一个方法可以解决这个问题:你可以使用“记忆化”这个技巧,也就是说,如果这个函数第二次被调用时输入是一样的,它会直接返回之前的结果,而不需要再进行计算。实际上,这个过程是在后台把结果存储起来了。在处理非线性程序时,可能会有成千上万次的调用,这就需要一个比较大的存储空间。通常使用记忆化的工具时,你可以设置一个存储限制,旧的结果会按照先进先出的原则被管理。换句话说,你在特定情况下仍然能充分利用这个技巧,因为只有在你需要返回函数值和导数时,输入才会是相同的。所以我想说的是,一个小的存储空间就足够了。
你没有说明你是使用 Python 2 还是 Python 3。如果你用的是 Python 3.2 及以上版本,你可以使用 functools.lru_cache 这个装饰器来实现记忆化。然后,你可以这样写代码:
@functools.lru_cache
def original_fn(x):
blah
return fnvalue, fnderiv
def new_fn_value(x):
fnvalue, fnderiv = original_fn(x)
return fnvalue
def new_fn_deriv(x):
fnvalue, fnderiv = original_fn(x)
return fnderiv
接着你把每个新函数传给 minimize
。虽然第二次调用会有一些额外的开销,但如果 x
没有变化,它就不会再进行计算。你需要了解一下在浮点数的上下文中,什么叫做 没有变化,特别是因为当最小化开始收敛时,x
的变化会变得很小。
如果你稍微查找一下,Python 2.x 也有很多关于记忆化的实现方法。
我说的这些有道理吗?