NumPy/SciPy で Intel MKL を利用する (2019年11月版)

Intel MKL は Intel 社が開発した, Intel 製 CPU でのみ動作する高速な数値処理ライブラリです. 線型代数演算や FFT などが含まれます. Numpy/SciPy は標準で線型代数演算に openblas を利用しますが, Intel MKL を使用すると処理が高速になります.

本記事の内容は Debian 10 (native/WSL) で Python 3.8.0 を用いて検証しました. ※公式には Debian は 8 または 9 のみサポートされていて Debian 10 はサポート外です. [CentOS 7.7 での結果を追記しました. 2019-11-13]

__2021-04-07 追記__ 本記事の内容は古くなっています. 最新の情報は [WSL2でPython環境構築 (2021年3月版)](https://osanshouo.github.io/blog/2021/03/20-python-build/) をご覧ください.

# Intel MKL のインストール

## ダウンロード

[Intel MKL](https://software.intel.com/en-us/mkl) から 「Choose and Download」, 「Linux*」, 「Register & Download」とリンクを辿り, フォームから氏名とメールアドレスなど必要事項を記入して提出. するとすぐにメールでダウンロードリンクが送られてくる (添付ファイルにキーが入っているが使わなかった). リンクを開いて環境にあったものを選びダウンロード.

なお apt または yum を用いてインストールするオプションもある. が個人的にはスタンドアローン版で良いと思う.

## インストール

tgz ファイルがダウンロードされるので, 解凍してその中に移動する. するとその中に `./install.sh` と `./silent.cfg` というふたつのファイルが見つかる. 単に `sudo ./install.sh` を実行すると対話式のインストールが始まる. それでもよいが `./silent.cfg` を適宜書き換えて `sudo ./install.sh -s ./silent.cfg` を実行すると, 自動的にインストールを行ってくれる.

[mkl numpyのインストール方法](https://qiita.com/unnonouno/items/8ab453a1868d77a93679) という記事によるとレジストレーションキーを要求されることになっているが, 私が実行したところ要求されなかった. なので `./silent.cfg` を編集するのも `ACCEPT_EULA=accept` とのみ書き換えればよく, アクティベーションキーに関するフィールドをつくってはならない.

## 環境変数の設定

`~/.profile` あるいは `~/.bashrc` あたりで必要な環境変数を設定しておく.

```shell
export MKL_ROOT_DIR=/opt/intel/mkl
export LD_LIBRARY_PATH=$MKL_ROOT_DIR/lib/intel64:/opt/intel/lib/intel64_lin:$LD_LIBRARY_PATH
export LIBRARY_PATH=$MKL_ROOT_DIR/lib/intel64:$LIBRARY_PATH
export PKG_CONFIG_PATH=$MKL_ROOT_DIR/bin/pkgconfig:$PKG_CONFIG_PATH
```

`PKG_CONFIG_PATH` はいまの目的では必要ないが, Python 以外でも Intel MKL を利用したいと思った場合に有用なので, 同時に設定しておく.


# NumPy と SciPy のインストール

## ビルド

まず `~/.numpy-site.cfg` というファイルを作成し, 以下の内容を書き込む.

```:.numpy-site.cfg
[mkl]
library_dirs = /opt/intel/mkl/lib/intel64/
include_dirs = /opt/intel/mkl/include
mkl_libs = mkl_rt
lapack_libs =
```

そうしたら pip でインストールする. バイナリパッケージをダウンロードするのではなくコンパイルを強制するために

```shell_session
$ pip install --no-binary :all: numpy
$ pip install --no-binary :all: scipy
```

とする. ビルドに時間がかかる (特に SciPy, デスクトップで12分程度) ので気長に待つ必要がある.

__[追記 2019-11-13]__ CentOS 7.7 で実行したところ gcc 4.8 と古く, C99 モードを有効化する必要があった. 次のようにフラグを立てればよい.

```shell_session
$ CFLAGS="-std=c99" pip3 install --no-binary :all: numpy
$ CFLAGS="-std=c99" pip3 install --no-binary :all: scipy
```


## 動作確認

```shell_session
$ python3.8
iPython 3.8.0 (default, Oct 15 2019, 23:02:58)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> import numpy as np
>>> np.show_config()
blas_mkl_info:
libraries = ['mkl_rt', 'pthread']
library_dirs = ['/opt/intel/mkl/lib/intel64']
define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
include_dirs = ['/opt/intel/mkl/include']
blas_opt_info:
libraries = ['mkl_rt', 'pthread']
library_dirs = ['/opt/intel/mkl/lib/intel64']
define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
include_dirs = ['/opt/intel/mkl/include']
lapack_mkl_info:
libraries = ['mkl_rt', 'pthread']
library_dirs = ['/opt/intel/mkl/lib/intel64']
define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
include_dirs = ['/opt/intel/mkl/include']
lapack_opt_info:
libraries = ['mkl_rt', 'pthread']
library_dirs = ['/opt/intel/mkl/lib/intel64']
define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
include_dirs = ['/opt/intel/mkl/include']
>>> 
>>> from scipy import show_config
>>> show_config()
lapack_mkl_info:
libraries = ['mkl_rt', 'pthread']
library_dirs = ['/opt/intel/mkl/lib/intel64']
define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
include_dirs = ['/opt/intel/mkl/include']
lapack_opt_info:
libraries = ['mkl_rt', 'pthread']
library_dirs = ['/opt/intel/mkl/lib/intel64']
define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
include_dirs = ['/opt/intel/mkl/include']
blas_mkl_info:
libraries = ['mkl_rt', 'pthread']
library_dirs = ['/opt/intel/mkl/lib/intel64']
define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
include_dirs = ['/opt/intel/mkl/include']
blas_opt_info:
libraries = ['mkl_rt', 'pthread']
library_dirs = ['/opt/intel/mkl/lib/intel64']
define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
include_dirs = ['/opt/intel/mkl/include']
>>> 
```

# 参考文献

- [mkl numpyのインストール方法](https://qiita.com/unnonouno/items/8ab453a1868d77a93679) 2016年5月
- [Intel MKL を apt からインストールする](https://qiita.com/f0o0o/items/d79971215fd37c3a5d36) 2018年10月
- [numpy で MKL を使う](https://qiita.com/f0o0o/items/69d9b766008091a6e698) 2018年10月