优化Python中的复杂函数 - 错误

1 投票
1 回答
1909 浏览
提问于 2025-04-17 22:24

我正在尝试最小化一个有三个变量的函数,这个函数是非线性的,而且非常复杂。它在Matlab中运行得很好,但我想转到Python上(因为这是一个学习的机会,而且能让我有更多的自由)。总之,使用Python中的最小化函数'Nelder-Mead'确实可以运行,但输出的结果让我很困惑,所以我想给我的变量加上限制。

这是我的代码:

bnds = ((0, 1), (0, 1), (0, 1))
x0 = [0.004, 0.1, 0.1]
res = minimize(myObjFun, x0, method='L-BFGS-B', bounds=bnds)
print(res)

在Matlab中,输出给了我三个值,这些值能够最小化这个函数:[0.2182, 0.0684, 0.0048],而在Python的Nelder-Mead方法中,得到的结果完全不同,而且超出了我想要的范围(应该在0到1之间)。

这是错误信息:

File "****/fixedpoints.py", line 45, in <module>
    res = minimize(myObjFun, x0, method='L-BFGS-B', bounds=bnds)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scipy/optimize/_minimize.py", line 380, in minimize
callback=callback, **options)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scipy/optimize/lbfgsb.py", line 304, in _minimize_lbfgsb
isave, dsave)
TypeError: _lbfgsb.setulb() 6th argument (f) can't be converted to double

1 个回答

2

我们无法调试,除非你给我们提供myObjFun或者一个类似的函数(可以用更简单或虚构的数据),这个函数在优化时的表现要相似。更具体来说,你的代码需要在一个表现良好的myObjFun上运行;例如:

>>> import scipy.optimize
>>> def myObjFun(x):
        return (x[0]-.2182)**4 + (x[1]-.0684)**2 + 5*(x[2]-.0048)**2 + 3.2
>>> print scipy.optimize.minimize(myObjFun, [0.004,0.1,0.1], method='L-BFGS-B', bounds=((0,1),(0,1),(0,1)))
  status: 0
 success: True
    nfev: 18
     fun: 3.200000001787815
       x: array([ 0.21213686,  0.06837957,  0.00480194])
 message: 'CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH'
     jac: array([ -8.88178420e-07,  -4.08562073e-05,   1.94511074e-05])
     nit: 17

现在,setulb中的参数f包含了在评估函数时目标函数的当前值 [1]

   f is a double precision variable.
 On first entry f is unspecified.
 On final exit f is the value of the function at x.

所以,在搜索空间的某个点计算出的目标函数值似乎因为某种原因无法转换为浮点数(这似乎是个类型错误)。

我也能遇到类似的错误(实际上是OverflowError),比如这个目标函数,通常表现良好,但每当x[1] < 0.0685时就会出问题(这应该是在找到最小值之前发生的):

>>> def myObjFun(x):                                                                                       
        return (x[0]-.2182)**4 + (x[1]-.0684)**2 + 5*(x[2]-.0048)**2 + 3.2 if x[1] > 0.0684 else 10**999
   ....: 

>>> print scipy.optimize.minimize(myObjFun, [0.004,0.1,0.1], method='L-BFGS-B', bounds=((0,1),(0,1),(0,1)))
---------------------------------------------------------------------------
OverflowError                             Traceback (most recent call last)
<ipython-input-44-9204b704b51a> in <module>()
----> 1 print scipy.optimize.minimize(myObjFun, [0.004,0.1,0.1], method='L-BFGS-B', bounds=((0,1),(0,1),(0,1)))

lib/python2.7/site-packages/scipy/optimize/_minimize.pyc in minimize(fun, x0, args, method, jac, hess, hessp, bounds, constraints, tol, callback, options)
    376     elif meth == 'l-bfgs-b':
    377         return _minimize_lbfgsb(fun, x0, args, jac, bounds,
--> 378                                 callback=callback, **options)
    379     elif meth == 'tnc':
    380         return _minimize_tnc(fun, x0, args, jac, bounds, callback=callback,

lib/python2.7/site-packages/scipy/optimize/lbfgsb.pyc in _minimize_lbfgsb(fun, x0, args, jac, bounds, disp, maxcor, ftol, gtol, eps, maxfun, maxiter, iprint, callback, **unknown_options)
    302         _lbfgsb.setulb(m, x, low_bnd, upper_bnd, nbd, f, g, factr,
    303                        pgtol, wa, iwa, task, iprint, csave, lsave,
--> 304                        isave, dsave)
    305         task_str = task.tostring()
    306         if task_str.startswith(b'FG'):

OverflowError: _lbfgsb.setulb() 6th argument (f) can't be converted to double

所以我建议你仔细检查你的myObjFun,并在搜索的范围内手动评估多个点,看看返回的值是否合理、类型是否正确,并且与matlab返回的结果是否一致。

撰写回答