Python的scipy.optimize.minimize.最小化使用SLSQP失败,并使用“linesearch的正方向导数”

2024-10-01 15:44:44 发布

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

我有一个受不等式约束的最小二乘极小化问题,我试图用它来解决scipy.optimize.minimize.最小化. 对于不等式约束,似乎有两种选择:COBYLA和SLSQP。在

我第一次尝试SLSQP是因为它允许函数的显式偏导数最小化。根据问题的规模,它会失败并出现错误:

Positive directional derivative for linesearch    (Exit mode 8)

无论何时施加区间或更一般的不等式约束。在

这在以前已经观察到了,例如here。手动缩放要最小化的函数(以及相关的偏导数)似乎可以解决这个问题,但我无法通过在选项中更改ftol来达到相同的效果。在

总的来说,这整件事让我对日常工作的稳健方式产生了怀疑。下面是一个简化的例子:

^{pr2}$

如何设置ftol以避免失败?更一般地说,COBYLA会出现类似的问题吗?对于这类不等式约束的最小二乘优化问题,COBYLA是一个更好的选择吗?在

在成本函数中使用平方根可以提高性能。然而,对于问题的非线性重新参数化(更简单,但更接近我在实践中需要做的事情),它再次失败。具体情况如下:

import numpy as np
import scipy.optimize as sp_optimize


def cost(x, y, g):

    e = ((y - x[1]) / x[0]) - g

    rss = np.sqrt(np.sum(e ** 2))

    return rss


def cost_deriv(x, y, g):

    e = ((y- x[1]) / x[0]) - g

    factor = 0.5 / np.sqrt(e.dot(e))
    deriv0 = -2 * factor * e.dot(y - x[1]) / (x[0]**2)
    deriv1 = -2 * factor * np.sum(e) / x[0]

    deriv = np.array([deriv0, deriv1])

    return deriv


x_true = np.array([1/300, .1])
N = 20
t = 20 * np.arange(N)
g = 100 * np.cos(2 * np.pi * 1e-3 * (t - t[-1] / 2))
y = g * x_true[0] + x_true[1]

x_guess = x_true / 2
prm_bounds = ((1e-4, 1e-2), (0, .4))

# check derivatives
delta = 1e-9
C0 = cost(x_guess, y, g)
C1 = cost(x_guess + np.array([delta, 0]), y, g)
approx_deriv0 = (C1 - C0) / delta
C1 = cost(x_guess + np.array([0, delta]), y, g)
approx_deriv1 = (C1 - C0) / delta
approx_deriv = np.array([approx_deriv0, approx_deriv1])
deriv = cost_deriv(x_guess, y, g)

# fails
min_res_SLSQP = sp_optimize.minimize(cost, x_guess, args=(y, g), jac=cost_deriv,
bounds=prm_bounds, method='SLSQP', options={'disp': True})
print(min_res_SLSQP)

Tags: 函数truenparrayoptimizedeltaguesscost
1条回答
网友
1楼 · 发布于 2024-10-01 15:44:44

与其最小化np.sum(e ** 2),不如最小化sqrt(np.sum(e ** 2)),或者更好(就计算而言):np.linalg.norm(e)!在

此修改:

  • 不会改变关于x的解决方案
  • 如果需要原始目标,则需要后处理(可能不需要)
  • 更强壮

有了这个变化,所有的情况都会起作用,甚至使用数值微分(我懒得修改梯度,它需要反映这一点!)。在

输出示例(函数求值的数量给出num diff):

Optimization terminated successfully.    (Exit mode 0)
            Current function value: 3.815547437029837e-06
            Iterations: 16
            Function evaluations: 88
            Gradient evaluations: 16
     fun: 3.815547437029837e-06
     jac: array([-6.09663382, -2.48862544])
 message: 'Optimization terminated successfully.'
    nfev: 88
     nit: 16
    njev: 16
  status: 0
 success: True
       x: array([ 2.00000037,  0.10000018])
Optimization terminated successfully.    (Exit mode 0)
            Current function value: 0.0002354577991007501
            Iterations: 23
            Function evaluations: 114
            Gradient evaluations: 23
     fun: 0.0002354577991007501
     jac: array([ 435.97259208,  288.7483819 ])
 message: 'Optimization terminated successfully.'
    nfev: 114
     nit: 23
    njev: 23
  status: 0
 success: True
       x: array([ 1.99999977,  0.10000014])
Optimization terminated successfully.    (Exit mode 0)
            Current function value: 0.0003392807206384532
            Iterations: 21
            Function evaluations: 112
            Gradient evaluations: 21
     fun: 0.0003392807206384532
     jac: array([ 996.57340243,   51.19298764])
 message: 'Optimization terminated successfully.'
    nfev: 112
     nit: 21
    njev: 21
  status: 0
 success: True
       x: array([ 2.00000008,  0.10000104])

虽然SLSQP可能存在一些问题,但鉴于其广泛的应用范围,它仍然是最受测试和健壮的代码之一!在

我也希望SLSQP在这里要比COBYLA好得多,因为后者主要基于线性化。(不过,这只是一个猜测;考虑到最小化接口,很容易尝试!)在

备选方案

一般而言,基于内点的凸二次规划求解器是最佳的求解方法。但为了这个,你得离开西皮。(或者也许SOCP解决方案会更好。。。我不确定)。在

cvxpy带来了一个很好的建模系统和一个好的开源解算器(ECOS;虽然从技术上讲是一个圆锥曲线解算器->更通用,更不健壮;但应该优于SLSQP)。在

使用cvxpy和ECOS,这看起来像:

^{pr2}$

相关问题 更多 >

    热门问题