2017-07-24 131 views
4

在Python调用MATLAB的性能必然会给一些性能降低,我可以通过重写(很多)在Python代码避免。然而,这对我来说不是一个现实的选择,但它让我很烦恼,效率的巨大损失在于从numpy数组到MATLAB double的简单转换。提高numpy的数组转换为MATLAB双

我谈论从数据1以下转换到data1m,其中

data1 = np.random.uniform(low = 0.0, high = 30000.0, size = (1000000,)) 
data1m = matlab.double(list(data1)) 

这里matlab.double来自Mathworks公司拥有MATLAB软件包/引擎。第二行代码在我的系统上需要20秒,这对于转换来说似乎太多了,除了使数字“可食用”MATLAB以外,其他任何操作都没有任何作用。

所以基本上我正在寻找一个伎俩相反给here的一个转换MATLAB输出在Python工作。

回答

2

在等待更好的建议,我会后的绝招,我拿出这么远。它归结为用`scipy.io.savemat'保存文件,然后在MATLAB中加载这个文件。

这不是最漂亮的黑客,它需要一些照顾,以确保依赖于相同脚本的不同进程最终不会写入和加载对方的.mat文件,但性能增益对​​我来说是值得的。

作为测试情况下,我写道,需要2门numpy的阵列(I与长度百万测试)和一个INT作为输入的两个简单,几乎相同的MATLAB函数。

function d = test(x, y, fs_signal) 
d = sum((x + y))./double(fs_signal); 

function d = test2(path) 
load(path) 
d = sum((x + y))./double(fs_signal); 

功能test需要转换,而test2需要节约。

测试test:转换两个numpy的阵列需要cirka 40秒我的系统上。准备和运行测试的总时间降至170秒

测试test2:保存数组和int在我的系统上花费了大约0.35秒。令人惊奇的是,加载在MATLAB中.MAT文件是非常有效的(或更令人惊讶,这是非常ineffcient在处理其双打)......总的时间来准备和运行测试2归结为0.38小号

这就是几乎450X性能增益...

+0

也许编写自己的C++代码可能会有所帮助。将数据从python转换为C++ shoudl很容易,例如, cython,然后你可以使用MATLAB的mex API来创建一个MATLAB变量,并为python(现在的C++)数据分配相同的内存指针。这两者肯定是非常快的(因为它只是创建对象并分配指针),并且应该是比IO上的中继更优雅的解决方案。 –

+0

也许这会有所帮助:https://github.com/kmatzen/matlab-python它是一个matlab C接口的包装,它应该给体面的速度。 – max9111

+0

尽管Cython看起来很有趣,但现在转到C++有点太令人望而生畏了。我想这取决于实施这一努力的回报。切换到mex API时,matlab功能本身是否还有可能会改善性能? – 5Ke

4

传递numpy的阵列有效

看看文件夹PYTHONPATH\Lib\site-packages\matlab\_internal在文件“mlarray_sequence.py”。在那里你会发现matlab数组对象的构造。性能问题来自使用generic_flattening函数中的循环复制数据。

为了避免这种情况,我们将编辑文件位。如果您还不想传递复数,则必须进行一些其他更改。

  • 首先复印一份找回原来的文件,如果某样东西错
  • 在文件的开头添加import numpy as np其他进口
  • 在第38行,你应该找到

    init_dims = _get_size(initializer) # replace this with 
        try: 
         init_dims=initializer.shape 
        except: 
         init_dims = _get_size(initializer) 
    
  • 在第54行,你应该找到

    self._data = flat(self, initializer, init_dims, typecode) # replace this with 
    try: 
        self._data = array.array(typecode,np.ravel(initializer, order='F')) 
    except: 
        self._data = flat(self, initializer, init_dims, typecode) 
    

现在您可以将一个numpy数组直接传递给matlab数组创建方法。

data1 = np.random.uniform(low = 0.0, high = 30000.0, size = (1000000,)) 
#faster 
data1m = matlab.double(data1) 
#or slower method 
data1m = matlab.double(data1.tolist()) 

matlab阵列创建的性能增加了15倍,现在界面更易于使用。

+0

感谢您的建议!当转换时间从40秒减少到0.6秒时,它看起来非常有前途。但是,当我使用它们作为输入时,现在我得到'Segmentation fault(核心转储)错误。逐步显示,在调用函数(而不是转换)时,future = pythonengine.evaluateFunction(...)[matlabengine.py中的第77行],_MLArrayMetaClass的__init__被再次调用,现在它跳过了已更改第38行:AtributeError:'double'对象没有'shape'属性。也许它试图在这里初始化函数的输出? – 5Ke

+0

我已经更新了我的代码。至少像b = engine.sqrt(data2m)这样的东西现在可以工作了。 – max9111

+0

是的,现在它工作!您的方法将总转换时间从40秒缩短到小于0.5秒! :-)它不会减少脚本本身的计算时间 - 这是完全有道理的,但它再次让我想知道为什么要保存/加载到.mat文件。 – 5Ke