【问题标题】:multithreaded blas in python/numpypython/numpy 中的多线程 blas
【发布时间】:2011-07-12 17:12:35
【问题描述】:

我正在尝试在 Python 中实现大量矩阵-矩阵乘法。最初,我假设 NumPy 会自动使用我的线程化 BLAS 库,因为我是针对这些库构建的。但是,当我查看 top 或其他内容时,似乎代码根本没有使用线程。

任何想法有什么问题或我可以做些什么来轻松使用 BLAS 性能?

【问题讨论】:

  • 你能说得更具体点吗?比如:large number 实际上有多大?你的矩阵的形状是什么?您目前的时间安排是什么?你的硬件特性?您期待(希望)什么样的性能改进?谢谢
  • @eat:矩阵大约为 1600x1600(双倍)。由于我正在解决一个非常大的耦合 ODE 系统,因此该代码执行了大量的矩阵矩阵乘法。仅在 Fortran 中使用 blas 而不是天真地循环矩阵乘法可以显着加快速度。我的系统上的线程可能应该做同样的事情。我希望加快订单 10 :)。
  • 是否愿意展示代码的相关部分,以便任何人都可以在自己的平台上使用它? (顺便说一句,您的矩阵是否接近满秩?如果它们恰好是低秩矩阵,那么存在加速计算的替代途径)。谢谢
  • 尽管我接受了下面的答案,但我想评论一下我遇到的其他问题:我安装的第一个 numpy 发行版不支持多线程。我终于安装了 epd 发行版,但发现它设置了一个 shell 变量 MKL_NUM_THREADS=1。我不知道为什么会这样,但是一旦在我的 bash_profile 中删除了这一行,问题就解决了。使用 linux 而不是 Mac OS 的朋友使用 epd 没有遇到这个问题。
  • @Lucas,我​​也从 .bash_profile 中删除了该变量,我也在 Mac OS X 上使用 EPD。我的问题没有解决。 Numpy.dot 仍然只使用一个核心。你还做了什么?

标签: python numpy scientific-computing blas


【解决方案1】:

并不是所有的 NumPy 都使用 BLAS,只有一些函数——特别是 dot()vdot()innerproduct() 以及来自 numpy.linalg 模块的几个函数。另请注意,许多 NumPy 操作受到大型数组的内存带宽的限制,因此优化的实现不太可能带来任何改进。如果您受到内存带宽的限制,多线程能否提供更好的性能在很大程度上取决于您的硬件。

【讨论】:

  • 听起来不太好。我希望我可以在 python 中以某种方式解决这个问题。如果我想使用 numpy 中的特定函数调用硬编码的矩阵乘法子例程,您认为使用 weave 之类的东西在 C 或 Fortran 中进行矩阵乘法是否值得?
  • @Lucas:NumPy 中的矩阵乘法应该由numpy.dot() 完成,也在内部完成。但是在不知道你实际在做什么的情况下,几乎不可能给出进一步的建议。也许你想打开一个新的 uqestion。
【解决方案2】:

可能是因为 Matrix x Matrix 乘法受内存限制,因此在同一内存层次结构上添加额外的内核不会给您带来太多好处。当然,如果您在切换到 Fortran 实现时看到显着加速,那么我可能是不正确的。

我的理解是,对于这类问题,适当的缓存比计算能力重要得多。大概 BLAS 会为您执行此操作。

对于一个简单的测试,您可以尝试安装Enthought's python 发行版进行比较。它们与英特尔的Math Kernel Library 链接,我相信如果可用,它会利用多个内核。

【讨论】:

    【解决方案3】:

    我已经在另一个线程中发布了这个,但我认为它更适合这个:

    更新(2014 年 7 月 30 日):

    我在我们的新 HPC 上重新运行基准测试。 硬件和软件堆栈都与原始答案中的设置有所不同。

    我将结果放在google spreadsheet 中(还包含原始答案的结果)。

    硬件

    我们的 HPC 有两个不同的节点,一个使用 Intel Sandy Bridge CPU,一个使用较新的 Ivy Bridge CPU:

    桑迪(MKL、OpenBLAS、ATLAS):

    • CPU:2 x 16 Intel(R) Xeon(R) E2560 Sandy Bridge @ 2.00GHz(16 核)
    • 内存:64 GB

    常春藤(MKL、OpenBLAS、ATLAS):

    • CPU:2 x 20 Intel(R) Xeon(R) E2680 V2 Ivy Bridge @ 2.80GHz(20 核,HT = 40 核)
    • 内存:256 GB

    软件

    软件堆栈适用于 sam 的两个节点。代替 GotoBLAS2,使用 OpenBLAS,还有一个设置为 8 个线程(硬编码)的 多线程 ATLAS BLAS。

    • 操作系统:Suse
    • 英特尔编译器:ictce-5.3.0
    • Numpy: 1.8.0
    • OpenBLAS: 0.2.6
    • 图集::3.8.4

    点积基准

    基准代码与以下相同。但是对于新机器,我还运行了矩阵大小 50008000 的基准测试。
    下表包括原始答案的基准测试结果(重命名为:MKL --> Nehalem MKL、Netlib Blas --> Nehalem Netlib BLAS 等)

    单线程性能:

    多线程性能(8 个线程):

    线程与矩阵大小(Ivy Bridge MKL)

    基准套件

    单线程性能:

    多线程(8 线程)性能:

    结论

    新的基准测试结果与原始答案中的结果相似。 OpenBLASMKL 性能相同,除了 特征值 检验。 特征值测试仅在单线程模式下的OpenBLAS上表现得相当好。 在多线程模式下,性能更差。

    “矩阵大小与线程图表”还表明,尽管 MKL 和 OpenBLAS 通常可以很好地扩展内核/线程数,但这取决于矩阵的大小。对于小型矩阵,添加更多内核不会大大提高性能。

    Sandy BridgeIvy Bridge 的性能也提高了大约 30%,这可能是由于更高的时钟频率(+ 0.8 Ghz)和/或更好的架构.


    原始答案 (04.10.2011):

    前段时间,我不得不优化一些使用 numpy 和 BLAS 用 python 编写的线性代数计算/算法,因此我对不同的 numpy/BLAS 配置进行了基准测试/测试。

    我具体测试过:

    • 带有 ATLAS 的 Numpy
    • Numpy 与 GotoBlas2 (1.13)
    • Numpy 与 MKL (11.1/073)
    • 带有加速框架的 Numpy (Mac OS X)

    我确实运行了两个不同的基准测试:

    1. 不同大小矩阵的简单点积
    2. 可以在here找到的基准套件。

    这是我的结果:

    机器

    Linux(MKL、ATLAS、No-MKL、GotoBlas2):

    • 操作系统:Ubuntu Lucid 10.4 64 位。
    • CPU:2 x 4 Intel(R) Xeon(R) E5504 @ 2.00GHz(8 核)
    • 内存:24 GB
    • 英特尔编译器:11.1/073
    • Scipy:0.8
    • Numpy:1.5

    Mac Book Pro(加速框架):

    • 操作系统:Mac OS X Snow Leopard (10.6)
    • CPU:1 个 Intel Core 2 Duo 2.93 Ghz(2 个内核)
    • 内存:4 GB
    • Scipy:0.7
    • Numpy:1.3

    Mac 服务器(加速框架):

    • 操作系统:Mac OS X Snow Leopard Server (10.6)
    • CPU:4 X Intel(R) Xeon(R) E5520 @ 2.26 Ghz(8 核)
    • 内存:4 GB
    • Scipy:0.8
    • Numpy:1.5.1

    点积基准

    代码

    import numpy as np
    a = np.random.random_sample((size,size))
    b = np.random.random_sample((size,size))
    %timeit np.dot(a,b)
    

    结果

    系统 |大小 = 1000 |大小 = 2000 |大小 = 3000 | netlib BLAS | 1350 毫秒 | 10900 毫秒 | 39200 毫秒 | ATLAS (1 CPU) | 314 毫秒 | 2560 毫秒 | 8700 毫秒 | MKL(1 个 CPU)| 268 毫秒 | 2110 毫秒 | 7120 毫秒 | MKL(2 个 CPU)| - | - | 3660 毫秒 | MKL(8 个 CPU)| 39 毫秒 | 319 毫秒 | 1000 毫秒 | GotoBlas2 (1 CPU) | 266 毫秒 | 2100 毫秒 | 7280 毫秒 | GotoBlas2(2 个 CPU)| 139 毫秒 | 1009 毫秒 | 3690 毫秒 | GotoBlas2(8 个 CPU)| 54 毫秒 | 389 毫秒 | 1250 毫秒 | Mac OS X (1 CPU) | 143 毫秒 | 1060 毫秒 | 3605 毫秒 | Mac 服务器(1 个 CPU)| 92 毫秒 | 714 毫秒 | 2130 毫秒 |

    基准套件

    代码
    有关基准套件的更多信息,请参阅here

    结果

    系统 |特征值 | svd |检测 |库存 |点 | netlib BLAS | 1688 毫秒 | 13102 毫秒 | 438 毫秒 | 2155 毫秒 | 3522 毫秒 | ATLAS (1 CPU) | 1210 毫秒 | 5897 毫秒 | 170 毫秒 | 560 毫秒 | 893 毫秒 | MKL(1 个 CPU)| 691 毫秒 | 4475 毫秒 | 141 毫秒 | 450 毫秒 | 736 毫秒 | MKL(2 个 CPU)| 552 毫秒 | 2718 毫秒 | 96 毫秒 | 267 毫秒 | 423 毫秒 | MKL(8 个 CPU)| 525 毫秒 | 1679 毫秒 | 60 毫秒 | 137 毫秒 | 197 毫秒 | GotoBlas2 (1 CPU) | 2124 毫秒 | 4636 毫秒 | 147 毫秒 | 456 毫秒 | 743 毫秒 | GotoBlas2(2 个 CPU)| 1560 毫秒 | 3278 毫秒 | 116 毫秒 | 295 毫秒 | 460 毫秒 | GotoBlas2(8 个 CPU)| 741 毫秒 | 2914 毫秒 | 82 毫秒 | 262 毫秒 | 192 毫秒 | Mac OS X (1 CPU) | 948 毫秒 | 4339 毫秒 | 151 毫秒 | 318 毫秒 | 566 毫秒 | Mac 服务器(1 个 CPU)| 1033 毫秒 | 3645 毫秒 | 99 毫秒 | 232 毫秒 | 342 毫秒 |

    安装

    MKL 的安装包括安装完整的英特尔编译器套件,这非常简单。然而,由于一些错误/问题,使用 MKL 支持配置和编译 numpy 有点麻烦。

    GotoBlas2 是一个可以轻松编译为共享库的小包。但是,由于bug,您必须在构建共享库后重新创建它才能与 numpy 一起使用它。
    除了为多个目标平台构建它之外,由于某种原因,它无法正常工作。所以我必须为每个平台创建一个 .so 文件,我希望有一个优化的 libgoto2.so 文件。

    如果您从 Ubuntu 的存储库安装 numpy,它将自动安装和配置 numpy 以使用 ATLAS。从源代码安装 ATLAS 可能需要一些时间并且需要一些额外的步骤(fortran 等)。

    如果您在带有 FinkMac Ports 的 Mac OS X 机器上安装 numpy,它会将 numpy 配置为使用 ATLASApple 的加速框架。 您可以通过在 numpy.core._dotblas 文件上运行 ldd 或调用 numpy.show_config() 来检查。

    结论

    MKL 表现最好,紧随其后的是 GotoBlas2
    特征值 测试中,GotoBlas2 的表现出人意料地差于预期。不知道为什么会这样。
    Apple 的 Accelerate Framework 性能非常好,尤其是在单线程模式下(与其他 BLAS 实现相比)。

    GotoBlas2MKL 都可以很好地扩展线程数。因此,如果您必须处理在多个线程上运行的大型矩阵,将会有很大帮助。

    在任何情况下都不要使用默认的 netlib blas 实现,因为它对于任何严肃的计算工作来说都太慢了。

    在我们的集群上,我还安装了 AMD 的 ACML,性能类似于 MKLGotoBlas2。我没有任何数字很难。

    我个人会推荐使用 GotoBlas2,因为它更容易安装并且是免费的。

    如果您想用 C++/C 编写代码,还请查看 Eigen3,它在某些 cases 中的性能应该优于 MKL/GotoBlas2,并且也非常易于使用。

    【讨论】:

    • 感谢分享。你知道 Apple 的 Accelerate Framework 是利用多核还是超线程?我猜不是,因为据我所知,您的“Mac 服务器”有 4 个内核,但您能确认一下吗?另外,对于 ATLAS,您是否暗示它只能使用 1 个核心(我只看到这种情况下的结果)?
    • Accelerate Framework 默认只使用一个内核。老实说,我不知道您是否可以将其设置为使用多个核心。开发人员页面上没有任何内容:developer.apple.com/library/mac/#featuredarticles/… 关于 ATLAS:默认的 ATLAS 安装是单线程的。不过也有一个多线程的 ATLAS 版本(AT93 左右)。见这里:cran.r-project.org/web/packages/gcbd/vignettes/gcbd.pdf
    • @EOL 苹果加速在我的山狮 Mac 上使用了我的所有四个内核。苹果 python 2.7.2 上的 Numpy 1.6.1
    • @Ümit 你如何让 numpy 在集群上使用多线程?我在一台笔记本电脑(Apple python 和另一台使用针对 MKL 构建的 enthought 的机器)上获得了 numpy 到多线程,但是当我向我们的集群发送一个作业要求使用 8 个内核时(在一台使用多线程构建的 numpy 的机器上) blas),它并不比使用单核快。我的下一个问题是你如何真正知道哪些库 numpy 函数正在使用?我做`>>> import inspect >>> import numpy as np >>> inspect.getmodule(np.dot) 'numpy.core._dotblas' 我在所有三种不同的python(苹果,enthought,集群)上都得到了这个跨度>
    • 近五年后,这个答案仍然是史诗般的。仍然是规范的 Numpy 加速基准。只有一个增加可能会增加史诗般的赌注:一个 BLIS 链接的 Numpy 基准。然而,乞丐不能成为选择者。我选择你,Ümit
    【解决方案4】:

    您听说过岩浆吗? GPU 和多核架构上的矩阵代数 http://icl.cs.utk.edu/magma/

    MAGMA 项目旨在开发一个类似于 LAPACK 的密集线性代数库,但适用于异构/混合架构,从当前的“多核+GPU”系统开始。

    【讨论】:

    • MCVE——类似的文化也要求量化——说明什么过程/花了多少时间完成/ 在什么特殊情况下。技术营销往往会忽略这些可量化的可验证事实,因此请不要犹豫,要么请求它们,要么自行生成它们,或者不要重新长号以公关为动机的文本。不要忘记,多核,更多的 GPU 引擎,受其(内部)延迟屏蔽架构的影响,并且由于它们专注于数字运算,迟早会遇到 I/O 带宽障碍。真正的并行设计经历了这一点
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多