【问题标题】:What could be wrong with this matrix multiplication benchmark (Matlab vs Numpy)?这个矩阵乘法基准(Matlab vs Numpy)可能有什么问题?
【发布时间】:2016-04-12 09:23:06
【问题描述】:

这是我为比较 numpy 与 Matlab 的性能而编写的代码。它只是测量矩阵乘法的平均时间(1701x576 矩阵 M1 * 576x576 矩阵 M2)。

Matlab 版本:(M1 为 (1701x576) 而 M2 为 (576x576) 矩阵)

function r = benchmark(M1,M2) 
    total_time=0;

    for i=1:4        
        for j=1:1500
            tic;
            a=M1*M2;
            tim=toc;
            total_time =total_time+tim;
        end     
    end        
    avg_time = total_time/4  
    r=avg_time
end

Python 版本

def benchmark():
    iters = range(1500)
    for i in range(4):      
        for j in iters:         
            tic = time.time()
            a=M1.dot(M2);
            toc = time.time() - tic
            t_time=t_time+toc;
    return t_time/4

Matlab 版本大约需要 ~18.2s ,而 Python 需要 ~19.3s 。我已经多次重复这个测试,并且在所有情况下,Matlab 的性能总是比 Python 好(即使差异较小)。我的理解是 Numpy 使用高效的编译代码进行向量运算,并且应该比 Matlab 更快。

那么,为什么 Matlab 的性能比 Numpy 快?测试是在 32 核机器上完成的。 我哪里做错了 ?还是预计 Numpy 会比 Matlab 慢。

有没有办法提高 Python 的性能?

编辑:更新了 matlab 代码以修复循环索引/返回值错误。该错误是由于我试图在发布之前编辑狙击手中的名称以使其可呈现(每次都是一个坏主意:))。

【问题讨论】:

  • Python 版本会因为重复的属性查找而产生少量开销。您可以尝试在循环之外执行dot = M1.dot,然后在您的定时部分执行dot(M2)。同样预存time = time.time。更一般地说,我不确定将完全相同的点积计算 6000 次是否是一个很好的基准。
  • 我相信 MATLAB 也使用高效的编译代码进行向量运算。我建议计算持续时间的最小值,因为这将为您提供执行相同计算的最接近的猜测。并且 tic/toc 测量挂钟时间并存在一些问题,timeit(已经存在于较新版本的 MATLAB 中)应该更准确。
  • 假设M1M2 是浮点数组,np.dot 的性能将主要取决于在运行时链接哪个BLAS 库numpy,而不是numpy 本身。您可以从np.show_config() 的输出中找到这一点。我相信 MATLAB 使用英特尔的数学内核库 (MKL)。
  • 另外,您的 MATLAB 函数返回 r 而不是 avg_time
  • 我已经编辑了代码 sn-p 来修复返回变量和循环索引问题

标签: python performance matlab numpy linear-algebra


【解决方案1】:

[编辑删除循环的提及;那是我的错误]

几件事--

首先,机器的多核特性并不重要,除非您明确使用这些额外的内核(或将 NumPy 与使用多核的 BLAS 库链接——感谢@ali_m)。如果不是这样,它在 32 核机器上的运行速度与在 4 核机器上的运行速度差不多(假设内核本身的时钟速度大致相等)。

其次,使用纯现成的 Matlab 与现成的 NumPy,Matlab generally beats out NumPy。不过,这是一个非常笼统的陈述; YMMV。另外,说到 Matlab,在循环索引中确实似乎存在一个错误。

第三,这可能不是性能的最佳基准;引擎盖下可能会发生一些不明显的缓存问题。更好的方法是在每次迭代中即时随机生成矩阵并将它们相乘,但根据随机数生成器的不同,即使这样也可能会出现问题。

【讨论】:

  • 他的基准测试并没有进行任何循环计算。他的循环只运行基准测试迭代。
  • 是的,但是简单地使用range 创建列表会在 Python 2 中导致性能损失。在 Python 3 中,一切都是生成器,因此它不应该是一个(或实际上任何一个)问题。
  • 啊,我明白你的意思了——不知何故错过了他只对循环本身内的计算部分进行计时的部分。编辑我的帖子;谢谢@BrenBarn
  • np.dot 通常会调用外部 BLAS 例程,根据运行时 numpy 链接到的 BLAS 库,它很可能会使用多个内核。
【解决方案2】:

我可以从测试中看到两个主要问题。

首先是您在 Python 中使用全局变量查找,而在 MATLAB 中使用局部变量查找。 Python 中的全局变量查找相对较慢。确保变量是局部变量,就像它们在 MATLAB 中一样会影响性能。

第二个是你一遍又一遍地重新做同样的计算。 MATLAB有JIT for循环,numpy有计算缓存,两者都可以减少重复计算的时间。

因此,为了使比较更加平等和可靠,您应该在每次循环中创建新的随机矩阵。这将防止缓存和 JIT 弄乱您的结果,并确保变量都是本地的。

【讨论】:

    【解决方案3】:

    您的 Matlab 代码中存在错误。您似乎在嵌套循环中使用相同的循环控制变量。

    外层循环实际上只运行一次。

    编辑:外部循环实际上运行了正确的次数。这两个循环控制变量似乎是独立的。

    【讨论】:

    • 外循环运行 4 次,不考虑重复变量。对于一个简单的例子运行for i=1:3 for i=1:3 disp(i), end, end
    • 我永远不会尝试这样的事情。它只是在我看来不合适。 @Daniel,您的代码和预期的原始工作。看起来我需要更新我的 Matlab 范围规则。感谢您提供新信息。
    • 我想每个人都应该意识到这种废话
    • 这个回答说的不是真的
    猜你喜欢
    • 1970-01-01
    • 2014-08-28
    • 2015-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-24
    • 1970-01-01
    • 2022-06-10
    相关资源
    最近更新 更多