'scipy.optimize.minimize中的Jacobian和Hessian输入`

2024-04-30 02:37:37 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图理解“dogleg”方法在Python的^{}函数中是如何工作的。我正在修改帮助页底部的示例。

根据注释,dogleg方法需要Jacobian和Hessian参数。为此,我使用^{}包:

import numpy as np
from scipy.optimize import minimize
from numdifftools import Jacobian, Hessian

def fun(x,a):
    return (x[0] - 1)**2 + (x[1] - a)**2

x0 = np.array([2,0]) # initial guess
a = 2.5

res = minimize(fun, x0, args=(a), method='dogleg',
               jac=Jacobian(fun)([2,0]), hess=Hessian(fun)([2,0]))

print(res)

编辑:

如果我按照下面的帖子的建议做出改变

res = minimize(fun, x0, args=a, method='dogleg',
               jac=Jacobian(lambda x: fun(x,a)),
               hess=Hessian(lambda x: fun(x,a)))

我得到一个错误TypeError: <lambda>() takes 1 positional argument but 2 were given。我做错什么了?

同样,在初始猜测x0时计算雅可比和海森是否正确?


Tags: 方法lambdafromimportnpargsresmethod
2条回答

这个错误来自对JacobianHessian的调用,而不是minimize。用Jacobian(lambda x: fun(x, a))替换Jacobian(fun)和类似的Hessian应该可以做到(因为现在被区分的函数只有一个向量参数)。

还有一件事:(a)就是a,如果你想让它成为元组,就使用(a,)

import numpy as np
from scipy.optimize import minimize
from numdifftools import Jacobian, Hessian

def fun(x, a):
    return (x[0] - 1) **2 + (x[1] - a) **2

def fun_der(x, a):
    return Jacobian(lambda x: fun(x, a))(x).ravel()

def fun_hess(x, a):
    return Hessian(lambda x: fun(x, a))(x)

x0 = np.array([2, 0]) # initial guess
a = 2.5

res = minimize(fun, x0, args=(a,), method='dogleg', jac=fun_der, hess=fun_hess)
print(res)

我知道这是一个有趣的例子,但我想指出,使用JacobianHessian这样的工具来计算导数而不是派生函数本身是相当昂贵的。例如,使用您的方法:

x0 = np.array([2, 0])
a = 2.5
%timeit minimize(fun, x0, args=(a,), method='dogleg', jac=fun_der, hess=fun_hess)
100 loops, best of 3: 13.6 ms per loop

但是你可以这样计算导数函数:

def fun_der(x, a):
    dx = 2 * (x[0] - 1)
    dy = 2 * (x[1] - a)
    return np.array([dx, dy]

def fun_hess(x, a):
    dx = 2
    dy = 2
    return np.diag([dx, dy])

%timeit minimize(fun, x0, args=(a,), method='dogleg', jac=fun_der, hess=fun_hess)
1000 loops, best of 3: 279 µs per loop

如你所见,速度快了将近50倍。它开始变得越来越复杂。因此,不管有多困难,我总是试图自己显式地导出函数。一个有趣的例子是Inductive Matrix Completion的基于内核的实现。

argmin --> sum((A - gamma_u(X) Z gamma_v(Y))**2 - lambda * ||Z||**2)
where gamma_u = (1/sqrt(m_x)) * [cos(UX), sin(UX)] and
gamma_v = (1/sqrt(m_y)) * [cos(VY), sin(VY)]
X.shape = n_x, p; Y.shape = n_y, q; U.shape = m_x, p; V.shape = m_y, q; Z.shape = 2m_x, 2m_y

与显式推导和利用这些函数相比,用这个方程计算梯度和hessian是极不合理的。所以正如@bnaul所指出的,如果你的函数有封闭形式的导数,你真的想计算和使用它们。

相关问题 更多 >