【问题标题】:Scipy: Minimize violates given boundsScipy:最小化违反给定的界限
【发布时间】:2018-09-07 20:57:33
【问题描述】:

我正在尝试将scipy.optimize.minimize 与简单的a <= x <= b 界限一起使用。但是,经常发生我的目标函数在边界之外进行评估。据我了解,这发生在minimize 试图确定边界处目标函数的梯度时。


小例子:

import math
import numpy as np
from scipy.optimize import Bounds, minimize

constraint = Bounds([-1, -1], [1, 1], True)
def fun(x):
    print(x)
    return -math.exp(-np.dot(x,x))
result = minimize(fun, [-1, -1], bounds=constraint)

输出显示最小化器跳转到点[1,1],然后尝试在[1.00000001, 1]处求值:

[-1. -1.]
[-0.99999999 -1.        ]
[-1.         -0.99999999]
[-0.72932943 -0.72932943]
[-0.72932942 -0.72932943]
[-0.72932943 -0.72932942]
[-0.22590689 -0.22590689]
[-0.22590688 -0.22590689]
[-0.22590689 -0.22590688]
[1. 1.]
[1.00000001 1.        ]
[1.         1.00000001]
[-0.03437328 -0.03437328]
...

当然,在这个例子中没有问题,因为fun 也可以在那里计算。但情况可能并非总是如此......


在我的实际问题中,最小值不能在边界上,我有一个简单的解决方法,即在边界上添加一个 epsilon。 但是人们会期望应该有一个简单的解决方案来解决这个问题,如果最小值可以在边界处也可以工作?

PS:如果我是第一个遇到这个问题的人会很奇怪——很抱歉,如果这个问题之前有人问过这个问题,但我在任何地方都没有找到。

【问题讨论】:

标签: python scipy


【解决方案1】:

正如here 所讨论的(感谢@“Welcome to Stack Overflow”的评论将我引导到那里),问题确实是渐变例程不尊重边界。 我写了一个新的来完成这项工作:

import math
import numpy as np
from scipy.optimize import minimize

def gradient_respecting_bounds(bounds, fun, eps=1e-8):
    """bounds: list of tuples (lower, upper)"""
    def gradient(x):
        fx = fun(x)
        grad = np.zeros(len(x))
        for k in range(len(x)):
            d = np.zeros(len(x))
            d[k] = eps if x[k] + eps <= bounds[k][1] else -eps
            grad[k] = (fun(x + d) - fx) / d[k]
        return grad
    return gradient

bounds = ((-1, 1), (-1, 1))
def fun(x):
    print(x)
    return -math.exp(-np.dot(x,x))
result = minimize(fun, [-1, -1], bounds=bounds,
                  jac=gradient_respecting_bounds(bounds, fun))

请注意,这可能会降低效率,因为fun(x) 现在在每个点都被评估两次。 这似乎是不可避免的,来自 lbfgsb.py 中 _minimize_lbfgsb 的相关 sn-p:

if jac is None:
    def func_and_grad(x):
        f = fun(x, *args)
        g = _approx_fprime_helper(x, fun, epsilon, args=args, f0=f)
        return f, g
else:
    def func_and_grad(x):
        f = fun(x, *args)
        g = jac(x, *args)
        return f, g

如你所见,f 的值只能被内部的_approx_fprime_helper 函数重用。

【讨论】:

  • 对我来说,你似乎错过了下限,函数应该是:` d[k] = eps if (x[k] + eps = bounds[k][0]) 否则 -eps `
  • @MarkusKaukonen 我假设eps 是正数,并且“x”不在界限之外,即x[k] &gt;= bounds[k][0]。这样就不需要第二次检查了。
  • 很好,我明白了。我继续使用包pypi.org/project/mystic 对我来说它似乎比 scipy 更好地解决约束和边界问题。
猜你喜欢
  • 1970-01-01
  • 2019-10-01
  • 1970-01-01
  • 2021-06-24
  • 2018-02-16
  • 2019-04-11
  • 2018-07-03
  • 2013-12-03
  • 2017-04-11
相关资源
最近更新 更多