【问题标题】:Logistic Regression and Scipy Optimization with fmin_bfgs使用 fmin_bfgs 进行逻辑回归和 Scipy 优化
【发布时间】:2015-01-31 07:33:22
【问题描述】:

我正在尝试实现逻辑回归,并且我正在使用 Scipy 的优化模块来查找优化的 theta 值。使用 fmin 函数时,我能够获得正确的值。但是我想在使用需要渐变的 fmin_bfgs 函数时这样做。

这是一个代码sn-p:

#Returns Cost of current theta values and gradient of cost w.r.t theta.
def costFunction(theta, X, y, _lambda):

    #Initializes useful variables
    m = len(y)
    grad = np.zeros((np.shape(theta)))

    #Solves for Hypothesis for input X.
    h_x = Sigmoid(np.dot(X,theta))

    #Reshaped because numpy kept returning row vector, not column.
    h_x = h_x.reshape((m,1))

    #Cost is broken up into terms for simplicity. 
    term1 = -y*np.log(h_x)
    term2 = (1-y)*np.log((1-h_x))



    #Regularized Cost FUnction
    J = (1/m) * sum(term1-term2) + (_lambda/(2*m)) * sum(np.square(theta[1:][:]))

    #Gradient for Theta1
    grad_reg = (_lambda/m)*theta[1:]

    #Combines gradient for Theta1 and onward. 
    grad = (1/m)* (np.dot(np.transpose(X),(h_x-y))) + np.vstack(([0],grad_reg)) 

    return J,grad 





#Finds Optimal Value for theta
cost, grad = costFunction(initial_theta, X,y, _lambda)
opt_theta = fmin_bfgs(cost,x0=initial_theta,fprime=grad, args = (X,y,_lambda))

我得到的错误是'numpy.ndarray' object is not callable,它来自优化模块中的function_wrapper 函数。我什至尝试在两个不同的函数中返回梯度和成本,但得到了某种vstack 错误(如果这很重要/有帮助的话)。

据我所知,我已经提供了优化功能的要求。

编辑/更新:我意识到我得到的错误是因为我传递了成本,并且当它期望函数返回这些参数时,将 grad numpy 数组作为参数。我意识到我可以创建一个包装函数?为了在不使用两个单独的函数的情况下获得这两个值,但出于临时目的,我更改了 costFunction 以便它只返回成本,并创建了一个全新的函数Grad()(尽管具有相同的代码),它只返回 grad。这又给了我all the input array dimensions except for the concatenation axis must match exactly vstack 错误。

【问题讨论】:

    标签: python optimization numpy machine-learning scipy


    【解决方案1】:

    如果没有最小的可重现示例,就很难调试。

    按照我调试它的方式,我会从一些非常简单的东西开始,以确保我得到正确的基本语法。有几种方法可以通过显式梯度使用 bfgs 最小化。一、没有梯度信息:

    In [1]: import numpy as np
    
    In [2]: from scipy.optimize import minimize
    
    In [3]: def f(x):
       ...:     return np.sum((x-2.)**2)
       ...: 
    
    In [4]: x0 = np.ones(3)
    
    In [5]: minimize(f, x0, method='bfgs')
    Out[5]: 
      status: 0
     success: True
        njev: 4
        nfev: 20
         fun: 1.6656677750444977e-16
           x: array([ 1.99999999,  1.99999999,  1.99999999])
    <snip>
    

    现在,使用渐变,您可以有一个返回函数渐变的可调用对象:

    In [6]: def f_and_jac(x):
       ...:     val = np.sum((x-2.)**2)
       ...:     grad = 2.*(x-2.)
       ...:     return val, grad
       ...: 
    
    In [7]: minimize(f_and_jac, x0, method='bfgs', jac=True)   # notice the 'jac' parameter
    Out[7]: 
      status: 0
     success: True
        njev: 4
        nfev: 4
         fun: 0.0
           x: array([ 2.,  2.,  2.])
    

    或者,您可以将jac 设置为可调用对象,该可调用对象应具有与成本函数相同的签名并返回梯度:

    In [8]: def jac(x):
       ...:     return 2.*(x-2.)
       ...: 
    
    In [9]: minimize(f, x0, method='bfgs', jac=jac)
    Out[9]: 
      status: 0
     success: True
        njev: 4
        nfev: 4
         fun: 0.0
           x: array([ 2.,  2.,  2.])
    

    【讨论】:

    • 我听取了您关于复制简单内容的建议,所以我让渐变函数吐出第一个渐变应该是什么。这些值是正确的,但似乎有一个奇怪的间距。它是:[ -0.1 -12.00921659 -11.26284221]。在前两个值之间,它有一个奇数间距。我去了 vstack 函数错误所在的位置,它显然收到了一个我打印出来的元组。在 flatten 方法之前是 ([0], array([[ 0.], [ 0.]])),在 flatten 方法之后是 ([0], array([ 0., 0.]))。我怎样才能让它成为一个单一的数组?
    • 这没什么用。最好将您的问题分成不同的问题:显然有一个是关于最小化本身的,另一个是关于成本函数的。
    • 好吧,我显然打算这样做,我如何让np.vstack(([0],grad_reg)) 返回单个数组?不像([0], array([ 0., 0.]))
    猜你喜欢
    • 1970-01-01
    • 2015-08-05
    • 2012-11-27
    • 2014-07-22
    • 1970-01-01
    • 2015-12-19
    • 2015-02-21
    • 2018-08-11
    • 1970-01-01
    相关资源
    最近更新 更多