`scipy.optimize` 函数甚至在 `maxiter=0` 时也会挂起

`scipy.optimize` functions hang even with `maxiter=0`

我正在尝试使用简单的多 class 逻辑回归训练 MNIST 数据(我从 Kaggle 下载),但是 scipy.optimize 函数挂起。

代码如下:

import csv
from math import exp
from numpy import *
from scipy.optimize import fmin, fmin_cg, fmin_powell, fmin_bfgs

# Prepare the data

def getIiter(ifname):
    """
    Get the iterator from a csv file with filename ifname
    """
    ifile = open(ifname, 'r')
    iiter = csv.reader(ifile)
    iiter.__next__()
    return iiter

def parseRow(s):
    y = [int(x) for x in s]
    lab = y[0]
    z = y[1:]
    return (lab, z)

def getAllRows(ifname):
    iiter = getIiter(ifname)
    x = []
    l = []
    for row in iiter:
        lab, z = parseRow(row)
        x.append(z)
        l.append(lab)
    return x, l

def cutData(x, y):
    """
    70% training
    30% testing
    """
    m = len(x)
    t = int(m * .7)
    return [(x[:t], y[:t]), (x[t:], y[t:])]

def num2IndMat(l):
    t = array(l)
    tt = [vectorize(int)((t == i)) for i in range(10)]
    return array(tt).T

def readData(ifname):
    x, l = getAllRows(ifname)
    t = [[1] + y for y in x]
    return array(t), num2IndMat(l)

#Calculate the cost function

def sigmoid(x):
    return 1 / (1 + exp(-x))

vSigmoid = vectorize(sigmoid)
vLog = vectorize(log)

def costFunction(theta, x, y):
    sigxt = vSigmoid(dot(x, theta))
    cm = (- y * vLog(sigxt) - (1 - y) * vLog(1 - sigxt)) / m / N
    return sum(cm)

def unflatten(flatTheta):
    return [flatTheta[i * N : (i + 1) * N] for i in range(n + 1)]

def costFunctionFlatTheta(flatTheta):
    return costFunction(unflatten(flatTheta), trainX, trainY)

def costFunctionFlatTheta1(flatTheta):
    return costFunction(flatTheta.reshape(785, 10), trainX, trainY)

x, y = readData('train.csv')
[(trainX, trainY), (testX, testY)] = cutData(x, y)

m = len(trainX)
n = len(trainX[0]) - 1
N = len(trainY[0])

initTheta = zeros(((n + 1), N))
flatInitTheta = ndarray.flatten(initTheta)
flatInitTheta1 = initTheta.reshape(1, -1)

在最后两行中,我们将 initTheta 展平,因为 fmin{,_cg,_bfgs,_powell} 函数似乎只将向量作为初始值参数 x0。我还使用 reshapeinitTheta 展平,希望 能有所帮助。

成本函数计算没有问题,在我的电脑上不到2秒:

print(costFunctionFlatTheta(flatInitTheta), costFunctionFlatTheta1(flatInitTheta1))
# 0.69314718056 0.69314718056

但是所有 fmin 函数都挂起,即使我设置了 maxiter=0。 例如

newFlatTheta = fmin(costFunctionFlatTheta, flatInitTheta, maxiter=0)

newFlatTheta1 = fmin(costFunctionFlatTheta1, flatInitTheta1, maxiter=0)

当我中断程序时,在我看来它全部挂在 optimize.py 调用成本函数的行,像这样的行:

return function(*(wrapper_args + args))

例如,如果我使用 fmin_cg,这将是 optimize.py(版本 0.5)中的第 292 行。

如何解决这个问题?

好的,我找到了停止 fmin_cg 挂起的方法。

基本上我只需要写一个函数来计算成本函数的梯度,并将它传递给fmin_cgfprime参数。

def gradient(theta, x, y):
    return dot(x.T, vSigmoid(dot(x, theta)) - y) / m / N

def gradientFlatTheta(flatTheta):
    return ndarray.flatten(gradient(flatTheta.reshape(785, 10), trainX, trainY))

然后

newFlatTheta = fmin_cg(costFunctionFlatTheta, flatInitTheta, fprime=gradientFlatTheta, maxiter=0)

在几秒钟内终止,将 maxiter 设置为更高的数字(例如 100)可以在合理的时间内训练模型。

The documentation of fmin_cg 说如果没有给出 fprime 梯度将被数值计算,这就是我怀疑导致挂起的原因。

感谢 this notebook by zgo2016@Kaggle 帮助我找到了解决方案。