我使用BFGS方法,提供给它的是我的平方指数/RBF核的负对数似然函数,以及它的梯度(雅可比矩阵)。如果不使用梯度,仅使用一阶差分,它可以正常工作 – 但是一旦我尝试使用NLL的梯度,就会出现以下错误:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
错误出现时,我的SE_der函数(梯度/雅可比矩阵)源代码中并没有使用.any()或.all(),我还尝试了这两种方法,但得到的错误完全相同。
前面的追踪信息如下:
Traceback (most recent call last):File "loaddata.py", line 107, in <module>gp.fit(X, y)File "/home/justinting/programming/bhm/ML/gp.py", line 33, in fitres = minimize(self.SE_NLL, gp_hp_guess, method='bfgs', jac=True)File "/usr/lib/python3.5/site-packages/scipy/optimize/_minimize.py", line 441, in minimizereturn _minimize_bfgs(fun, x0, args, jac, callback, **options)File "/usr/lib/python3.5/site-packages/scipy/optimize/optimize.py", line 865, in _minimize_bfgsold_fval, old_old_fval)File "/usr/lib/python3.5/site-packages/scipy/optimize/optimize.py", line 706, in _line_search_wolfe12old_fval, old_old_fval)File "/usr/lib/python3.5/site-packages/scipy/optimize/linesearch.py", line 282, in line_search_wolfe2phi, derphi, old_fval, old_old_fval, derphi0, c1, c2, amax)File "/usr/lib/python3.5/site-packages/scipy/optimize/linesearch.py", line 379, in scalar_search_wolfe2if (phi_a1 > phi0 + c1 * alpha1 * derphi0) or \
相关代码如下:
gp_hp_guess = [1.0] * 3 # 初始猜测res = minimize(self.SE_NLL, gp_hp_guess, method='bfgs', jac=self.SE_der)# 其他代码def SE_der(self, args): [f_err, l_scale, n_err] = args L = self.L_create(f_err, l_scale, n_err) alpha = linalg.solve(L.T, (linalg.solve(L, self.y))) # 保存以便在导数函数中使用 aaT = alpha.dot(alpha.T) K_inv = np.linalg.inv(L.T).dot(np.linalg.inv(L)) # self.K_inv = np.linalg.inv(self.L.T).dot(np.linalg.inv(self.L)) dK_dtheta = np.gradient(self.K_se(self.X, self.X, f_err, l_scale))[0] der = 0.5 * np.matrix.trace((aaT - K_inv).dot(dK_dtheta)) return -derdef SE_NLL(self, args): [f_err, l_scale, n_err] = args L = self.L_create(f_err, l_scale, n_err) alpha = linalg.solve(L.T, (linalg.solve(L, self.y))) # 保存以便在导数函数中使用 nll = ( 0.5 * self.y.T.dot(alpha) + np.matrix.trace(L) + # 对角线之和 L.shape[0]/2 * math.log(2*math.pi) ) return nll
我省略了辅助函数的源代码,因为当不使用梯度函数时,NLL可以正常工作,并且它们共享相同的辅助函数。
在优化后直接调用SE_der函数并传入优化后的参数(实际上并未在优化中使用梯度),它会输出一个单一的数字,正如预期的那样(至少我认为这是预期的),所以我没能发现问题所在。
这个错误是我对scipy期望的雅可比函数的误解,还是其他原因?我尝试查看了Python源代码,但实际处理函数的调用被隐藏在似乎不在Github上的Python代码中的函数后面 – 我不知道它们是否在其他地方的私有/C++存储库中。
回答:
看看侧边栏。你看到所有那些关于相同ValueError
的SO问题了吗?
虽然情况各不相同,但几乎在所有情况下,这都是因为在Python环境中使用了布尔数组,而该环境期望的是标量布尔值。
一个简单的例子是
In [236]: if np.arange(10)>5:print('yes')---------------------------------------------------------------------------ValueError Traceback (most recent call last)<ipython-input-236-633002262b65> in <module>()----> 1 if np.arange(10)>5:print('yes')ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
np.arange(10)>5
产生一个布尔数组,np.array([False, False, ...])
。
组合布尔表达式也可能产生这种情况。np.arange(10)>5 | np.arange(10)<2
会产生这种情况,(np.arange(10)>5) | (np.arange(10)<2)
则不会 – 因为逻辑运算符的优先级。 在这种情况下使用and
而不是|
是无望的。
我会更详细地查看你的代码,但在此期间,这可能会帮助你自己找到问题所在。
==================
从错误堆栈中:
if (phi_a1 > phi0 + c1 * alpha1 * derphi0) or \
此时代码期望(phi_a1 > phi0 + c1 * alpha1 * derphi0)
(以及or
后面的任何内容)是一个标量。可以推测这些变量之一是一个具有多个值的数组。诚然,这发生在调用堆栈的很深的地方,因此追溯这些值到你的代码会很困难。
打印,关注变量类型和形状,可能是最有用的。有时在这些迭代求解器上,代码在一个循环中运行良好,然后某个变量变为数组,在下一个循环中就卡住了。
==================
你为什么使用np.matrix.trace
?在我的测试中,它会产生一个2维的单元素np.matrix
。虽然这不明显会导致这个ValueError,但仍然值得怀疑。