如何通过lmfit在多进程共享数组中传递ModelResult类?

时间:2019-07-05 03:46:13

标签: python multiprocessing lmfit

我在不同的过程中使用 lmfit 有一些问题,以使我的代码更快。如何定义一些包含每个拟合结果的共享数组?

我有一个数据立方体,位置分别为a,b,x和f(x)。我在 lmfit 中制作了一个模型,可以很好地工作并将f(x)调整为一点,并返回一些参数。 Lmfit返回一个名为 ModelResult()的类,该类包含所有这些参数以及一些有用的额外数据。因此,我需要为每个a和b运行此拟合,然后再使用此参数以及可能的额外数据制作一个多维数据集。我可以以线性方式(无需并行化)运行它,但是我有1000多个点,并且模型很复杂,因此花费了超过15000秒的时间。

当我使用 multiprocessing 库时,我的问题开始了。我需要在每个进程之间共享数据,所以当一个进程完成时,锁定变量并将结果存储在内部,然后再解锁变量。多重处理库具有 Value() Array()来满足我的需要。我打算使用Array,并对变量进行了一些更改,以将a和b传递给c,其中c是a * b的范围。但是我无法定义一个数组来为每个c保留 ModelResult()

代码在这里:

import multiprocessing as mp
import numpy as np
import time 
from lmfit import Model
from numpy import sqrt, exp, pi

#Set time zero
start_time = time.time()

#Example of functions to fit
def gaussian(x, amp, cen, wid):
    """1-d gaussian: gaussian(x, amp, cen, wid)"""
    return (amp / (sqrt(2*pi) * wid)) * exp(-(x-cen)**2 / (2*wid**2))

def linear(x, slope, intercept):
    """a linear function"""
    return slope*x + intercept

#Function to fit every point
def fit_point(a,b,data_cube,x,pars,mod):
        pos=int(b+(a*10))
        data_point = np.array(data_cube[:,a,b])
        #print(pos,mp.current_process().name)
        error_point= np.array((data_point*0)+0.002) #Example error
        res_point=mod.fit(data_point, pars, weights=1./error_point, x=x)
        print(res_point.fit_report())
        cube_res[pos]=res_point
        return #cube_res[:]

#Invented some data
x=np.arange(10)
data_cube=np.random.rand(10, 10, 10)

#Example of a model with 2 gaussians and a line
mod = Model(linear, prefix='l_')+Model(gaussian, prefix='g1_')+Model(gaussian, prefix='g2_')
pars= mod.make_params()
pars['g1_amp'].set(0.5)
pars['g2_amp'].set(0.5)
pars['g1_cen'].set(2)
pars['g2_cen'].set(3)
pars['g1_wid'].set(0.5)
pars['g2_wid'].set(0.5)
pars['l_slope'].set(1)
pars['l_intercept'].set(1)

#Definition of the shared Array #Where I think there is the problem!
cube_res = mp.Array('u', 100)

#Definition of the process and starts
processes = []
for a in np.arange(0,10):
    for b in np.arange(0,10):
        process = mp.Process(target=fit_point, args=(a,b,data_cube,x,pars,mod))
        process.start()
        processes.append(process)
for process in processes:
    process.join()

print('Time count')
print("--- %s seconds ---" % (time.time() - start_time))    

#Intent to print some results
#print(cube_res[20].fit_report)

#Final, to recover a,b
#final_cube_res = np.reshape(cube_res, (100,100))

错误是:

TypeError: unicode string expected instead of ModelResult instance

这是因为我定义了 mp.Array('u',100),其中'u'是unicode,而100是范围。

我不知道如何定义数组以将ModelResult保存在其中。

感谢阅读!

1 个答案:

答案 0 :(得分:0)

错误消息告诉您不能将lmfit.ModelResult放入字符串中。实际上,您的

cube_res = mp.Array('u', 100)

表示cube_res是100个Unicode字符的数组。也就是说,每个结果必须为1个字符长。我认为您想要使用的是multiprocessing.Manger().dict来保存结果。

cube_res = mp.Manager().dict()

这将允许您使用(x,y)位置作为键,然后可以将ModelResult用作值。...

...但是:您将无法直接保存ModelResult,因为需要对多进程之间共享的数据进行酸洗,并且通常来说,复杂的对象(尤其是那些带有方法的对象)不容易被酸洗。好消息是lmfit.ModelResult有一个dumps()方法,您可以使用该方法将该对象转换为可拾取的json字符串。因此,您的代码将使用

    res_point=mod.fit(data_point, pars, weights=1./error_point, x=x)
    print(res_point.fit_report())
    cube_res[(a,b)] = res_point.dumps()
    return 

在您的fit_point()函数中。

我们还没有完成,因为从转储的json字符串中恢复ModelResult有点复杂(lmfit具有此功能,但这些功能假定您已将结果写入文件中)。完成所有joined处理后,您必须这样做:

print('Time count')
print("--- %s seconds ---" % (time.time() - start_time))

import lmfit
# make a dummy ModelResult -- we'll overwrite everything for this
modres = lmfit.model.ModelResult(lmfit.Model(gaussian), lmfit.Parameters())

# make a dictionary of the functions you actually used (the function *names* 
# are included in the dumped string, but not the functions themselves)
funcdefs = {'gaussian': gaussian, 'linear': linear}
for pos, dumpval in cube_res.items():
    modelresult = modres.loads(dumpval, funcdefs=funcdefs)
    print('### Result for fit ', pos)
    print(modelresult.fit_report())

我认为那应该让您入门...