问题描述
根据docs,如果jac
是布尔值且True
,则目标
假设函数 fun
返回 (f,grad)
,即目标值
和梯度。这有助于避免重复计算
目标和梯度中出现的项。
现在我想知道是否有类似的选择或方法来实现
对 hessian hess
相同,使得目标函数可以返回
元组 (f,grad,hess)
,其中 hess
是 Hessian 矩阵?
这是一个 MWE:
import numpy as np
from scipy.optimize import minimize
def obj_and_grad_and_hess(x):
obj = np.exp(x) * x**2
grad = obj + 2*np.exp(x)*x
hess = obj + 4*np.exp(x)*(x) + 2*np.exp(x)
return obj,hess
# res = minimize(obj_and_grad_and_hess,x0=[1.0],jac=True,hess=True)
这个问题是 类似于 this question,其中 jacobian 函数可以返回 jacobian 和 hessian。
解决方法
在幕后,scipy.optimize.minimize 使用 MemoizeJac
处理 jac=True
情况的装饰器。装饰器每次调用时都会缓存函数的返回值 f
和 grad
。通过继承这个类,您可以以同样的方式实现一个 MemoizeJacHess
装饰器:
from scipy.optimize.optimize import MemoizeJac
class MemoizeJacHess(MemoizeJac):
""" Decorator that caches the return vales of a function returning
(fun,grad,hess) each time it is called. """
def __init__(self,fun):
super().__init__(fun)
self.hess = None
def _compute_if_needed(self,x,*args):
if not np.all(x == self.x) or self._value is None or self.jac is None or self.hess is None:
self.x = np.asarray(x).copy()
self._value,self.jac,self.hess = self.fun(x,*args)
def hessian(self,*args):
self._compute_if_needed(x,*args)
return self.hess
但是,由于尚不支持 hess=True
选项,因此您必须
像这样使用它:
obj = MemoizeJacHess(obj_and_grad_and_hess)
grad = obj.derivative
hess = obj.hessian
res = minimize(obj,x0=[1.0],jac=grad,hess=hess)