scipy.optimize.minimize,需要多个值来解析jacobian

时间:2016-11-23 17:15:11

标签: python scipy

我希望沿单个方向最小化2D标量函数,即线搜索。例如我想做2D标量版:

scipy.optimize.minimize(lambda x: x*x, 2, jac=lambda x: 2*x)

但以下对我不起作用。 (使用测试函数f(x,y)=(x-4)^ 2 +(y-4)^ 2.)

def my_func((x,y)):
    return (x-4)**2+(y-4)**2

def grad_my_func((x,y)):
    return (2*(x-4), 2*(y-4))

scipy.optimize.minimize如果我执行以下操作,则有效:

mygrad = np.array(grad_my_func((-4,-4)))
# mygrad -> [-16,-16]
scipy.optimize.minimize(lambda x: my_func(np.array([-4,-4]) + x*mygrad), 0)

结果是[-4,-4] + x * mygrad在(4,4)产生最小值:

   status: 0
  success: True
     njev: 4
     nfev: 12
 hess_inv: array([[ 0.00097656]])
      fun: 2.842170943040401e-14
        x: array([-0.50000001])
  message: 'Optimization terminated successfully.'
      jac: array([ 0.])
      nit: 2

但是如果我尝试为方向导数设置一个函数,它就不起作用了,我也不明白为什么。我还在技术上给最小化器提供1D功能吗?

scipy.optimize.minimize(
    lambda x: my_func(np.array([-4,-4]) + x*mygrad), 0, 
    jac=lambda x: np.dot(
        grad_my_func(np.array([-4,-4]) + x*mygrad),
        mygrad/scipy.linalg.norm(mygrad)) )

长回溯。我无法解释追溯的是它指向我的jac功能,但最终投诉是关于my_funcjac没有调用(使用) grad_my_func)。

ValueError                                Traceback (most recent call last)
<ipython-input-66-1e528ef250f5> in <module>()
      1 scipy.optimize.minimize(
      2     lambda x: my_func(np.array([-4,-4]) + x*mygrad), 0,
----> 3     jac=lambda x: np.dot(
      4         grad_my_func(np.array([-4,-4]) + x*mygrad),
      5         mygrad/scipy.linalg.norm(mygrad)) )

/usr/local/lib/python2.7/site-packages/scipy/optimize/_minimize.pyc in minimize(fun, x0, args, method, jac, hess, hessp, bounds, constraints, tol, callback, options)
    436         return _minimize_cg(fun, x0, args, jac, callback, **options)
    437     elif meth == 'bfgs':
--> 438         return _minimize_bfgs(fun, x0, args, jac, callback, **options)
    439     elif meth == 'newton-cg':
    440         return _minimize_newtoncg(fun, x0, args, jac, hess, hessp, callback,

/usr/local/lib/python2.7/site-packages/scipy/optimize/optimize.pyc in _minimize_bfgs(fun, x0, args, jac, callback, gtol, norm, eps, maxiter, disp, return_all, **unknown_options)
    859             alpha_k, fc, gc, old_fval, old_old_fval, gfkp1 = \
    860                      _line_search_wolfe12(f, myfprime, xk, pk, gfk,
--> 861                                           old_fval, old_old_fval)
    862         except _LineSearchError:
    863             # Line search failed to find a better solution.

/usr/local/lib/python2.7/site-packages/scipy/optimize/optimize.pyc in _line_search_wolfe12(f, fprime, xk, pk, gfk, old_fval, old_old_fval, **kwargs)
    693     ret = line_search_wolfe1(f, fprime, xk, pk, gfk,
    694                              old_fval, old_old_fval,
--> 695                              **kwargs)
    696
    697     if ret[0] is None:

/usr/local/lib/python2.7/site-packages/scipy/optimize/linesearch.pyc in line_search_wolfe1(f, fprime, xk, pk, gfk, old_fval, old_old_fval, args, c1, c2, amax, amin, xtol)
     99     stp, fval, old_fval = scalar_search_wolfe1(
    100             phi, derphi, old_fval, old_old_fval, derphi0,
--> 101             c1=c1, c2=c2, amax=amax, amin=amin, xtol=xtol)
    102
    103     return stp, fc[0], gc[0], fval, old_fval, gval[0]

/usr/local/lib/python2.7/site-packages/scipy/optimize/linesearch.pyc in scalar_search_wolfe1(phi, derphi, phi0, old_phi0, derphi0, c1, c2, amax, amin, xtol)
    172         if task[:2] == b'FG':
    173             alpha1 = stp
--> 174             phi1 = phi(stp)
    175             derphi1 = derphi(stp)
    176         else:

/usr/local/lib/python2.7/site-packages/scipy/optimize/linesearch.pyc in phi(s)
     85     def phi(s):
     86         fc[0] += 1
---> 87         return f(xk + s*pk, *args)
     88
     89     def derphi(s):

/usr/local/lib/python2.7/site-packages/scipy/optimize/optimize.pyc in function_wrapper(*wrapper_args)
    283     def function_wrapper(*wrapper_args):
    284         ncalls[0] += 1
--> 285         return function(*(wrapper_args + args))
    286
    287     return ncalls, function_wrapper

<ipython-input-66-1e528ef250f5> in <lambda>(x)
      1 scipy.optimize.minimize(
----> 2     lambda x: my_func(np.array([-4,-4]) + x*mygrad), 0,
      3     jac=lambda x: np.dot(
      4         grad_my_func(np.array([-4,-4]) + x*mygrad),
      5         mygrad/scipy.linalg.norm(mygrad)) )

<ipython-input-34-76d10d8be6fa> in my_func(***failed resolving arguments***)
----> 1 def my_func((x,y)):
      2    return (x-4)**2+(y-4)**2

ValueError: need more than 1 value to unpack

2 个答案:

答案 0 :(得分:1)

当我提供lambdas名称并在命令中使用它们时,错误堆栈是:

In [184]: optimize.minimize(bar,0,jac=foo1)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-184-ef7e300bda33> in <module>()
----> 1 optimize.minimize(bar,0,jac=foo1)

/usr/lib/python3/dist-packages/scipy/optimize/_minimize.py in minimize(fun, x0, args, method, jac, hess, hessp, bounds, constraints, tol, callback, options)
    439         return _minimize_cg(fun, x0, args, jac, callback, **options)
    440     elif meth == 'bfgs':
--> 441         return _minimize_bfgs(fun, x0, args, jac, callback, **options)
    442     elif meth == 'newton-cg':
    443         return _minimize_newtoncg(fun, x0, args, jac, hess, hessp, callback,
 etc

在您的错误消息中,--->未明确指向jac参数。它只是指向多行表达式的中间位置:

      1 scipy.optimize.minimize(
      2     lambda x: my_func(np.array([-4,-4]) + x*mygrad), 0,
----> 3     jac=lambda x: np.dot(
      4         grad_my_func(np.array([-4,-4]) + x*mygrad),
      5         mygrad/scipy.linalg.norm(mygrad)) )

错误仍可能与jac返回的内容有关。如果它返回错误的术语数,则可能会更改x0的形状,并在下次调用my_func时出现问题。这是因为如果未定义jac

,则运行调用

我会尝试在数值估算后对分析jac进行建模:

      fun: 2.842170943040401e-14
 hess_inv: array([[ 0.00097656]])
      jac: array([ 0.])
  message: 'Optimization terminated successfully.'

换句话说,它必须返回一个元素。

答案 1 :(得分:0)

原来ValueError: need more than 1 value to unpack确实是错误。因此,scipy例程将[[j]]作为最小化x的{​​{1}}的值返回,然后我将使用f(x + x*grad)乘以x*grad。但是我的函数期望一个类似元组的结构([[ x*grad[0], x*grad[1] ]]),而不是元组中的列表。

将代码修改为以下内容:

[ x*grad[0], x*grad[1] ]

即。 scipy.optimize.minimize( lambda x: my_func(np.array([-4,-4]) - x[0]*mygrad), [0.], jac=lambda x: np.dot( grad_my_func(np.array([-4,-4]) - x[0]*mygrad), mygrad/scipy.linalg.norm(mygrad)) ) 代替0作为初始猜测[0.]而不是x[0]*mygrad,解决了问题。

我还可以补充一点,我认为我的方向导数的分析版本是正确的,但是以函数形式提供导数似乎导致更多的数值问题,而不仅仅是估计导数。