调用scipy.fmin_powell优化时报'tuple' object is not callable如何解决
问题描述
我正在学习编写机器学习模型代码,遇到了TypeError类型错误。我查到了类似问题python fsolve: 'list' object is not callable,但该问题的解决方案无法解决我的问题。
代码如下:
def cost_fun(self, lam, x, theta, m): """ :type lam: int :type x: numpy.ndarray :type theta: numpy.ndarray :type m: int """ # sigmoid为sigmoid激活函数 hyp = np.transpose(sigmoid(np.transpose(theta) * x)) J = np.dot(-self.y, np.transpose(np.log(hyp))) - \ (np.dot(1 - self.y, np.transpose(np.log(1 - hyp))) / m) + \ np.dot((sum(theta ** 2) - theta[0] ** 2), lam / (2 * m)) grad = np.transpose(np.dot(np.transpose(np.divide(x, m // 2)), np.transpose((hyp - self.y)))) + \ (np.dot(theta, lam) / (m // 2)) grad[0] = 1 / m * sum(np.transpose(hyp - self.y) * x[0]) return J, grad def grad_desc(self, lam): """ :type lam: int :type params: numpy.ndarray """ min_theta1 = fmin_powell( self.cost_fun(lam, self.x, self.params, self.m), self.params )
报错信息如下:
Traceback (most recent call last): File "C:/Users/Michael/OneDrive/Desktop/machinelearning.py", line 133, in <module> main() File "C:/Users/Michael/OneDrive/Desktop/machinelearning.py", line 17, in main ai.train(lam=5) File "C:/Users/Michael/OneDrive/Desktop/machinelearning.py", line 126, in train self.grad_desc(lam) File "C:/Users/Michael/OneDrive/Desktop/machinelearning.py", line 111, in grad_desc self.cost_fun(lam, self.x, self.params, self.m), self.params File "C:\Users\Michael\anaconda3\lib\site-packages\scipy\optimize\optimize.py", line 2558, in fmin_powell res = _minimize_powell(func, x0, args, callback=callback, **opts) File "C:\Users\Michael\anaconda3\lib\site-packages\scipy\optimize\optimize.py", line 2631, in _minimize_powell fval = squeeze(func(x)) File "C:\Users\Michael\anaconda3\lib\site-packages\scipy\optimize\optimize.py", line 327, in function_wrapper return function(*(wrapper_args + args)) TypeError: 'tuple' object is not callable Process finished with exit code 1
错误原因
- scipy的
fmin_powell优化器第一个入参要求传入可调用的函数对象,你代码中直接写self.cost_fun(lam, self.x, self.params, self.m)是先执行了损失函数,拿到了返回的(J, grad)元组,优化器运行时尝试把这个元组当做函数调用,直接触发类型错误。 - 待优化的参数
theta应该是优化器动态调整的变量,你提前把固定的self.params传给损失函数,相当于写死了待优化参数,优化器无法完成参数更新。 fmin_powell是无导数优化算法,不需要传入梯度值,你当前的损失函数同时返回损失和梯度,优化器无法正确解析返回结果。
修复方案
- 调整损失函数的参数顺序,把待优化的
theta放到第一位,同时仅返回损失值:
def cost_fun(self, theta, lam, x, m): """ :type theta: numpy.ndarray :type lam: int :type x: numpy.ndarray :type m: int """ hyp = np.transpose(sigmoid(np.transpose(theta) * x)) J = np.dot(-self.y, np.transpose(np.log(hyp))) - \ (np.dot(1 - self.y, np.transpose(np.log(1 - hyp))) / m) + \ np.dot((sum(theta ** 2) - theta[0] ** 2), lam / (2 * m)) return J
- 调整
fmin_powell的调用方式,传入函数对象,把固定参数放到args中:
def grad_desc(self, lam): """ :type lam: int """ min_theta1 = fmin_powell( self.cost_fun, # 仅传入函数对象,不要加括号执行 self.params, # 待优化参数的初始值 args=(lam, self.x, self.m) # 其他固定参数按顺序传入 )
如果你需要利用已经计算好的梯度提升优化效率,可以更换为支持梯度输入的优化器(比如fmin_tnc),保留损失函数返回(J, grad)的逻辑,调用时补充fprime参数即可。
内容的提问来源于stack exchange,提问作者Michael Williams
相关产品推荐
相关产品推荐

