为什么在这个简单的情况下,Matlab看起来比Python慢得多?

4

最近我在Matlab中优化一个掩码函数的问题上提出了一个问题。我得到了两个答案,这些答案对我很有帮助,但是根据我的计时,所有的Matlab解决方案似乎都比Numpy的解决方案慢得多。不过,不同函数的代码可以在我的之前的问题中找到,为了给大家一个想法,我提供了Numpy“loop”解决方案,当然这不是最快的,但可能是最简单易读的:

def dealiasing2d(where, data):
    nk, n0, n1 = data.shape
    for i0 in xrange(n0):
        for i1 in xrange(n1):
            if where[i0, i1]:
                data[:, i0, i1] = 0.

我使用Matlab R2014b和与Blas和Lapack链接的“基本”Numpy 1.9.1(n0 = n1 = N)获得以下结果:

N = 500 ; nk = 500:
Method          | time (s) | normalized      
----------------|----------|------------
Numpy           |    0.05  |     1.0
Numpy loop      |    0.05  |     1.0
Matlab find     |    0.74  |    14.8
Matlab bsxfun2  |    0.76  |    15.2
Matlab bsxfun   |    0.78  |    15.6
Matlab loop     |    0.78  |    15.6
Matlab repmat   |    0.89  |    17.8

N = 500 ; nk = 100:
Method          | time (s) | normalized      
----------------|----------|------------
Numpy           |    0.01  |     1.0
Numpy loop      |    0.03  |     3.0
Matlab find     |    0.15  |    13.6
Matlab bsxfun2  |    0.15  |    13.6
Matlab bsxfun   |    0.16  |    14.5
Matlab loop     |    0.16  |    14.5
Matlab repmat   |    0.18  |    16.4

N = 2000 ; nk = 10:
Method          | time (s) | normalized      
----------------|----------|------------
Numpy           |    0.02  |     1.0
Matlab find     |    0.23  |    13.8
Matlab bsxfun2  |    0.23  |    13.8
Matlab bsxfun   |    0.26  |    15.6
Matlab repmat   |    0.28  |    16.8
Matlab loop     |    0.34  |    20.4
Numpy loop      |    0.42  |    25.1

我觉得这些结果非常奇怪。对我来说,Numpy和Matlab在科学计算方面非常相似,因此性能应该相似,但是这里的差距超过了10倍!所以我第一个猜测是我比较两种语言的方式有问题。另一种可能是我的Matlab设置有问题,但我不明白为什么会出现这种情况。还有就是Matlab和Numpy之间存在真正的深层差异吗?
有人可以测试这些函数并验证这些结果吗?您有没有想法为什么在这种简单的情况下Matlab似乎比Python慢得多?
为了测试Matlab函数,我使用了一个文件:
N = 500;
n0 = N;
n1 = N;
nk = 500;
disp(['N = ', num2str(N), ' ; nk = ', num2str(nk)])

where = false([n1, n0]);
where(1:100, 1:100) = 1;
data = (5.+1i)*ones([n1, n0, nk]);

disp('time dealiasing2d_loops:')
time = timeit(@() dealiasing2d_loops(where, data));
disp(['     ', num2str(time), ' s'])

disp('time dealiasing2d_find:')
time = timeit(@() dealiasing2d_find(where, data));
disp(['     ', num2str(time), ' s'])

disp('time dealiasing2d_bsxfun:')
time = timeit(@() dealiasing2d_bsxfun(where, data));
disp(['     ', num2str(time), ' s'])

disp('time dealiasing2d_bsxfun2:')
time = timeit(@() dealiasing2d_bsxfun2(where, data));
disp(['     ', num2str(time), ' s'])

disp('time dealiasing2d_repmat:')
time = timeit(@() dealiasing2d_repmat(where, data));
disp(['     ', num2str(time), ' s'])

我使用以下方法来衡量Python函数的性能:

from __future__ import print_function

import numpy as np
from timeit import timeit, repeat

import_lines = {
    'numpy_bad': 'from dealiasing_numpy_bad import dealiasing2d as dealiasing',
    'numpy': 'from dealiasing_numpy import dealiasing'}
tools = import_lines.keys()

time_approx_one_bench = 5.

setup = """
import numpy as np

N = 500
n0, n1 = N, N
nk = 500
where = np.zeros((n0, n1), dtype=np.uint8)
where[0:100, 0:100] = 1
data = (5.+1j)*np.ones((nk, n0, n1), dtype=np.complex128)
"""
exec(setup)

print('n0 = n1 = {}, nk = {}'.format(N, nk))
print(13*' ' + 'min          mean')
durations = np.empty([len(tools)])

for it, tool in enumerate(tools):
    setup_tool = import_lines[tool] + setup
    duration = timeit(setup_tool + 'dealiasing(where, data)', number=1)
    nb_repeat = int(round((time_approx_one_bench - duration)/duration))
    nb_repeat = max(1, nb_repeat)
    ds = np.array(repeat('dealiasing(where, data)',
                         setup=setup_tool, number=1, repeat=nb_repeat))
    duration = ds.min()
    print('{:11s} {:8.2e} s ; {:8.2e} s'.format(
        tool.capitalize() + ':', duration, ds.mean()))
    durations[it] = duration

fastest = tools[durations.argmin()].capitalize()

durations = durations / durations.min()
print('Durations normalized by the fastest method (' + fastest + '):')
for it, tool in enumerate(tools):
    print('{:11s} {:8.3f}'.format(tool.capitalize() + ':', durations[it]))

1
不确定这是否有帮助,但是可能会影响您的测试的一件事是,在MATLAB中调用匿名函数非常慢。匿名函数实际上是最慢的,部分原因是它们需要重新创建被调用的工作区的一部分。其次(但这是个人偏好)--我不喜欢timeit(),因为它计算执行时间的中位数,而不是最小值。这意味着在计时函数时,开销非常大。 - user2271770
这里有一份语言比较表:http://julialang.org/benchmarks/ --- 主要是基于没有数组向量化的基准测试。在这个基准测试中,Python解释器速度似乎相当稳定。 - pv.
1个回答

3

我认为这主要与复制data变量有关。如果你安排好MATLAB的写时复制行为,就可以得到相当不错的时间。我使用线性索引编写了一个简单的版本。

function data = dealiasing2d2(where_dealiased, data)
[n1, n2, nk] = size(data);
where_li = find(where_dealiased);
for idx = 1:nk
  offset = n1 * n2 * (idx-1);
  data(where_li + offset) = 0;
end

我这样运行它(注意,重要的是timed是一个函数而不是脚本,以允许data被重复使用)

function timed
N = 2000;
nk = 10;

where = false([N, N]);
where(1:100, 1:100) = 1;
data = (5.+1j)*ones([N, N, nk]);
tic, data = dealiasing2d2(where,data); toc

这段代码在我运行R2014b的GLNXA64机器上,仅用了0.00437秒。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接