<p>我知道这是一个有趣的例子,但我想指出,使用<code>Jacobian</code>或<code>Hessian</code>这样的工具来计算导数而不是派生函数本身是相当昂贵的。例如,使用您的方法:</p>
<pre><code>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
</code></pre>
<p>但是你可以这样计算导数函数:</p>
<pre><code>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
</code></pre>
<p>如你所见,速度快了将近50倍。它开始变得越来越复杂。因此,不管有多困难,我总是试图自己显式地导出函数。一个有趣的例子是<a href="http://bigdata.ices.utexas.edu/publication/1600/" rel="noreferrer">Inductive Matrix Completion</a>的基于内核的实现。</p>
<pre><code>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
</code></pre>
<p>与显式推导和利用这些函数相比,用这个方程计算梯度和hessian是极不合理的。所以正如@bnaul所指出的,如果你的函数有封闭形式的导数,你真的想计算和使用它们。</p>