在我对最小化问题的约束和它们的雅可比行列式之间有相当多的共享计算,以至于我几乎可以免费获得雅可比行列式。有什么办法可以共享计算吗?
最佳答案
由于约束和 jacobians 可能并不总是一起评估,因此您只能期望有较小的改进。但是如果你能把常用的计算放到一个单独的函数/方法中,你就可以 cache它的返回值,这样您以后就不需要重新计算它们了:
import scipy.optimize as opt
from functools import lru_cache
# only for the dummy example:
import scipy as sp
from time import sleep
def cost(x):
'''dummy cost function to minimize on [1,11]'''
return sp.log(x)
@lru_cache(maxsize=None) # careful with this choice
def heavy_stuff(x):
'''idle computation representing common work in constraint and jacobian'''
sleep(0.1)
return 0
def constraint(x):
'''constraint for [1,11], with simulated idle work'''
# the following only works for 1d arrays, needs more work for nd
throwaway = heavy_stuff(tuple(x))
return 5 - abs(6 - x) # non-negative between 1 and 11
def jacobian(x):
'''return the jacobiam with the same simulated idle work'''
throwaway = heavy_stuff(tuple(x))
return 1/x
x0 = 11
tol = 0
opts = {'disp': True}
cons = {'type': 'ineq', 'fun': constraint}
kwargs = {'method':'SLSQP', 'constraints': cons,
'jac': jacobian, 'tol': tol, 'options': opts}
res = opt.minimize(cost,x0,**kwargs)
print(heavy_stuff.cache_info())
上面的虚拟示例试图在区间 [1,11]
上最小化 log(x)
。我定义了一个给我们间隔的约束,而不是常量边界,这样我就可以展示我对你的问题的意思。
constraint
和 jacobian
做同样的工作,这是你想要备用的,以防对同一个参数进行多次评估。您必须将所有这些通用计算放入一个通用函数(此处命名为 heavy_stuff
),并在 constraint
和 jacobian
中处理返回值.
我的观点是你应该使用 functools.lru_cache
记住沉重的东西。通过设置适当的缓存大小,使用相同的 x
对 heavy_stuff
进行多次计算将立即为您提供先前计算的返回值,而无需重新计算。
如果我的怀疑是正确的,maxsize=1
可能在 lru_cache
装饰器中就足够了。设置 maxsize=None
(无上限)会造成无缘无故丢失过多内存的危险。您应该试验一下,看看是否需要多个内存值,或者几个或一个就足够了。
但是请注意,lru_cache
使用字典来查找先前计算的结果,其中键是修饰函数的输入参数。这意味着输入参数必须是可哈希的,这实际上意味着它们应该是不可变的。 Numpy 数组与列表非常相似,它们同样不可散列。这就是我们使用 tuple(x)
调用 heavy_stuff
的原因:一维数组输入被转换为元组。如果 x
是一个多维数组,那么每一层嵌套都必须转换为一个元组。更糟糕的是,heavy_stuff
几乎肯定必须将元组转换回 numpy ndarrays 才能完成繁重的工作。但是,如果计算 jacobian/constraint 真的是这种 CPU 密集型,那么您的整体情况可能仍然更好。
如果您想评估缓存的性能,您应该仔细查看最后打印的 heavy_stuff.cache_info()
。它会告诉您缓存值的使用频率,以及必须计算新值的次数。
关于python - scipy.optimize.minimize,一次计算约束及其雅可比,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42846648/