将ATLAS/MKL链接到已安装的Numpy

24

TL;DR: 如何将ATLAS/MKL链接到现有的Numpy而无需重新构建。

我使用Numpy进行大矩阵计算时发现速度非常慢,因为Numpy只使用1个核心进行计算。经过许多搜索后,我发现我的Numpy没有链接到一些优化库,例如ATLAS/MKL。这是我的Numpy配置:

>>>import numpy as np
>>>np.__config__.show()
blas_info:
    libraries = ['blas']
    library_dirs = ['/usr/lib']
    language = f77
lapack_info:
    libraries = ['lapack']
    library_dirs = ['/usr/lib']
    language = f77
atlas_threads_info:
    NOT AVAILABLE
blas_opt_info:
    libraries = ['blas']
    library_dirs = ['/usr/lib']
    language = f77
    define_macros = [('NO_ATLAS_INFO', 1)]
atlas_blas_threads_info:
  NOT AVAILABLE
openblas_info:
  NOT AVAILABLE
lapack_opt_info:
    libraries = ['lapack', 'blas']
    library_dirs = ['/usr/lib']
    language = f77
    define_macros = [('NO_ATLAS_INFO', 1)]
atlas_info:
  NOT AVAILABLE
lapack_mkl_info:
  NOT AVAILABLE
blas_mkl_info:
  NOT AVAILABLE
atlas_blas_info:
  NOT AVAILABLE
mkl_info:
  NOT AVAILABLE

因此,我想将ATLAS/MKL链接到Numpy。但是,我的Numpy是从PIP安装的,所以我不想手动安装,因为我想使用最新版本。我搜索过一些内容,但它们只适用于从头构建。因此,我的问题是:

  • 是否有任何方法可以在不重新构建的情况下将ATLAS/MKL链接到Numpy?
  • 我发现配置信息保存在已安装的Numpy文件夹中的_config_.py中。那么修改它能解决我的问题吗?如果可以,请告诉我如何操作。
2个回答

28
假设您正在运行某种Linux系统,以下是一种可能的方法:
假设您正在运行某种Linux系统,以下是一种可能的方法:
  1. Find out what BLAS library numpy is currently linked against using ldd.

    • For versions of numpy older than v1.10:

      $ ldd /<path_to_site-packages>/numpy/core/_dotblas.so
      

      For example, if I install numpy via apt-get, it links to

      ...
      libblas.so.3 => /usr/lib/libblas.so.3 (0x00007fed81de8000)
      ...
      

      If _dotblas.so doesn't exist, this probably means that numpy failed to detect any BLAS libraries when it was originally installed, in which case it simply doesn't build any of the BLAS-dependent components. This often happens if you install numpy using pip without manually specifying a BLAS library (see below). I'm afraid you'll have no option but to rebuild numpy if you want to link against an external BLAS library.


    • For numpy v1.10 and newer:

      _dotblas.so has been removed from recent versions of numpy, but you should be able to check the dependencies of multiarray.so instead:

      $ ldd /<path_to_site-packages>/numpy/core/multiarray.so
      
  2. Install ATLAS/MKL/OpenBLAS if you haven't already. By the way, I would definitely recommend OpenBLAS over ATLAS - take a look at this answer (although the benchmarking data is now probably a bit out of date).

  3. Use update-alternatives to create a symlink to the new BLAS library of your choice. For example, if you installed libopenblas.so into /opt/OpenBLAS/lib, you would do:

    $ sudo update-alternatives --install /usr/lib/libblas.so.3 \
                                         libblas.so.3 \
                                         /opt/OpenBLAS/lib/libopenblas.so \
                                         50
    

    You can have multiple symlinks configured for a single target library, allowing you to manually switch between multiple installed BLAS libraries.

    For example, when I call $ sudo update-alternatives --config libblas.so.3, I can choose between one of 3 libraries:

      Selection    Path                                    Priority   Status
    ------------------------------------------------------------
      0            /opt/OpenBLAS/lib/libopenblas.so         40        auto mode
      1            /opt/OpenBLAS/lib/libopenblas.so         40        manual mode
      2            /usr/lib/atlas-base/atlas/libblas.so.3   35        manual mode
    * 3            /usr/lib/libblas/libblas.so.3            10        manual mode
    
如果你真的想要“最新”的numpy版本,你也可以查看我关于使用OpenBLAS集成从源代码编译numpy的答案
使用pip安装支持BLAS的numpy
如@tndoan在评论中提到的那样,可以通过在~/.numpy-site.cfg中放置一个配置文件来使pip遵循特定的numpy配置 - 有关更多详细信息,请参见此答案
我个人偏好手动配置和构建numpy。这并不特别困难,而且可以更好地控制numpy的配置。

2
对于仍想使用配置文件重新安装pip的人,这里是他们的解决方案。@ali_m:您能否编辑您的帖子并将此链接放入您的答案中。谢谢。 - tndoan
关于使用openBlas的建议,我在http://www.scipy.org/scipylib/building/linux.html上找到了这个信息。 截至2014年1月,ATLAS是推荐使用的库,因为当与multiprocessing模块(或任何os.fork的使用)结合使用时,OpenBLAS会出现死锁,并且旧版本(<= 0.2.8)在处理更大的问题规模时往往会崩溃。 - LGenzelis
@LGenzelis 我相信这个问题已经在这个PR中得到了解决,该PR的日期为2014年2月19日(请参见此处的讨论)。就在几天前,我构建了最新版本的numpy(v1.11.0)和OpenBLAS(v0.2.17),并在使用multiprocessing的代码中使用它们,没有出现任何问题。不幸的是,numpy文档的这部分内容已经很长时间没有更新了。 - ali_m
@ali_m,谢谢你的信息。不过,我不建议使用OpenBLAS。在阅读了你的回答后,我安装了它(从apt-get),并重新编译了scipy和numpy。然而,我的代码运行速度变慢了3倍,所以我又回到了ATLAS。 - LGenzelis
@LGenzelis 我建议从源代码构建OpenBLAS的原因是很充分的。软件包维护者提供的二进制文件通常是旧版本(它们可能仍然包含你提到的分支错误),而且由于它们不是本地编译的,可能无法使用特定CPU可用的所有核心和指令集(尤其是如果它是相当新型号的)。如果您非常关心性能,则从源代码构建ATLAS也比通过apt-get安装要好,但在我的经验中,ATLAS更难编译,速度比OpenBLAS慢得多。 - ali_m
显示剩余3条评论

1
答案取决于NumPy最初是如何构建的。如果它是针对BLAS和LAPACK进行构建的,那么至少没有办法强制numpy.dot在重新构建之前使用ATLAS/MKL。其他函数不使用numpy.dot,您可以使用update-alternatives更改符号链接libblas.so.3liblapack.so.3的目标。这是因为numpy.dot需要ATLAS风格的CBLAS,或者OpenBLAS/MKL,而不是来自netlib的BLAS/CBLAS和LAPACK。
我正在使用openSUSE,并已从netlib安装了标准的cblas-devel。然而,似乎不可能强制NumPy使用提供的cblas/cblas-devel。也就是说,如果您将NumPy构建为使用netlib BLAS/LAPACK/CBLAS(作为官方包) ,那么_dotblas.so(提供numpy.dot的BLAS版本)无法构建(在1.10之前),或者multiarray.so(1.10及更高版本)根本不链接到libblas.so.3。请参见github上的问题:https://github.com/numpy/numpy/issues/1265和引用的Debian错误报告:https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=464784。也许有人可以深入源代码来进行修补...无论如何,只有一个受影响的函数(numpy.dot),您总是可以使用更快的OpenBLAS轻松地重新构建整个NumPy,所以可能并不重要。 结论:您可以稍后链接到ATLAS/MKL/OpenBLAS,而无需重新构建,但是如果NumPy最初没有针对ATLAS/MKL/OpenBLAS进行构建,则numpy.dot仍将非常缓慢(因为numpy.dot一开始根本没有使用任何BLAS,在编译完成后无法更改)。 更新:实际上,您可以强制numpy构建_dotblas.so。我已经为numpy-1.9.2制作了一个补丁:
diff -Npru numpy-1.9.2.orig/numpy/core/setup.py numpy-1.9.2/numpy/core/setup.py
--- numpy-1.9.2.orig/numpy/core/setup.py        2015-02-01 11:38:25.000000000 -0500
+++ numpy-1.9.2/numpy/core/setup.py     2016-03-28 01:31:12.948885383 -0400
@@ -953,8 +953,8 @@ def configuration(parent_package='',top_
     #blas_info = {}
     def get_dotblas_sources(ext, build_dir):
         if blas_info:
-            if ('NO_ATLAS_INFO', 1) in blas_info.get('define_macros', []):
-                return None # dotblas needs ATLAS, Fortran compiled blas will not be sufficient.
+            #if ('NO_ATLAS_INFO', 1) in blas_info.get('define_macros', []):
+            #    return None # dotblas needs ATLAS, Fortran compiled blas will not be sufficient.
             return ext.depends[:3]
         return None # no extension module will be built

现在,_dotblas.so 已链接到 libblas.so.3,您可以使用 update-alternatives 来测试差异。

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