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



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中。那么修改它能解决我的问题吗?如果是,你能告诉我怎么做吗

假设您运行的是某种风格的linux,以下是一种方法:

  1. 使用ldd查找当前链接的BLAS库numpy。

    • 对于v1.10以上的numpy版本:

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

      例如,如果我通过apt-get安装numpy,它将链接到

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

      如果_dotblas.so不存在,这可能意味着numpy在最初安装时未能检测到任何BLAS库,在这种情况下,它根本不会构建任何依赖于BLAS的组件。如果使用pip安装numpy而不手动指定BLAS库,则经常会发生这种情况(请参见下文)。如果你想链接到外部BLAS库,恐怕你别无选择,只能重建numpy。


    • 对于numpy v1.10及更新版本:

      _dotblas.so已从最近版本的numpy中删除,但您应该能够检查multiarray.so的依赖关系:

      $ ldd /<path_to_site-packages>/numpy/core/multiarray.so
      
  2. 如果你还没有安装ATLAS/MKL/OpenBLAS。顺便说一句,我肯定会推荐OpenBLAS而不是ATLAS——看看这个答案(尽管基准数据现在可能有点过时)。

  3. 使用update-alternatives创建一个指向您选择的新BLAS库的符号链接。例如,如果您将libopenblas.so安装到/opt/OpenBLAS/lib中,您将执行以下操作:

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

    您可以为单个目标库配置多个符号链接,从而可以在多个已安装的BLAS库之间手动切换。

    例如,当我调用$ sudo update-alternatives --config libblas.so.3时,我可以在以下三个库中进行选择:

    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的配置。

答案取决于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。也就是说,如果您针对netlib BLAS/LAPACK/CBAS(作为官方包)构建NumPy,则_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/MHL/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来测试差异。

相关内容

  • 没有找到相关文章

最新更新