如何定义 Scipy.Optimize.Minimize 的导数

计算科学 优化 Python 凸优化 scipy 二次规划
2021-12-06 16:31:52

我正在尝试使用scipy.optimize.minimize来最小化二次目标函数:f(x)=xQx. 首先,我通过定义一个函数,使用内置的 Nelder-Mead Simplex 算法成功地实现了这一点:

def objective(x):
    Q = np.asmatrix(DF.cov())       # Covariance matrix
    x = np.asmatrix(x)
    return x.transpose() * Q * x 

传递给 SciPy 的最小化函数:

minimize(objective, x0, method='Nelder-Mead',options={'xtol': 1e-6, 'disp': True})

现在,按照上面链接中的文档,还有许多其他可用的优化例程,我想尝试一下。其中每一个都需要计算函数导数,f(x),必须写在类似于上面的python函数里面,有的需要Hessian2f(x). 我最初的尝试如下:

def der_objective(x):
    Q = np.asmatrix(DF.cov())       # Covariance matrix
    x = np.asmatrix(x).reshape(len(Q),1)
    return 2 * Q * x 

但这显然会返回错误的尺寸。我不完全确定 SciPy 如何期望结果,并且无法从教程中的 Rosenbrock 示例中解决

您能否解释一下 SciPy 教程中的 rosen_der 示例是如何工作的(例如,为什么它对给定的xj? 形状相同的向量?)以及我应该如何设计我的 der_objective(x) 函数来实现相同的目标?x

1个回答

如果您忽略链接到的教程中的数学公式,只看调用本身,

res = minimize(rosen, x0, method='BFGS', jac=rosen_der, ... options={'disp': True})

定义了两个python函数。一种是标量泛f(x)

def rosen(x): ... """The Rosenbrock function""" ... return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0)

另一个是向量梯度函数,

f(x)=(fx0|x,,fxn1|x)T,

它的大小自动与相同。x

def rosen_der(x): ... xm = x[1:-1] ... xm_m1 = x[:-2] ... xm_p1 = x[2:] ... der = np.zeros_like(x) ... der[1:-1] = 200*(xm-xm_m1**2) - 400*(xm_p1 - xm**2)*xm - 2*(1-xm) ... der[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0]) ... der[-1] = 200*(x[-1]-x[-2]**2) ... return der

就代码而言,这是故意写成与相同的形式,以便迭代最小化例程可以形成像以便变量可以通过向量的连续迭代将“下坡”移动到局部最小值(注意仅使用最后一个答案是方法“最陡下降”,没有人会使用选择在课堂外使用)。希望这对您来说不会太令人惊讶。如果是这样,您可能需要阅读更多关于基于梯度的理论在回到你的编码之前进行优化。x

x(n+1=xnαf(xn)
x

就您的实际代码而言,使用带有 numpy.dot 的基本数组来执行矩阵乘法就足够了,而不是将所有内容编写为矩阵(numpy 生成 2d),或者如果您真的想在函数中保留这种风格,返回结果时使用numpy.asarrayand 。numpy.ravel在最坏的情况下,您需要仔细检查您的矩阵是否为并且您将设为列向量(正如我之前所说的那样)。QN×Nxasmatrix