Arbitrary arbitrage

とっ散らかった頭のお掃除

Ubuntu 16.04 上で numpy の環境構築をする

この記事を読んでわかること

  • ubuntu16.04 上での各種 numpy のインストール方法
  • 各 numpy のインストール方法で、BLAS ライブラリを入れ替える方法
  • BLAS ライブラリのパフォーマンス

概要

Ubuntupython の環境構築( numpy を含め)をする方法は、それはもう数多存在していて、どれを選んだらいいのかいまいちわからない。というわけで、どのやり方が自分にあっているのかを考察するため、主に速度・構築の難易度に関して実験して確認してみた。

ちなみに、当然のことながら python とは python3 のことである。

簡単に概観を整理すると、
まず、python 本体をどうやって導入するのかを決める。選択肢としては以下の通り。

  • apt でインストールする
  • anaconda をインストールする
  • Intel Distribution for Python をインストールする

anaconda1 というのは、データサイエンス向けの python プラットフォームで、科学技術計算のライブラリなどが同梱されており、何がなんだがよくわからない。 ananconda に同梱されている numpy なんかは、MKL (Intel Math Kernel Liblary)2 という計算を高速化するプロプライエタリなライブラリにリンクされているので高速らしい。MKL については後述します。
というわけで、全部入りの anaconda なのですが、全部入りすぎて何がなんだがよくわからない。conda というパッケージマネージャーがついてくるけど、apt と pip ですら辛いのにもう私の手に余る。

Intel Distribution for Python3 というのは、前述の MKL に加えて、 Intel MPI4, Intel TBB5, Intel DAAL6 といったライブラリにリンクされたモジュールがはいっている。DAALなんかは面白そうだけど、いれればとりあえず速くなるタイプのものではないので、必要になったら検討する。

参考

CPUに最適化した計算ライブラリ | Qiita

結局、apt で python と pip をインストールすることにする。そうなると今度は numpy の導入方法が問題になる。釈迦に説法とは思うが、 numpy というのは python において効率的に数値計算を行うためのライブラリであり、特にベクトル・行列の演算を高速化できる。 numpy 内部では、BLAS(Basic Liner Algebra Subprograms) API7 を呼び出すことで、線形代数計算を行なっている。前述の MKL は Intel が提供する BLAS API を実装したライブラリである。

numpy のインストール方法によって、BLAS ライブラリが勝手にはいったり、はいらなかったり、種類を選べたり、選べなかったりする。

MKL にあげられるように、 BLAS の実装は様々提供されているが、一般的なものをあげると

  • reference BLAS8
    • リファレンス実装。単純なfor文で実装されているらしい。
  • OpenBLAS9
    • 後藤和茂によって開発されていた GotoBLAS の後継。オープンソース実装であり、おそらくもっとも有名だろう。
  • ATLAS10
    • オープンソース実装。ビルド時にCPUに合わせて自動的にチューニングを行う。チューニングのための計測に時間がかかる。チューニングをしないなら、あまり使う意味はなさそうなので、今回はパス。
  • MKL
    • Intelによる実装。2015年からコミュニティライセンスが作られ、無償で利用できるようになった。

anaconda を使わない方針なので、 numpy のインストール方法は apt か pip か 自分でビルドするかということになる。それぞれについて、標準でインストールする場合と OpenBLAS にリンクさせる場合、 MKL にリンクさせる場合の手順とパフォーマンスを調べる。

補足

LAPACK(Linear Algebra PACKage) に関して

numpy は BLAS だけでなく LAPACK API ともリンクしている。LAPACK は内部で BLAS を呼び出して線型方程式や固有値問題、特異値問題などを解く。多くの BLAS 実装では LAPACK の実装が同時に提供されているため、本記事では BLASLAPACK を同時に扱うことにする。

環境

環境構築の容易さと実際の運用を考慮して、実験は Docker コンテナ上で行う。環境は以下の通り。

apt (default)

apt で標準の numpy を導入する。

docker コンテナの用意

$ docker run -it --name apt_default ubuntu:16.04 /bin/bash

必要なものをインストールする。

# apt update && \
    apt install -y python3 python3-pip python3-dev vim htop

numpy のインストール

numpy の依存パッケージを見てみる。

# apt depends python3-numpy
python3-numpy
  Depends: python3 (<< 3.6)
  Depends: python3 (>= 3.5~)
  Depends: < python3.5:any>
    python3.5
 |Depends: libblas3
  Depends: < libblas.so.3>
    libatlas3-base
    libblas3
    libopenblas-base
  Depends: libc6 (>= 2.14)
 |Depends: liblapack3
  Depends: < liblapack.so.3>
    libatlas3-base
    liblapack3
    libopenblas-base

libblas3 と liblapack3 に依存していることがわかる。それぞれ、BLAS, LAPACK のリファレンス実装である。

 |Depends: libblas3
  Depends: < libblas.so.3> 

という部分は libblas3 or < libblas.so.3>という関係を意味しており、

  Depends: < libblas.so.3>
    libatlas3-base
    libblas3
    libopenblas-base

つづくこの部分は virtual package11 というものである。 virtual package とは、共通の機能をもったパッケージを仮想的にまとめて扱うためのものであり、今回の場合 libatlas3-base, libblas3, libopenblas-base というパッケージは全て BLAS の機能をもっていて、 /usr/lib/libblas.so.3 にシンボリックリンクをはる。 libatlas3-base と libopenblas-base のどちらもはいっていない状態で python3-numpy をインストールすると libblas3 がインストールされるだろう。

# apt install python3-numpy
# python3 -c "import numpy; print(numpy.version.version)"
1.11.0

検証

BLAS

# python3 -c "import numpy; numpy.show_config()"
atlas_3_10_blas_threads_info:
  NOT AVAILABLE
mkl_info:
  NOT AVAILABLE
lapack_info:
    library_dirs = ['/usr/lib']
    libraries = ['lapack', 'lapack']
    language = f77
atlas_blas_threads_info:
  NOT AVAILABLE
blas_opt_info:
    library_dirs = ['/usr/lib']
    define_macros = [('NO_ATLAS_INFO', 1), ('HAVE_CBLAS', None)]
    libraries = ['blas', 'blas']
    language = c
blas_info:
    library_dirs = ['/usr/lib']
    define_macros = [('HAVE_CBLAS', None)]
    libraries = ['blas', 'blas']
    language = c
openblas_lapack_info:
  NOT AVAILABLE
lapack_opt_info:
    library_dirs = ['/usr/lib']
    define_macros = [('NO_ATLAS_INFO', 1), ('HAVE_CBLAS', None)]
    libraries = ['lapack', 'lapack', 'blas', 'blas']
    language = c
lapack_mkl_info:
  NOT AVAILABLE
atlas_3_10_info:
  NOT AVAILABLE
atlas_blas_info:
  NOT AVAILABLE
atlas_3_10_threads_info:
  NOT AVAILABLE
blas_mkl_info:
  NOT AVAILABLE
atlas_info:
  NOT AVAILABLE
atlas_threads_info:
  NOT AVAILABLE
atlas_3_10_blas_info:
  NOT AVAILABLE
openblas_info:
  NOT AVAILABLE

どうやら、 /usr/lib/ 以下の blaslapack を使っていそう。 /usr/lib/ を見てみると

# ls -l /usr/lib/
...
drwxr-xr-x  2 root root  4096 Jun 11 13:04 lapack
drwxr-xr-x  2 root root  4096 Jun 10 19:56 ldscripts
drwxr-xr-x  2 root root  4096 Jun 11 13:04 libblas
lrwxrwxrwx  1 root root    30 Jun 11 13:04 libblas.so.3 -> /etc/alternatives/libblas.so.3
lrwxrwxrwx  1 root root    32 Jun 11 13:04 liblapack.so.3 -> /etc/alternatives/liblapack.so.3
 ...

libblas.so.3 と liblapack.so.3 が存在して、これらは /etc/alternatives/ からのシンボリックリンクらしい。 /etc/alternateves を見てみると # ls -l /etc/alternatives/lib* lrwxrwxrwx 1 root root 29 Jun 11 13:04 /etc/alternatives/libblas.so.3 -> /usr/lib/libblas/libblas.so.3 lrwxrwxrwx 1 root root 30 Jun 11 13:04 /etc/alternatives/liblapack.so.3 -> /usr/lib/lapack/liblapack.so.3

結局 /usr/lib/libblas/libblas.so.3 と /usr/lib/lapack/liblapack.so.3 からのシンボリックリンクだった。 /etc/alternatives/ とはなんだったのかと思われるかもしれないが、 linux ではupdate-alternativeというシンボリックリンクを管理するコマンドがあって、それを使ってシンボリックリンクをはっているので、こういう構造になっているようだ。

速度

(5000, 5000) の行列同士の積と逆行列を計算させる。本来なら、何度か繰り返して平均値でも取るべきですが、リファレンス BLAS はすこぶる遅いので勘弁して

# python3 -c "import numpy; from time import *; a=numpy.random.rand(5000,5000); t=time(); numpy.dot(a, a.T); print(time()-t)"
78.48567032814026

# python3 -c "import numpy; from time import *; a=numpy.random.rand(5000,5000); t=time(); numpy.linalg.inv(a); print(time()-t)"
92.94670248031616

pip (default)

pip で標準の numpy を導入する。

docker コンテナの用意

$ docker run -it --name pip_default ubuntu:16.04 /bin/bash

必要なものをインストールする。

# apt update && \
    apt install -y python3 python3-pip python3-dev vim htop

numpy のインストール

# python3 -m pip install --upgrade pip
# python3 -m pip install numpy
# python3 -c "import numpy; print(numpy.version.version)"
1.14.4

検証

BLAS

# python3 -c "import numpy; numpy.show_config()"
blas_mkl_info:
  NOT AVAILABLE
openblas_info:
    language = c
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    define_macros = [('HAVE_CBLAS', None)]
lapack_opt_info:
    language = c
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    define_macros = [('HAVE_CBLAS', None)]
blas_opt_info:
    language = c
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    define_macros = [('HAVE_CBLAS', None)]
lapack_mkl_info:
  NOT AVAILABLE
blis_info:
  NOT AVAILABLE
openblas_lapack_info:
    language = c
    libraries = ['openblas', 'openblas']
    library_dirs = ['/usr/local/lib']
    define_macros = [('HAVE_CBLAS', None)]

どうやら、 /usr/local/lib/ 以下の blaslapack を使っていそう。 /usr/local/lib/ を見てみると

# ls -l /usr/local/lib
total 4
drwxr-xr-x 3 root root 4096 Jun 11 14:23 python3.5

python3.5 というディレクトリだけ。もう少し探してみると

# find /usr/local/lib/ -name \*blas\*
/usr/local/lib/python3.5/dist-packages/numpy/.libs/libopenblasp-r0-39a31c03.2.18.so
# find /usr/local/lib/ -name \*lapack\*
/usr/local/lib/python3.5/dist-packages/numpy/linalg/lapack_lite.cpython-35m-x86_64-linux-gnu.so

こいつを使っているっぽい?

速度

(5000, 5000) の行列同士の積と逆行列を計算させる。10回計算して平均値をとる

# python3 -c "import timeit; t = timeit.Timer('numpy.dot(a, a.T)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
1.0404255745001136

# python3 -c "import timeit; t = timeit.Timer('numpy.linalg.inv(a)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
2.788704502300243

build (default)

numpy を特になんの設定もせずに build する。

docker コンテナの用意

$ docker run -it --name build_default ubuntu:16.04 /bin/bash

必要なものをインストールする。

# apt update && \
    apt install -y python3 python3-pip python3-dev vim htop

numpy のインストール

Cython をインストールする。

# python3 -m pip install --upgrade pip
# python3 -m pip install Cython

ソースをダウンロードする。

# apt install -y git
# cd
# git clone --depth=1 -b v1.14.4 https://github.com/numpy/numpy.git
# cd numpy

ビルドしてインストールする。-j 4 はビルド時のジョブ数。 CPU のコア数にしとけばいいはず。

# python3 setup.py build -j 4 install
# cd ..
# python3 -c "import numpy; print(numpy.version.version)"
1.14.4

当然ながら version は1.14.4

検証

BLAS

# python3 -c "import numpy; numpy.show_config()"
blas_src_info:
  NOT AVAILABLE
lapack_mkl_info:
  NOT AVAILABLE
lapack_info:
  NOT AVAILABLE
blas_info:
  NOT AVAILABLE
openblas_clapack_info:
  NOT AVAILABLE
atlas_3_10_threads_info:
  NOT AVAILABLE
atlas_3_10_blas_threads_info:
  NOT AVAILABLE
atlas_3_10_info:
  NOT AVAILABLE
openblas_lapack_info:
  NOT AVAILABLE
atlas_info:
  NOT AVAILABLE
openblas_info:
  NOT AVAILABLE
atlas_threads_info:
  NOT AVAILABLE
blas_mkl_info:
  NOT AVAILABLE
atlas_blas_info:
  NOT AVAILABLE
atlas_3_10_blas_info:
  NOT AVAILABLE
lapack_src_info:
  NOT AVAILABLE
blas_opt_info:
  NOT AVAILABLE
atlas_blas_threads_info:
  NOT AVAILABLE
blis_info:
  NOT AVAILABLE
lapack_opt_info:
  NOT AVAILABLE

全部 NOT AVAILABLE ですね。これどうなるんだろう。

速度

(5000, 5000) の行列同士の積と逆行列を計算させる。本来なら、何度か繰り返して平均値でも取るべきですが、これもすこぶる遅いので勘弁して

# python3 -c "import numpy; from time import *; a=numpy.random.rand(5000,5000); t=time(); numpy.dot(a, a.T); print(time()-t)"
157.6705596446991

# python3 -c "import numpy; from time import *; a=numpy.random.rand(5000,5000); t=time(); numpy.linalg.inv(a); print(time()-t)"
133.88565135002136

意外と遅くないですね。 Cython の力?

apt (openBLAS)

apt で openBLAS にリンクした、 numpy を導入する。

docker コンテナの用意

$ docker run -it --name apt_openblas ubuntu:16.04 /bin/bash

必要なものをインストールする。

# apt update && \
    apt install -y python3 python3-pip python3-dev vim htop

openBLAS のインストール

# apt install -y libopenblas-base libopenblas-dev
...
Setting up libopenblas-base (0.2.18-1ubuntu1) ...
update-alternatives: using /usr/lib/openblas-base/libblas.so.3 to provide /usr/lib/libblas.so.3 (libblas.so.3) in auto mode
update-alternatives: using /usr/lib/openblas-base/liblapack.so.3 to provide /usr/lib/liblapack.so.3 (liblapack.so.3) in auto mode
Setting up libopenblas-dev (0.2.18-1ubuntu1) ...
update-alternatives: using /usr/lib/openblas-base/libblas.so to provide /usr/lib/libblas.so (libblas.so) in auto mode
update-alternatives: using /usr/lib/openblas-base/liblapack.so to provide /usr/lib/liblapack.so (liblapack.so) in auto mode
Processing triggers for libc-bin (2.23-0ubuntu10) ...

流れる出力を見ていると、 update-alternatives によって、 /usr/lib/openblas-base/libblas.so.3 が /usr/lib/libblas.so.3 に関連付けられているのがわかる。 実際に update-alternatives の設定を見てみると

# update-alternatives --config libblas.so.3
There are 2 choices for the alternative libblas.so.3 (providing /usr/lib/libblas.so.3).

  Selection    Path                                 Priority   Status
------------------------------------------------------------
* 0            /usr/lib/openblas-base/libblas.so.3   40        auto mode
  1            /usr/lib/libblas/libblas.so.3         10        manual mode
  2            /usr/lib/openblas-base/libblas.so.3   40        manual mode

Press <enter> to keep the current choice[*], or type selection number: 

現状、 /usr/lib/libblas.so.3 に関連付けられているファイルは /usr/lib/libblas/libblas.so.3 と /usr/lib/openblas-base/libblas.so.3 の2つが存在し、 update-alternatives によって、どちらを使用するかを選べるようになっている。

numpy のインストール

さて、この状態で先ほどと同じように apt を使って numpy をインストールしよう。

# apt install python3-numpy

検証

BLAS

# python3 -c "import numpy; numpy.show_config()"
atlas_blas_info:
  NOT AVAILABLE
atlas_blas_threads_info:
  NOT AVAILABLE
blas_mkl_info:
  NOT AVAILABLE
atlas_3_10_blas_info:
  NOT AVAILABLE
atlas_3_10_threads_info:
  NOT AVAILABLE
mkl_info:
  NOT AVAILABLE
blas_info:
    language = c
    libraries = ['blas', 'blas']
    library_dirs = ['/usr/lib']
    define_macros = [('HAVE_CBLAS', None)]
atlas_info:
  NOT AVAILABLE
atlas_threads_info:
  NOT AVAILABLE
openblas_lapack_info:
  NOT AVAILABLE
lapack_mkl_info:
  NOT AVAILABLE
lapack_opt_info:
    define_macros = [('NO_ATLAS_INFO', 1), ('HAVE_CBLAS', None)]
    libraries = ['lapack', 'lapack', 'blas', 'blas']
    library_dirs = ['/usr/lib']
    language = c
blas_opt_info:
    define_macros = [('NO_ATLAS_INFO', 1), ('HAVE_CBLAS', None)]
    libraries = ['blas', 'blas']
    library_dirs = ['/usr/lib']
    language = c
atlas_3_10_info:
  NOT AVAILABLE
lapack_info:
    language = f77
    libraries = ['lapack', 'lapack']
    library_dirs = ['/usr/lib']
openblas_info:
  NOT AVAILABLE
atlas_3_10_blas_threads_info:
  NOT AVAILABLE

これは、前回と変わっていないようだ。

/usr/lib/ を見てみると

# ls -l /usr/lib/
...
drwxr-xr-x  2 root root     4096 Jun 11 16:42 ldscripts
drwxr-xr-x  2 root root     4096 Jun 11 16:48 libblas
lrwxrwxrwx  1 root root       27 Jun 11 16:48 libblas.a -> /etc/alternatives/libblas.a
lrwxrwxrwx  1 root root       28 Jun 11 16:48 libblas.so -> /etc/alternatives/libblas.so
lrwxrwxrwx  1 root root       30 Jun 11 16:48 libblas.so.3 -> /etc/alternatives/libblas.so.3
lrwxrwxrwx  1 root root       32 Jun 11 16:48 libblas.so.3gf -> /etc/alternatives/libblas.so.3gf
lrwxrwxrwx  1 root root       29 Jun 11 16:48 liblapack.a -> /etc/alternatives/liblapack.a
lrwxrwxrwx  1 root root       30 Jun 11 16:48 liblapack.so -> /etc/alternatives/liblapack.so
lrwxrwxrwx  1 root root       32 Jun 11 16:48 liblapack.so.3 -> /etc/alternatives/liblapack.so.3
lrwxrwxrwx  1 root root       34 Jun 11 16:48 liblapack.so.3gf -> /etc/alternatives/liblapack.so.3gf
lrwxrwxrwx  1 root root       22 Apr 19  2016 libopenblas.a -> libopenblasp-r0.2.18.a
lrwxrwxrwx  1 root root       23 Apr 19  2016 libopenblas.so -> libopenblasp-r0.2.18.so
lrwxrwxrwx  1 root root       23 Apr 19  2016 libopenblas.so.0 -> libopenblasp-r0.2.18.so
-rw-r--r--  1 root root 50859686 Apr 19  2016 libopenblasp-r0.2.18.a
-rw-r--r--  1 root root 31962416 Apr 19  2016 libopenblasp-r0.2.18.so
...
drwxr-xr-x  2 root root     4096 Jun 11 16:48 openblas-base
 ...

やはりlibblas.so.3 と liblapack.so.3 が存在して、これらは /etc/alternatives/ からのシンボリックリンクらしい。 /etc/alternateves を見てみると

 # ls -l /etc/alternatives/lib*
lrwxrwxrwx 1 root root 32 Jun 11 16:48 /etc/alternatives/libblas.a -> /usr/lib/openblas-base/libblas.a
lrwxrwxrwx 1 root root 33 Jun 11 16:48 /etc/alternatives/libblas.so -> /usr/lib/openblas-base/libblas.so
lrwxrwxrwx 1 root root 35 Jun 11 16:48 /etc/alternatives/libblas.so.3 -> /usr/lib/openblas-base/libblas.so.3
lrwxrwxrwx 1 root root 35 Jun 11 16:48 /etc/alternatives/libblas.so.3gf -> /usr/lib/openblas-base/libblas.so.3
lrwxrwxrwx 1 root root 34 Jun 11 16:48 /etc/alternatives/liblapack.a -> /usr/lib/openblas-base/liblapack.a
lrwxrwxrwx 1 root root 35 Jun 11 16:48 /etc/alternatives/liblapack.so -> /usr/lib/openblas-base/liblapack.so
lrwxrwxrwx 1 root root 37 Jun 11 16:48 /etc/alternatives/liblapack.so.3 -> /usr/lib/openblas-base/liblapack.so.3
lrwxrwxrwx 1 root root 37 Jun 11 16:48 /etc/alternatives/liblapack.so.3gf -> /usr/lib/openblas-base/liblapack.so.3

ちゃんと /usr/lib/openblas-base/libblas.so.3 からのシンボリックリンクになっている。

速度

(5000, 5000) の行列同士の積と逆行列を計算させる。10回計算して平均値をとる

# python3 -c "import timeit; t = timeit.Timer('numpy.dot(a, a.T)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
1.0449801932001719

# python3 -c "import timeit; t = timeit.Timer('numpy.linalg.inv(a)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
2.7496115829999326

pip (openBLAS)

pip で 自前の opneBLAS にリンクした numpy を導入する。これやる意味あるか?

docker コンテナの用意

$ docker run -it --name pip_openblas ubuntu:16.04 /bin/bash

必要なものをインストールする。

# apt update && \
    apt install -y python3 python3-pip python3-dev vim htop

openBLAS のインストール

# apt install -y libopenblas-base libopenblas-dev

numpy のインストール

numpy はビルド時に~/.numpy-site.cfgを見にいくらしい。 このへんを参考にしながら、以下のように記述する。

[openblas]
libraries = openblas
library_dirs = /usr/lib
include_dirs = /usr/include/openblas
runtime_library_dirs = /usr/lib

pip で numpy を導入するときには、標準では自動的にバイナリパッケージをおとしてくるので、これを無効化する。インストール時に--no-binaryオプションを指定してもいい12が、~/.config/pip/pip.confに事前に記述することもできる。

[install]
no-binary = numpy,scipy

インストールする

# python3 -m pip install --upgrade pip
# python3 -m pip install numpy

検証

BLAS

# python3 -c "import numpy; numpy.show_config()"
lapack_mkl_info:
  NOT AVAILABLE
openblas_lapack_info:
    define_macros = [('HAVE_CBLAS', None)]
    library_dirs = ['/usr/lib']
    language = c
    libraries = ['openblas', 'openblas']
    runtime_library_dirs = ['/usr/lib']
openblas_info:
    define_macros = [('HAVE_CBLAS', None)]
    library_dirs = ['/usr/lib']
    language = c
    libraries = ['openblas', 'openblas']
    runtime_library_dirs = ['/usr/lib']
blas_mkl_info:
  NOT AVAILABLE
blis_info:
  NOT AVAILABLE
blas_opt_info:
    define_macros = [('HAVE_CBLAS', None)]
    library_dirs = ['/usr/lib']
    language = c
    libraries = ['openblas', 'openblas']
    runtime_library_dirs = ['/usr/lib']
lapack_opt_info:
    define_macros = [('HAVE_CBLAS', None)]
    library_dirs = ['/usr/lib']
    language = c
    libraries = ['openblas', 'openblas']
    runtime_library_dirs = ['/usr/lib']

ちゃんと設定できていそう。

速度

(5000, 5000) の行列同士の積と逆行列を計算させる。10回計算して平均値をとる

# python3 -c "import timeit; t = timeit.Timer('numpy.dot(a, a.T)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
1.044793247798225

# python3 -c "import timeit; t = timeit.Timer('numpy.linalg.inv(a)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
2.7951152697001818

build (openBLAS)

numpy を openBLAS にリンクさせて build する。

docker コンテナの用意

$ docker run -it --name build_openblas ubuntu:16.04 /bin/bash

必要なものをインストールする。

# apt update && \
    apt install -y python3 python3-pip python3-dev vim htop

openBLAS のインストール

# apt install -y libopenblas-base libopenblas-dev

numpy のインストール

Cython をインストールする。

# python3 -m pip install --upgrade pip
# python3 -m pip install Cython

ソースをダウンロードする。

# apt install -y git
# cd
# git clone --depth=1 -b v1.14.4 https://github.com/numpy/numpy.git
# cd numpy

ビルドのための設定ファイル (site.cfg) を作成する。 pip のときと同じ。

[openblas]
libraries = openblas
library_dirs = /usr/lib
include_dirs = /usr/include/openblas
runtime_library_dirs = /usr/lib

ビルドしてインストールする。-j 4 はビルド時のジョブ数。 CPU のコア数にしとけばいいはず。

# python3 setup.py build -j 4 install
# cd ..

検証

BLAS

# python3 -c "import numpy; numpy.show_config()"
blas_mkl_info:
  NOT AVAILABLE
blis_info:
  NOT AVAILABLE
lapack_mkl_info:
  NOT AVAILABLE
openblas_lapack_info:
    runtime_library_dirs = ['/usr/lib']
    language = c
    library_dirs = ['/usr/lib']
    define_macros = [('HAVE_CBLAS', None)]
    libraries = ['openblas', 'openblas']
blas_opt_info:
    runtime_library_dirs = ['/usr/lib']
    language = c
    library_dirs = ['/usr/lib']
    define_macros = [('HAVE_CBLAS', None)]
    libraries = ['openblas', 'openblas']
lapack_opt_info:
    runtime_library_dirs = ['/usr/lib']
    language = c
    library_dirs = ['/usr/lib']
    define_macros = [('HAVE_CBLAS', None)]
    libraries = ['openblas', 'openblas']
openblas_info:
    runtime_library_dirs = ['/usr/lib']
    language = c
    library_dirs = ['/usr/lib']
    define_macros = [('HAVE_CBLAS', None)]
    libraries = ['openblas', 'openblas']

速度

(5000, 5000) の行列同士の積と逆行列を計算させる。10回計算して平均値をとる

# python3 -c "import timeit; t = timeit.Timer('numpy.dot(a, a.T)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
1.0436332723998931

# python3 -c "import timeit; t = timeit.Timer('numpy.linalg.inv(a)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
2.759005813498516

apt (MKL)

apt で MKL にリンクした、 numpy を導入する。

docker コンテナの用意

$ docker run -it --name apt_mkl ubuntu:16.04 /bin/bash

必要なものをインストールする。

# apt update && \
    apt install -y python3 python3-pip python3-dev vim htop

MKL のインストール

https://software.intel.com/en-us/articles/installing-intel-free-libs-and-python-apt-repo

ここを参考にしながら進める。

MKL を使用する前に EULA(End User License Agreements)13 に目を通しておきます。

GPG key を追加する。

# cd
# apt install -y wget apt-transport-https
# wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB
# apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB

リポジトリを追加する。

# sh -c 'echo deb https://apt.repos.intel.com/mkl all main > /etc/apt/sources.list.d/intel-mkl.list'

インストールする。

# apt update && \
    apt install -y intel-mkl-64bit-2018.3-051

/opt/intel/ 以下にインストールされる。

update-alternatives の設定をする。 priority を50に設定しておくことで、 openBLAS などよりも優先されるはず。

# update-alternatives --install /usr/lib/libblas.so libblas.so  /opt/intel/mkl/lib/intel64/libmkl_rt.so 50
# update-alternatives --install /usr/lib/libblas.so.3 libblas.so.3 /opt/intel/mkl/lib/intel64/libmkl_rt.so 50
# update-alternatives --install /usr/lib/liblapack.so  liblapack.so  /opt/intel/mkl/lib/intel64/libmkl_rt.so 50
# update-alternatives --install /usr/lib/liblapack.so.3 liblapack.so.3 /opt/intel/mkl/lib/intel64/libmkl_rt.so 50

ldconfig の設定をする。MKL は libmkl_rt.so 以外にも多くの共有ライブラリファイルを /opt/intel/mkl/lib/intel64/ 以下に持っていて、それらにたいしてパスを通してやる必要がある。 /etc/ld.so.conf.d/ 以下に適当なファイルをつくって記述する。

/opt/intel/lib/intel64
/opt/intel/mkl/lib/intel64
# ldconfig

これは、以下のコマンドと同じようなことになるはず。

# export LD_LIBRARY_PATH="/opt/intel/mkl/lib/intel64:/opt/intel/lib/intel64:$LD_LIBRARY_PATH"

numpy のインストール

さて、この状態で apt を使って numpy をインストールしよう。

# apt install -y python3-numpy

openBLAS のときとちがって、今度は libblas3 もインストールされる。 update-alternatives の設定を確認してみると

# update-alternatives --config libblas.so.3
There are 2 choices for the alternative libblas.so.3 (providing /usr/lib/libblas.so.3).

  Selection    Path                                     Priority   Status
------------------------------------------------------------
* 0            /opt/intel/mkl/lib/intel64/libmkl_rt.so   50        auto mode
  1            /opt/intel/mkl/lib/intel64/libmkl_rt.so   50        manual mode
  2            /usr/lib/libblas/libblas.so.3             10        manual mode

Press <enter> to keep the current choice[*], or type selection number: 

# update-alternatives --config liblapack.so.3
There are 2 choices for the alternative liblapack.so.3 (providing /usr/lib/liblapack.so.3).

  Selection    Path                                     Priority   Status
------------------------------------------------------------
* 0            /opt/intel/mkl/lib/intel64/libmkl_rt.so   50        auto mode
  1            /opt/intel/mkl/lib/intel64/libmkl_rt.so   50        manual mode
  2            /usr/lib/lapack/liblapack.so.3            10        manual mode

Press <enter> to keep the current choice[*], or type selection number: 

大丈夫そう。

検証

BLAS

# python3 -c "import numpy; numpy.show_config()"
atlas_blas_info:
  NOT AVAILABLE
atlas_blas_threads_info:
  NOT AVAILABLE
blas_mkl_info:
  NOT AVAILABLE
atlas_3_10_blas_info:
  NOT AVAILABLE
atlas_3_10_threads_info:
  NOT AVAILABLE
mkl_info:
  NOT AVAILABLE
blas_info:
    language = c
    libraries = ['blas', 'blas']
    library_dirs = ['/usr/lib']
    define_macros = [('HAVE_CBLAS', None)]
atlas_info:
  NOT AVAILABLE
atlas_threads_info:
  NOT AVAILABLE
openblas_lapack_info:
  NOT AVAILABLE
lapack_mkl_info:
  NOT AVAILABLE
lapack_opt_info:
    define_macros = [('NO_ATLAS_INFO', 1), ('HAVE_CBLAS', None)]
    libraries = ['lapack', 'lapack', 'blas', 'blas']
    library_dirs = ['/usr/lib']
    language = c
blas_opt_info:
    define_macros = [('NO_ATLAS_INFO', 1), ('HAVE_CBLAS', None)]
    libraries = ['blas', 'blas']
    library_dirs = ['/usr/lib']
    language = c
atlas_3_10_info:
  NOT AVAILABLE
lapack_info:
    language = f77
    libraries = ['lapack', 'lapack']
    library_dirs = ['/usr/lib']
openblas_info:
  NOT AVAILABLE
atlas_3_10_blas_threads_info:
  NOT AVAILABLE

速度

(5000, 5000) の行列同士の積と逆行列を計算させる。10回計算して平均値をとる

# python3 -c "import timeit; t = timeit.Timer('numpy.dot(a, a.T)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
0.8721326167986263

# python3 -c "import timeit; t = timeit.Timer('numpy.linalg.inv(a)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
2.221680459997151

pip (MKL)

pip で MKL にリンクした numpy を導入する。

docker コンテナの用意

$ docker run -it --name pip_mkl ubuntu:16.04 /bin/bash

必要なものをインストールする。

# apt update && \
    apt install -y python3 python3-pip python3-dev vim htop

MKL のインストール

https://software.intel.com/en-us/articles/end-user-license-agreement

MKL を使用する前に EULA(End User License Agreements)14 に目を通しておきます。

GPG key を追加する。

# cd
# apt install -y wget apt-transport-https
# wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB
# apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB

リポジトリを追加する。

# sh -c 'echo deb https://apt.repos.intel.com/mkl all main > /etc/apt/sources.list.d/intel-mkl.list'

インストールする。

# apt update && \
    apt install -y intel-mkl-64bit-2018.3-051

update-alternatives の設定をする。

# update-alternatives --install /usr/lib/libblas.so libblas.so  /opt/intel/mkl/lib/intel64/libmkl_rt.so 50
# update-alternatives --install /usr/lib/libblas.so.3 libblas.so.3 /opt/intel/mkl/lib/intel64/libmkl_rt.so 50
# update-alternatives --install /usr/lib/liblapack.so  liblapack.so  /opt/intel/mkl/lib/intel64/libmkl_rt.so 50
# update-alternatives --install /usr/lib/liblapack.so.3 liblapack.so.3 /opt/intel/mkl/lib/intel64/libmkl_rt.so 50

ldconfig の設定をする。 /etc/ld.so.conf.d/ 以下に適当なファイルをつくって記述する。

/opt/intel/lib/intel64
/opt/intel/mkl/lib/intel64
# ldconfig

numpy のインストール

numpy はビルド時に~/.numpy-site.cfgを見にいく。 このへんを参考にしながら、以下のように記述する。

[mkl]
library_dirs = /opt/intel/mkl/lib/intel64
include_dirs = /opt/intel/mkl/include
mkl_libs = mkl_rt
lapack_libs =

バイナリパッケージを無効化する。インストール時に--no-binaryオプションを指定してもいい15が、~/.config/pip/pip.confに事前に記述する。

[install]
no-binary = numpy,scipy

インストールする

# python3 -m pip install --upgrade pip
# python3 -m pip install numpy

検証

BLAS

# python3 -c "import numpy; numpy.show_config()"
blas_opt_info:
    libraries = ['mkl_rt', 'pthread']
    include_dirs = ['/opt/intel/mkl/include']
    library_dirs = ['/opt/intel/mkl/lib/intel64']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
lapack_opt_info:
    libraries = ['mkl_rt', 'pthread']
    include_dirs = ['/opt/intel/mkl/include']
    library_dirs = ['/opt/intel/mkl/lib/intel64']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
blas_mkl_info:
    libraries = ['mkl_rt', 'pthread']
    include_dirs = ['/opt/intel/mkl/include']
    library_dirs = ['/opt/intel/mkl/lib/intel64']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
lapack_mkl_info:
    libraries = ['mkl_rt', 'pthread']
    include_dirs = ['/opt/intel/mkl/include']
    library_dirs = ['/opt/intel/mkl/lib/intel64']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]

ちゃんと設定できていそう。

速度

(5000, 5000) の行列同士の積と逆行列を計算させる。10回計算して平均値をとる

# python3 -c "import timeit; t = timeit.Timer('numpy.dot(a, a.T)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
0.8707317243970465

# python3 -c "import timeit; t = timeit.Timer('numpy.linalg.inv(a)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
2.2194733479002027

build (MKL)

numpy を MKL にリンクさせて build する。

docker コンテナの用意

$ docker run -it --name build_mkl ubuntu:16.04 /bin/bash

必要なものをインストールする。

# apt update && \
    apt install -y python3 python3-pip python3-dev vim htop

MKL のインストール

https://software.intel.com/en-us/articles/end-user-license-agreement

MKL を使用する前に EULA(End User License Agreements)16 に目を通しておきます。

GPG key を追加する。

# cd
# apt install -y wget apt-transport-https
# wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB
# apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB

リポジトリを追加する。

# sh -c 'echo deb https://apt.repos.intel.com/mkl all main > /etc/apt/sources.list.d/intel-mkl.list'

インストールする。

# apt update && \
    apt install -y intel-mkl-64bit-2018.3-051

update-alternatives の設定をする。

# update-alternatives --install /usr/lib/libblas.so libblas.so  /opt/intel/mkl/lib/intel64/libmkl_rt.so 50
# update-alternatives --install /usr/lib/libblas.so.3 libblas.so.3 /opt/intel/mkl/lib/intel64/libmkl_rt.so 50
# update-alternatives --install /usr/lib/liblapack.so  liblapack.so  /opt/intel/mkl/lib/intel64/libmkl_rt.so 50
# update-alternatives --install /usr/lib/liblapack.so.3 liblapack.so.3 /opt/intel/mkl/lib/intel64/libmkl_rt.so 50

ldconfig の設定をする。 /etc/ld.so.conf.d/ 以下に適当なファイルをつくって記述する。

/opt/intel/lib/intel64
/opt/intel/mkl/lib/intel64
# ldconfig

numpy のインストール

Cython をインストールする。

# python3 -m pip install --upgrade pip
# python3 -m pip install Cython

ソースをダウンロードする。

# apt install -y git
# cd
# git clone --depth=1 -b v1.14.4 https://github.com/numpy/numpy.git
# cd numpy

ビルドのための設定ファイル (site.cfg) を作成する。 pip のときと同じ。

[mkl]
library_dirs = /opt/intel/mkl/lib/intel64
include_dirs = /opt/intel/mkl/include
mkl_libs = mkl_rt
lapack_libs =

ビルドしてインストールする。-j 4 はビルド時のジョブ数。 CPU のコア数にしとけばいいはず。

# python3 setup.py build -j 4 install
# cd ..

検証

BLAS

# python3 -c "import numpy; numpy.show_config()"
lapack_opt_info:
    library_dirs = ['/opt/intel/mkl/lib/intel64']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    libraries = ['mkl_rt', 'pthread']
    include_dirs = ['/opt/intel/mkl/include']
lapack_mkl_info:
    library_dirs = ['/opt/intel/mkl/lib/intel64']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    libraries = ['mkl_rt', 'pthread']
    include_dirs = ['/opt/intel/mkl/include']
blas_opt_info:
    library_dirs = ['/opt/intel/mkl/lib/intel64']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    libraries = ['mkl_rt', 'pthread']
    include_dirs = ['/opt/intel/mkl/include']
blas_mkl_info:
    library_dirs = ['/opt/intel/mkl/lib/intel64']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    libraries = ['mkl_rt', 'pthread']
    include_dirs = ['/opt/intel/mkl/include']

速度

(5000, 5000) の行列同士の積と逆行列を計算させる。10回計算して平均値をとる

# python3 -c "import timeit; t = timeit.Timer('numpy.dot(a, a.T)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
0.8726400416984689

# python3 -c "import timeit; t = timeit.Timer('numpy.linalg.inv(a)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
2.2215519364981446

おまけ

openBLAS をソースからビルドする

いろいろ弄りたい人向け

準備

$ docker run -it --name openblas_from_sorce ubuntu:16.04 /bin/bash
apt update&& \
    apt install -y python3 python3-pip python3-dev htop vim

openBLAS をインストールする

dpkg-dev が必要になるのでインストールする。
openBLAS のソースを apt のリポジトリからダウンロードする。
依存ライブラリをインストールする。

# cd
# apt install -y dpkg-dev 
# apt source openblas
# apt build-dep openblas
# apt install -y libblas-dev

ビルドすると、2つの .deb ファイルができる。

# cd openblas-0.2.18
# dpkg-buildpackage -b -uc
# cd ..
# ls -l
...
-rw-r--r--   1 root root 3531174 Jun 12 00:11 libopenblas-base_0.2.18-1ubuntu1_amd64.deb
-rw-r--r--   1 root root 3306144 Jun 12 00:12 libopenblas-dev_0.2.18-1ubuntu1_amd64.deb
...

インストールする。

# dpkg -i *.deb

以下のように、 blaslapack が入っている。

# update-alternatives --config libblas.so.3
There are 2 choices for the alternative libblas.so.3 (providing /usr/lib/libblas.so.3).

  Selection    Path                                 Priority   Status
------------------------------------------------------------
* 0            /usr/lib/openblas-base/libblas.so.3   40        auto mode
  1            /usr/lib/libblas/libblas.so.3         10        manual mode
  2            /usr/lib/openblas-base/libblas.so.3   40        manual mode

Press <enter> to keep the current choice[*], or type selection number: 

# update-alternatives --config liblapack.so.3
There are 2 choices for the alternative liblapack.so.3 (providing /usr/lib/liblapack.so.3).

  Selection    Path                                   Priority   Status
------------------------------------------------------------
* 0            /usr/lib/openblas-base/liblapack.so.3   40        auto mode
  1            /usr/lib/lapack/liblapack.so.3          10        manual mode
  2            /usr/lib/openblas-base/liblapack.so.3   40        manual mode

Press <enter> to keep the current choice[*], or type selection number: 

速度

(5000, 5000) の行列同士の積と逆行列を計算させる。10回計算して平均値をとる

# python3 -c "import timeit; t = timeit.Timer('numpy.dot(a, a.T)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
1.0459788094041869

# python3 -c "import timeit; t = timeit.Timer('numpy.linalg.inv(a)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
2.764898907497991

CPU のアーキテクチャを検出してビルドするので、最適化されることを期待したが、 Skylake 以降は、 Haswell と同じらしい?単に apt でインストールするのと同様のパフォーマンスだろう。

MKL をカスタムインストールする

色々設定したい人向け?

MKL をダウンロードする

ここから https://software.intel.com/en-us/mkl

コンテナ作成

$ docker run -it --name mkl_custom ubuntu:16.04 /bin/bash
$ docker cp /usr/local/data/mkl/l_mkl_2018.3.222.tgz mkl_custom:/root/
$ docker attach mkl_custom
# apt update&& \
    apt install -y python3 python3-pip python3-dev htop vim

MKL をインストールする

依存パッケージのインストール。

# apt install cpio

解凍して、インストールスクリプトを実行する。

# cd /root
# tar -xzvf l_mkl_2018.3.222.tgz
# cd l_mkl_2018.3.222
# ./install.sh

/opt/intel以下に MKL がインストールされる。

いろいろ設定できるみたい。

# ./install.sh -h
This program installs Intel(R) Software Development Products.

Usage: install.sh [options]

    -h, --help                      print this message
    -v, --version                   print version information
    -s, --silent [FILE]             run setup silently, with settings in the configuration file
    -d, --duplicate [FILE]          run setup interactively, record the user input into the 
                                    configuration file
    -l, --lang                      set user interface language
    -t, --tmp-dir [DIRECTORY]       set custom temporary folder
    -D, --download-dir [DIRECTORY]  set custom download folder
    --download_url [URL]            set custom download URL
    --user-mode                     run setup with current user privileges
    --ignore-signature              skip signature validation
    --ignore-cpu                    skip CPU model check
    --nonrpm-db-dir [DIRECTORY]     set directory to store product installation database
    --SHARED_INSTALL                install to a network-mounted drive or shared file system
                                    for multiple users

All provided paths must be absolute.

Copyright (C) 2006-2018 Intel Corporation. All rights reserved.

miniconda の場合

numpy だけ試せれば良いので、miniconda をインストールする。miniconda は python本体 と conda だけを含む最小構成のディストリビューション

$ docker run -it --name miniconda ubuntu:16.04 /bin/bash
# apt update&& \
    apt install -y wget bzip2

miniconda をインストールする

インストールスクリプトは -b オプションでインタラクティブを省略できるが、EULA17に同意の上でどうぞ

# cd
# wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh
# chmod 744 miniconda.sh
# ./miniconda.sh
# source ~/.bashrc
# python3 -V
Python 3.6.5 :: Anaconda, Inc.

anaconda では python3.6 になる。

numpy をインストールする

# conda update conda
# conda install numpy
# python3 -c "import numpy; print(numpy.version.version)"
1.14.3

BLAS

# python3 -c "import numpy; numpy.show_config()"
blas_mkl_info:
  NOT AVAILABLE
blis_info:
  NOT AVAILABLE
openblas_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/root/miniconda3/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
blas_opt_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/root/miniconda3/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
lapack_mkl_info:
  NOT AVAILABLE
openblas_lapack_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/root/miniconda3/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]
lapack_opt_info:
    libraries = ['openblas', 'openblas']
    library_dirs = ['/root/miniconda3/lib']
    language = c
    define_macros = [('HAVE_CBLAS', None)]

速度

# python3 -c "import timeit; t = timeit.Timer('numpy.dot(a, a.T)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
1.0443371900997591

# python3 -c "import timeit; t = timeit.Timer('numpy.linalg.inv(a)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
2.7718222966999746

miniconda に conda でいれる numpy は openBLAS 版っぽいですね。

anaconda の場合

miniconda では openBLAS 版の numpy がはいるようなので、改めてanaconda の場合

$ docker run -it --name anaconda ubuntu:16.04 /bin/bash
# apt update&& \
    apt install -y wget bzip2

anaconda をインストールする

やはりインストールスクリプトは -b オプションでインタラクティブを省略できるが、EULA18に同意の上でどうぞ

# cd
# wget https://repo.anaconda.com/archive/Anaconda3-5.2.0-Linux-x86_64.sh -O ~/anaconda.sh
# chmod 744 anaconda.sh
# ./anaconda.sh
# source ~/.bashrc
# python3 -V
Python 3.6.5 :: Anaconda, Inc.
# python3 -c "import numpy; print(numpy.version.version)"
1.14.3

BLAS

# python3 -c "import numpy; numpy.show_config()"
mkl_info:
    libraries = ['mkl_rt', 'pthread']
    library_dirs = ['/root/anaconda3/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/root/anaconda3/include']
blas_mkl_info:
    libraries = ['mkl_rt', 'pthread']
    library_dirs = ['/root/anaconda3/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/root/anaconda3/include']
blas_opt_info:
    libraries = ['mkl_rt', 'pthread']
    library_dirs = ['/root/anaconda3/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/root/anaconda3/include']
lapack_mkl_info:
    libraries = ['mkl_rt', 'pthread']
    library_dirs = ['/root/anaconda3/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/root/anaconda3/include']
lapack_opt_info:
    libraries = ['mkl_rt', 'pthread']
    library_dirs = ['/root/anaconda3/lib']
    define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
    include_dirs = ['/root/anaconda3/include']

ちゃんと MKL がはいっているようだ。

速度

# python3 -c "import timeit; t = timeit.Timer('numpy.dot(a, a.T)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
0.8611712920013815

# python3 -c "import timeit; t = timeit.Timer('numpy.linalg.inv(a)', setup='import numpy; a = numpy.random.rand(5000, 5000)'); print(t.timeit(10) / 10)"
2.2252039810991846

python 3.6 にしたい

J Fernyhough という方の PPA を使うのがいいっぽい。

$ docker run -it --name python36 ubuntu:16.04 /bin/bash

リポジトリを追加する。

# apt update && \
    apt install -y software-properties-common wget
# add-apt-repository ppa:jonathonf/python-3.6
# apt update

インストールする。

# apt install  python3.6 python3.6-dev
# python3.6 -V
Python 3.6.5

pip をインストールする。

# cd
# wget https://bootstrap.pypa.io/get-pip.py -O ~/get-pip.py
# python3.6 get-pip.py 

まとめ

apt_default pip_default build_default apt_openBLAS pip_openBLAS build_openBLAS apt_MKL pip_MKL build_MKL miniconda anaconda
BLAS referenceBLAS openBLAS なし(Cython??) openBLAS openBLAS openBLAS MKL MKL MKL openBLAS MKL
行列積(5000, 5000) 78.4857 1.0404 157.6706 1.0450 1.0448 1.0436 0.8721 0.8707 0.8726 1.0443 0.8612
逆行列(5000, 5000) 92.9467 2.7887 133.8857 2.7496 2.7951 2.7590 2.2216 2.2194 2.2216 2.7718 2.2252

当然ながら、同じ BLAS 実装だと、同じパフォーマンスになる。行列積と逆行列の結果だけをみて結論を出すのが妥当かはわからないが、 openBLAS よりも MKL の方が1.1 ~ 1.2倍程度高速らしい。もっと、データ分析や機械学習の現場で使いうるようなベンチマークがあれば教えてください。

BLAS 実装が同じであれば同じ性能なので、 BLAS 実装と numpy のインストール方法は独立に選んでいいですね。オープンソースがいいなら openBLAS を少しでも高速なのがいいなら MKL を選んだらいいと思います。

numpy のインストール方法ですが、まあ pip でいれるのが楽だと思いました。というか管理も考えると、それ以外の選択肢はちょっと厳しい。

あとは、 anaconda も便利ですね。miniconda にすると MKL がはいらないという罠がありますが、何も考えずに MKL がはいるのはらくちん。 tensorflow をいれると Cudnn までついてくるという話19もあって、至れり尽くせり。

参考