Chainerを高速化するiDeepをインストールする

# はじめに

Chainer 4から[iDeep](https://github.com/intel/ideep)が正式にサポートされるようになりました。iDeepを使うことでCPUによる学習・推論が高速になります。もちろん、iDeepはXeon系のCPUを主なターゲットとしていますが、経験上ノートPCレベルでも多少の速度向上があります。

iDeepの活用方法について説明したウェブサイトはいくつかあるのですが、導入をMKLのインストールから通しで説明しているサイトがなかったので、備忘録のためにiDeepの導入方法を記載します。

なお、本説明はUbuntu 16.04、Chainer 5.0.0rc1を対象にしています。iDeepやChainerのAPIは今後どんどんかわってゆくと思われるので、適宜ソースのサイトを参照してください。

# 手順

### Pythonの導入

適当な方法でPythonが使える環境を作ります。このとき、Pythonのshared objectを忘れず一緒に導入します。たとえば、pyenvならば次のようにshared objectをインストールします。

```
PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.6.4
```

### MKLの導入

Intelの[公式](https://software.intel.com/en-us/articles/installing-intel-free-libs-and-python-apt-repo)を参考にAPT経由でインストールします。

```bash
# Add GPG key
wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-
SW-PRODUCTS-2019.PUB
sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB
rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB

# Add intel repo to apt
sudo wget https://apt.repos.intel.com/setup/intelproducts.list -O 
/etc/apt/sources.list.d/intelproducts.list

# install MKL
sudo apt-get update
# 最新のMKLをapt search intel-mkl で選んだ
sudo apt install intel-mkl-2019.0-045
```

このままでは他のライブラリがMKLを見つけられないので、`LD_LIBRARY_PATH`にMKLを追加

```bash
echo 'export LD_LIBRARY_PATH="/opt/intel/mkl/lib/intel64:/opt/intel/lib/intel64:$LD_LIBRARY_PATH"' >> ~/.bashrc
# zshユーザはこちら
# echo 'export LD_LIBRARY_PATH="/opt/intel/mkl/lib/intel64:/opt/intel/lib/intel64:$LD_LIBRARY_PATH"' >> ~/.zshrc
```

### MKL-DNNの導入

[公式の情報](https://github.com/intel/mkl-dnn)にしたがって導入します。

```bash
# 別にdoxygenとかはいらないように見える
sudo apt install cmake checkinstall

git clone --depth 1 https://github.com/intel/mkl-dnn.git
cd scripts && ./prepare_mkl.sh && cd ..
mkdir -p build && cd build && cmake $CMAKE_OPTIONS .. && make

# 別に make install で入れても良い
sudo checkinstall --pkgname mkl-dnn --pkgversion 0.16 --pkglicense Apache-2.0 --maintainer 'Intel Corporation' --provides mkl-dnn --requires intel-mkl
```

ちなみにcheckinstallは次のように設定しました。

```
checkinstall 1.6.2, Copyright 2009 Felipe Eduardo Sanchez Diaz Duran
           This software is released under the GNU GPL.


The package documentation directory ./doc-pak does not exist.
Should I create a default set of package docs?  [y]: y

Preparing package documentation...OK

*** No known documentation files were found. The new package
*** won't include a documentation directory.

*****************************************
**** Debian package creation selected ***
*****************************************

This package will be built according to these values:

0 -  Maintainer: [ Intel Corporation ]
1 -  Summary: [ Package created with checkinstall 1.6.2 ]
2 -  Name:    [ mkl-dnn ]
3 -  Version: [ 0.16 ]
4 -  Release: [ 1 ]
5 -  License: [ Apache-2.0 ]
6 -  Group:   [ checkinstall ]
7 -  Architecture: [ amd64 ]
8 -  Source location: [ build ]
9 -  Alternate source location: [  ]
10 - Requires: [ intel-mkl ]
11 - Provides: [ mkl-dnn ]
12 - Conflicts: [  ]
13 - Replaces: [  ]

Enter a number to change any of them or press ENTER to continue:

Installing with make install...

========================= Installation results ===========================
[  0%] Building CXX object src/CMakeFiles/mkldnn.dir/common/lrn.cpp.o

...

-- Installing: /usr/local/include/mkldnn.hpp

======================== Installation successful ==========================

Some of the files created by the installation are inside the home directory: /home

You probably don't want them to be included in the package.
Do you want me to list them?  [n]: n
Should I exclude them from the package? (Saying yes is a good idea)  [n]: yes

Some of the files created by the installation are inside the build
directory: /home/koreyou/work/chainer-inception-v3/mkl-dnn/build

You probably don't want them to be included in the package,
especially if they are inside your home directory.
Do you want me to list them?  [n]: n
Should I exclude them from the package? (Saying yes is a good idea)  [y]: yes
```

### numpy-mklの導入

MKLがリンクされたnumpyを導入します。普通にnumpyを導入してしまうと、MKLがリンクされないことがあるので ["pip で MKL にリンクされた numpy, scipy が自動的にインストールされるようにする"](https://qiita.com/grafi/items/3f24b514d46c41cc9c58) を参考にnumpy-mklを導入します。

```bash
# もしインストールされてれいれば
pip uninstall numpy scipy

pip install numpy
```

ちゃんとMKLが使われているか確認しましょう。librariesのところがmkl_rtとなっていれば成功です。

```bash
python -c "import numpy; numpy.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']
```


### iDeepの導入

いよいよiDeepの導入です。以前とは違い、pypi経由で簡単に導入できます。

```bash
pip install 'ideep4py<2.1'
```

https://docs.chainer.org/en/stable/tips.html に推奨のバージョンが書いてあるので、それに従ったほうがよいでしょう。

`python -c "import ideep4py"`で特にエラーが出なければちゃんとインストールできています。

### Chainerで確認

cupyと同様にchainer側でiDeepを呼ぶだけなので、Chainerをインストールし直す必要はありません（たぶん）。次のコマンドで`True`と出力されればちゃんとiDeepが使えるようになっています。

```bash
python -c "import chainer; print(chainer.backends.intel64.is_ideep_available())"
```

以上でiDeepの導入は終了です。iDeepを導入したからといってすべての演算がiDeepに自動的に切り替わるわけではないため、[公式](https://docs.chainer.org/en/stable/tips.html) を参考にiDeepを有効にしてください。


# 参考

* https://qiita.com/ikeyasu/items/62781ac2eeff5be4e5f4
* https://qiita.com/grafi/items/3f24b514d46c41cc9c58