lmfit最小化失败并出现ValueError:数组太大

时间:2018-07-31 20:50:03

标签: python optimization lmfit

我正在尝试使用“ brute”方法来最小化20个变量的函数。它以一个神秘的错误失败。这是完整的代码:

import random
import numpy as np
import lmfit

def progress_update(params, iter, resid, *args, **kws):
    pass
    #print(resid)

def score(params, data = None):
    parvals = params.valuesdict()
    M = data
    X_params = []
    Y_params = []
    for i in range(M.shape[0]):
        X_params.append(parvals['x'+str(i)])
    for j in range(M.shape[1]):
        Y_params.append(parvals['y'+str(i)])
    return diff(M, X_params, Y_params)


def diff(M, X_params, Y_params):
    total = 0
    for i in range(M.shape[0]):
        for j in range(M.shape[1]):
            total += abs(M[i,j] - (X_params[i] - Y_params[j])**2)
    return total

dim = 10
random.seed(0)
M = np.empty((dim, dim))

for i in range(M.shape[0]):
    for j in range(M.shape[1]):
        M[i,j] = i*random.random()+j**2

params = lmfit.Parameters()
for i in range(M.shape[0]):
    params.add('x'+str(i), value=random.random()*10, min=0, max=10)
for j in range(M.shape[1]):
    params.add('y'+str(j), value=random.random()*10, min=0, max=10)

result = lmfit.minimize(score, params, method='brute', kws={'data': M},  iter_cb=progress_update)

但是,此操作失败并显示:

ValueError: array is too big; `arr.size * arr.dtype.itemsize` is larger than the maximum possible size.

是什么原因导致此问题?

1 个答案:

答案 0 :(得分:1)

“导致此问题的原因”

Math

您不能强行解决高维问题,因为强行方法require exponential work(时间和内存(如果是天真的实现的话))。

更直接地,lmfit在后台使用numpy(*),它具有可以分配多少数据的最大大小。您的初始数据结构不太大(10x10),它是导致问题的暴力破解所需的组合表。

如果您愿意破解该实现,则可以切换到稀疏的内存结构。但这并不能解决数学问题。

关于高维优化

尝试使用其他最小化器,但要警告:在高维空间中全局最小化非常困难。像fixed point / gradient descent之类的“局部最小值”方法可能会更有效率。

我不想过于悲观,但是一般情况下进行高级优化非常困难,而且恐怕超出了SO问题的范围。 Here is a survey

实用替代方案

梯度下降为supported a little in sklearn,但对于机器学习而言,梯度下降比常规优化更多; scipy actually has pretty good optimization的覆盖范围和great documentation。我从那里开始。可以执行gradient descent there too,但不是必需的。

从scipy关于无约束最小化的文档中,您有很多选择:

  

方法Nelder-Mead使用单纯形算法[],[]。这个算法   在许多应用程序中都很强大。但是,如果数值计算   可以信任派生,使用第一和/或其他算法的其他算法   二阶导数信息可能会更好   表现一般。

     

方法Powell是对Powell方法[],[]的修改,   共轭方向法。它执行顺序一维   沿方向集的每个向量最小化   选项和信息),在每次主迭代时都会更新   最小化循环。函数不必是可区分的,并且不需要   取导数。

以及许多其他基于导数的方法可用。 (通常,当您拥有派生信息时,您会做得更好。)


脚注/查看源代码

(*)此处的实际错误is thrown(基于您的numpy实现)。引用:

`if (npy_mul_with_overflow_intp(&nbytes, nbytes, dim)) {
    PyErr_SetString(PyExc_ValueError,
        "array is too big; `arr.size * arr.dtype.itemsize` "
        "is larger than the maximum possible size.");
    Py_DECREF(descr);
    return NULL;`