【问题标题】:Python: How to prevent Scipy's optimize.minimize function from changing the shape of initial guess x0?Python:如何防止 Scipy 的 optimize.minimize 函数改变初始猜测 x0 的形状?
【发布时间】:2018-03-12 11:24:21
【问题描述】:

我正在尝试从 Scipy 实现优化算法。当我在不输入雅可比梯度函数的情况下实现它时它工作正常。我相信我在输入梯度时遇到的问题是因为最小化函数本身正在改变初始猜测 x0 的形状。您可以从下面的代码输出中看到这一点。

输入:

import numpy as np
from costFunction import *
import scipy.optimize as op

def sigmoid(z):

    epsilon = np.finfo(z.dtype).eps

    g = 1/(1+np.exp(-z))
    g = np.clip(g,epsilon,1-epsilon)
    return g

def costFunction(theta,X,y):
    m = y.size
    h = sigmoid(X@theta)
    J = 1/(m)*(-y.T@np.log(h)-(1-y).T@np.log(1-h))
    grad = 1/m*X.T@(h-y)
    print ('Shape of theta is',np.shape(theta),'\n')
    print ('Shape of gradient is',np.shape(grad),'\n')
    return J, grad

X = np.array([[1, 3],[5,7]])
y = np.array([[1],[0]])

m,n = np.shape(X)
one_vec = np.ones((m,1))
X = np.hstack((one_vec,X))
initial_theta = np.zeros((n+1,1))

print ('Running costFunction before executing minimize function...\n')
cost, grad = costFunction(initial_theta,X,y) #To test the shape of gradient before calling minimize

print ('Executing minimize function...\n')
Result = op.minimize(costFunction,initial_theta,args=(X,y),method='TNC',jac=True,options={'maxiter':400})

输出:

Running costFunction before executing minimize function...

Shape of theta is (3, 1) 
Traceback (most recent call last):

Shape of gradient is (3, 1) 

Executing minimize function...

Shape of theta is (3,) 

  File "C:/Users/#####/minimizeshapechange.py", line 34, in <module>
Shape of gradient is (3, 2) 

    Result = op.minimize(costFunction,initial_theta,args=(X,y),method='TNC',jac=True,options={'maxiter':400})
  File "C:\Users\#####\anaconda3\lib\site-packages\scipy\optimize\_minimize.py", line 453, in minimize
    **options)
  File "C:\Users\#####\anaconda3\lib\site-packages\scipy\optimize\tnc.py", line 409, in _minimize_tnc
    xtol, pgtol, rescale, callback)
ValueError: tnc: invalid gradient vector from minimized function.

Process finished with exit code 1

【问题讨论】:

    标签: python numpy optimization scipy minimize


    【解决方案1】:

    我不会分析你的确切计算,但有一些评论:

    • (1) 你的渐变坏了!
      • scipy 期望 partial derivative 产生一个与您的 x0 相等的形状数组。
      • 你的渐变形状是(3,2),而(n+1, 1)是预期的
      • 与使用scipy.optimize.rosen_der(der =导数)的教程中给出的示例进行比较
    • (2) 看来您的 scipy 版本有点旧,因为我的 (0.19.0) 告诉我:
      • ValueError: tnc: invalid gradient vector from minimized function.

    来自scipy的一些支持源代码:

    if (PyArray_SIZE(arr_grad) != py_state->n)
    {
      PyErr_SetString(PyExc_ValueError,
        "tnc: invalid gradient vector from minimized function.");
      goto failure;
    

    备注: 上面的代码是 5 年前更改/触摸/引入的。如果您在使用列出的代码时确实没有收到此错误(删除了 costFunction 的导入),那么您似乎正在使用 scipy

    【讨论】:

    • 非常感谢您的回复。 1.梯度是(3,2)的原因是因为最小化函数正在改变它。在调用最小化函数来演示这一点之前,我已经编辑了代码以包含一个打印语句。 2. 我不确定版本的问题,因为我的也是 0.19.0 并且得到的输出和你一样。
    • 你应该提到那个错误。嗯......然后对这些形状更加小心。通常初始向量的形状是(n,)(不完全是(n, 1)),在这种情况下,minimize 不会改变任何东西,你的渐变仍然被破坏。 (Shape of theta before executing optimization function: (3,) ... Shape of theta inside costFunction is (3,) ... grad: [[ 0. 0.] [ 1. 1.] [ 1. 1.]])
    • 对不起,我不清楚。我再次更新了代码。在执行最小化函数之前和之后,我输入了 theta 形状和梯度的打印语句。如您所见,它们都从 (3,1) 变为 (3,)。
    • 我已经告诉过你:从initial_theta = np.zeros(n+1) 开始并查看(我认为这是正确的形状;虽然我不能保证这是唯一可行的方法;至少最小化不会改变任何东西这是意料之中的!)。
    • 那么,您的意思是我应该将输入 theta 作为 1D 向量并在 costFunction 内部将 theta 调整为 2D 列向量以便进行线性代数?
    【解决方案2】:

    我对 Scipy 尝试做与您相同的事情时遇到了同样的问题。我不明白为什么这可以解决问题,但是在它工作之前玩数组形状给了我以下信息:

    梯度函数定义如下

    def Gradient(theta,X,y):
        #Initializing variables
        m = len(y)
        theta = theta[:,np.newaxis]     #<---- THIS IS THE TRICK
        grad = np.zeros(theta.shape)
    
        #Vectorized computations
        z = X @ theta
        h = sigmoid(z)
        grad = (1/m)*(X.T @ ( h - y));
    
        return grad    #< --- also works with grad.ravel()
    

    initial_theta 初始化为

    initial_theta = np.zeros((n+1))
    initial_theta.shape
    

    (3,)

    即一个简单的 numpy 数组而不是列向量。

    梯度函数返回

    Gradient(initial_theta,X,y).shape
    

    (3,1) 或 (3,) 取决于函数返回grad 还是grad.ravel

    scipy.optimize 称为

    import scipy.optimize as opt
    model = opt.minimize(fun = CostFunc, x0 = initial_theta, args = (X, y), method = 'TNC', jac = Gradient)
    

    什么不适用于 Scipy

    使用initial_theta = np.zeros((n+1))[:,np.newaxis] 的形状 (3,1) 的初始θ使 scipy.minimize 函数调用崩溃。

    ValueError: tnc: 来自最小化函数的无效梯度向量。

    如果有人能澄清这些观点,那就太好了!谢谢

    【讨论】:

      【解决方案3】:

      你的 costFunctuion 代码是错误的,也许你应该看看

      def costFunction(theta,X,y):
         h_theta = sigmoid(X@theta)
         J = (-y) * np.log(h_theta) - (1 - y) * np.log(1 - h_theta)
      return np.mean(J)
      

      【讨论】:

        【解决方案4】:

        请在 jpuiter in1 中复制并粘贴到单独的单元格中,依此类推

        In 1
                                import pandas as pd
                                import numpy as np
                                import matplotlib.pyplot as plt
                                import seaborn as sns
                                %matplotlib inline
                                filepath =('C:/Pythontry/MachineLearning/dataset/couresra/ex2data1.txt')
                                data =pd.read_csv(filepath,sep=',',header=None)
                                #print(data)
                                X = data.values[:,:2]  #(100,2)
                                y = data.values[:,2:3] #(100,1)
                                #print(np.shape(y))
                                #In 2
                                #%% ==================== Part 1: Plotting ====================
                                postive_value = data.loc[data[2] == 1]
                                #print(postive_value.values[:,2:3])
                                negative_value = data.loc[data[2] == 0]
                                #print(len(postive_value))
                                #print(len(negative_value))
                                ax1 = postive_value.plot(kind='scatter',x=0,y=1,s=50,color='b',marker="+",label="Admitted") # S is line width #https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.scatter.html#matplotlib.axes.Axes.scatter 
                                ax2 = negative_value.plot(kind='scatter',x=0,y=1,s=50,color='y',ax=ax1,label="Not Admitted")
                                ax1.set_xlabel("Exam 1 score")
                                ax2.set_ylabel("Exam 2 score")
                                plt.show()
                                #print(ax1 == ax2)
                                #print(np.shape(X))
        
                        # In 3
                                #============ Part 2: Compute Cost and Gradient ===========
                                [m,n] = np.shape(X) #(100,2)
                                print(m,n)
                                additional_coulmn = np.ones((m,1))
                                X = np.append(additional_coulmn,X,axis=1)
                                initial_theta = np.zeros((n+1), dtype=int)
                                print(initial_theta)
        
                                # In4
                                #Sigmoid and cost function
                                def sigmoid(z):
                                    g = np.zeros(np.shape(z));
                                    g = 1/(1+np.exp(-z));
                                    return g
                                def costFunction(theta, X, y):
                                       J = 0;
                                       #print(theta)
                                       receive_theta = np.array(theta)[np.newaxis] ##This command is used to create the 1D array 
                                       #print(receive_theta)
                                       theta = np.transpose(receive_theta)
                                       #print(np.shape(theta))       
                                       #grad = np.zeros(np.shape(theta))
                                       z = np.dot(X,theta) # where z = theta*X
                                       #print(z)
                                       h = sigmoid(z) #formula h(x) = g(z) whether g = 1/1+e(-z) #(100,1)
                                       #print(np.shape(h))
                                       #J = np.sum(((-y)*np.log(h)-(1-y)*np.log(1-h))/m); 
                                       J = np.sum(np.dot((-y.T),np.log(h))-np.dot((1-y).T,np.log(1-h)))/m
                                       #J = (-y * np.log(h) - (1 - y) * np.log(1 - h)).mean()
                                       #error = h-y
                                       #print(np.shape(error))
                                       #print(np.shape(X))
                                       grad =np.dot(X.T,(h-y))/m
                                       #print(grad)
                                       return J,grad
                    #In5
                                [cost, grad] = costFunction(initial_theta, X, y)
                                print('Cost at initial theta (zeros):', cost)
                                print('Expected cost (approx): 0.693\n')
                                print('Gradient at initial theta (zeros): \n',grad)
                                print('Expected gradients (approx):\n -0.1000\n -12.0092\n -11.2628\n')
        
                    In6 # Compute and display cost and gradient with non-zero theta
                    test_theta = [-24, 0.2, 0.2]
                    #test_theta_value = np.array([-24, 0.2, 0.2])[np.newaxis]  #This command is used to create the 1D row array 
        
                    #test_theta = np.transpose(test_theta_value) # Transpose 
                    #test_theta = test_theta_value.transpose()
                    [cost, grad] = costFunction(test_theta, X, y)
        
                    print('\nCost at test theta: \n', cost)
                    print('Expected cost (approx): 0.218\n')
                    print('Gradient at test theta: \n',grad);
                    print('Expected gradients (approx):\n 0.043\n 2.566\n 2.647\n')
        
        
                #IN6
            # ============= Part 3: Optimizing using range  =============
            import scipy.optimize as opt
            #initial_theta_initialize = np.array([0, 0, 0])[np.newaxis]
            #initial_theta = np.transpose(initial_theta_initialize)
            print ('Executing minimize function...\n')
            # Working models
            #result = opt.minimize(costFunction,initial_theta,args=(X,y),method='TNC',jac=True,options={'maxiter':400})
            result = opt.fmin_tnc(func=costFunction, x0=initial_theta, args=(X, y))
            # Not working model
            #costFunction(initial_theta,X,y)
            #model = opt.minimize(fun = costFunction, x0 = initial_theta, args = (X, y), method = 'TNC',jac = costFunction)
            print('Thetas found by fmin_tnc function: ', result);
            print('Cost at theta found : \n', cost);
            print('Expected cost (approx): 0.203\n');
            print('theta: \n',result[0]);
            print('Expected theta (approx):\n');
            print(' -25.161\n 0.206\n 0.201\n');
        

        结果: 正在执行最小化函数...

        fmin_tnc 函数找到的 Thetas:(array([-25.16131854, 0.20623159, 0.20147149]), 36, 0) 发现的 theta 成本: 0.218330193827 预期成本(大约):0.203

        θ: [-25.16131854 0.20623159 0.20147149] 预期 theta(大约):

        -25.161 0.206 0.201

        【讨论】:

          【解决方案5】:

          scipy 的 fmin_tnc 不适用于列向量或行向量。它期望参数是数组格式。

          Python Implementation of Andrew Ng’s Machine Learning Course (Part 2.1)

          opt.fmin_tnc(func = costFunction, x0 = theta.flatten(),fprime = gradient, args = (X, y.flatten()))
          

          【讨论】:

            【解决方案6】:

            对我有用的是将 y 重塑为向量(1-D)而不是矩阵(2-D 数组)。我只是简单地使用了以下代码,然后重新运行了 SciPy 的最小化函数,它就起作用了。

            y = np.reshape(y,100) #例如,如果你的 y 变量有 100 个数据点。

            【讨论】:

              【解决方案7】:

              有点晚了,但我也开始了用 Python 实现的 anderw assignment,并付出了很多努力来解决上述问题。终于适合我了。

              这个blog 帮助我,但在 fmin_tnc 函数调用中进行了一项更改,请参阅以下内容:-

              result = op.fmin_tnc(func=costFunction, x0=initial_theta, fprime=None, approx_grad=True, args=(X, y))here获得此信息

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2022-01-25
                • 1970-01-01
                • 2020-11-26
                • 1970-01-01
                相关资源
                最近更新 更多