我希望沿单个方向最小化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_func
,jac
没有调用(使用) 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
答案 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
,解决了问题。
我还可以补充一点,我认为我的方向导数的分析版本是正确的,但是以函数形式提供导数似乎导致更多的数值问题,而不仅仅是估计导数。