不同BLAS实现对NumPy性能的影响

12

我正在运行一个使用Python和NumPy实现的算法。该算法中计算量最大的部分涉及解决一组线性系统(即调用numpy.linalg.solve())。我设计了这个小型基准测试:

import numpy as np
import time

# Create two large random matrices
a = np.random.randn(5000, 5000)
b = np.random.randn(5000, 5000)

t1 = time.time()
# That's the expensive call:
np.linalg.solve(a, b)
print time.time() - t1

我已经在以下平台上运行过:

  1. 我的笔记本电脑,一台2013年底的MacBook Pro 15寸,拥有4个2GHz的内核(sysctl -n machdep.cpu.brand_string输出为Intel(R) Core(TM) i7-4750HQ CPU @ 2.00GHz
  2. 一个Amazon EC2 c3.xlarge实例,有4个虚拟CPU。亚马逊将它们推广为“高频率Intel Xeon E5-2680 v2 (Ivy Bridge)处理器”

总结:

  • 在Mac上运行需要大约4.5秒
  • 在EC2实例上运行需要大约19.5秒

我还尝试在其他基于OpenBLAS / Intel MKL的设置上运行它,运行时间总是与我在EC2实例上获得的运行时间相当(除了硬件配置)。

有人能解释为什么Mac上的表现(使用Accelerate Framework)比其他环境要好4倍以上吗?下面提供了有关每个NumPy / BLAS设置的详细信息。

笔记本电脑设置

numpy.show_config() 输出:

atlas_threads_info:
  NOT AVAILABLE
blas_opt_info:
    extra_link_args = ['-Wl,-framework', '-Wl,Accelerate']
    extra_compile_args = ['-msse3', '-I/System/Library/Frameworks/vecLib.framework/Headers']
    define_macros = [('NO_ATLAS_INFO', 3)]
atlas_blas_threads_info:
  NOT AVAILABLE
openblas_info:
  NOT AVAILABLE
lapack_opt_info:
    extra_link_args = ['-Wl,-framework', '-Wl,Accelerate']
    extra_compile_args = ['-msse3']
    define_macros = [('NO_ATLAS_INFO', 3)]
atlas_info:
  NOT AVAILABLE
lapack_mkl_info:
  NOT AVAILABLE
blas_mkl_info:
  NOT AVAILABLE
atlas_blas_info:
  NOT AVAILABLE
mkl_info:
  NOT AVAILABLE

EC2实例设置:

在Ubuntu 14.04上,我使用以下命令安装了OpenBLAS:

sudo apt-get install libopenblas-base libopenblas-dev
安装NumPy时,我创建了一个名为site.cfg的文件,并将以下内容添加到其中:
[default]
library_dirs= /usr/lib/openblas-base

[atlas]
atlas_libs = openblas

numpy.show_config() 给出:

atlas_threads_info:
    libraries = ['lapack', 'openblas']
    library_dirs = ['/usr/lib']
    define_macros = [('ATLAS_INFO', '"\\"None\\""')]
    language = f77
    include_dirs = ['/usr/include/atlas']
blas_opt_info:
    libraries = ['openblas']
    library_dirs = ['/usr/lib']
    language = f77
openblas_info:
    libraries = ['openblas']
    library_dirs = ['/usr/lib']
    language = f77
lapack_opt_info:
    libraries = ['lapack', 'openblas']
    library_dirs = ['/usr/lib']
    define_macros = [('ATLAS_INFO', '"\\"None\\""')]
    language = f77
    include_dirs = ['/usr/include/atlas']
openblas_lapack_info:
  NOT AVAILABLE
lapack_mkl_info:
  NOT AVAILABLE
blas_mkl_info:
  NOT AVAILABLE
mkl_info:
  NOT AVAILABLE

2
Haswell每个周期每个核心的原始计算能力比Ivybridge高2倍(由于包含FMA)。我想知道你的openblas是否没有启用AVX支持进行构建?这将再增加2倍。 - Stephen Canon
1
听起来可能与这个有关。你能检查一下你的EC2实例是否真的在进行多线程BLAS操作吗? - ali_m
1个回答

3
这种行为的原因可能是Accelerate使用了多线程,而其他库没有。
大多数BLAS实现都遵循环境变量OMP_NUM_THREADS来确定使用多少个线程。我认为如果没有明确指定,则它们只使用1个线程。Accelerate的手册页面,然而听起来默认情况下启用了线程;可以通过设置环境变量VECLIB_MAXIMUM_THREADS来关闭它。
要确定这是否真的是发生的事情,请尝试:
export VECLIB_MAXIMUM_THREADS=1

在调用加速版本之前,

export OMP_NUM_THREADS=4

针对其他版本。

无论这是否是真正的原因,当您使用BLAS时,始终设置这些变量都是一个好主意,以确保您控制正在发生的事情。


与加速器相关的VECLIB_MAXIMUM_THREADS确实会影响numpy.linalg.norm的性能。另一方面,scipy.linalg.norm则始终较慢且不受该变量的影响,这让我相信它并非与加速器有关,而是使用了参考LAPACK。 - Elmar Peise
谢谢Elmar。顺便说一下,scipy.linalg.norm执行if ord in (None, 2) and (a.ndim == 1): nrm2 = get_blas_funcs('nrm2')numpy.linalg.linalg中的norm说:“#立即处理一些默认、简单、快速和常见的情况”。总体来说,太复杂了。 - denis

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