iDeep を使ってCPUでのChainerの推論速度をアップしよう

# 本日は

Chainerのｖ４がリリースされました。

このアップデートでChainerのバックエンドが追加されました。IntelのCPU上で学習・推論が高速になったようです。

- [オープンソースの深層学習フレームワークChainer および 汎用配列計算ライブラリCuPy の最新版となるv4をリリース](https://www.preferred-networks.jp/ja/press-release)

> Intel Deep Learning Package (iDeep)※2バックエンドを追加して、Intel CPUでの学習および推論の高速化を実現しました。これにより、当社のベンチマークにおいて、GoogLeNet（画像認識用のニューラルネットワークのひとつ）でのCPU使用時の推論速度が従来比8.9倍に向上※3しました。

- [v4.0.0](https://github.com/chainer/chainer/releases/tag/v4.0.0)

> Support iDeep backend for acceleration on Intel CPUs. We observed that the GoogLeNet inference with batch size 1 is made x8.9 faster (compared to the case without iDeep, both on Intel(R) Xeon(R) CPU E5-2623 v3 @ 3.00GHz with MKL).

というわけでCPU上での動作が良くなったみたいなので実験してみましょう。

# 動かす対象

Chainerのリポジトリの examples にある imagenet 

https://github.com/chainer/chainer/tree/master/examples/imagenet

にGoogLeNetの実装があるのでこれを使っていこうと思います。ただ、悲しいことに　

> This example currently does not include dataset preparation script.

となってますのでデータ収集やら推論のコードやらは自前で書かないといけないっぽいです。

過去に動かしていた方がいらっしゃったようです

- [Chainerのimagenetを[確実に]動かす](https://qiita.com/rerere0101/items/fde1661df4a26f1d0626)

引用しているリポジトリ

https://github.com/shi3z/chainer_imagenet_tools

を見たのですがPython2系でツールが実装されているようなのでPython3で動作するように
データ収集、準備、学習、推論までできるようなスクリプトたちを下記のリポジトリにて公開しました（名前を変更しました）。

- https://github.com/terasakisatoshi/chainer-caltech-101

# 使い方

とりあえずクローンします。

```shell-session
$ git@github.com:terasakisatoshi/chainer-caltech-101.git
```

## データセットの準備

ImageNet（学習サンプル）をダウンロードします。

```shell-session
$ cd chainer-imagenet
$ $ wget http://www.vision.caltech.edu/Image_Datasets/Caltech101/101_ObjectCategories.tar.gz
```

ダウンロードしたらこれを解凍しておきます。
さて、データを256x256のサイズの画像に変換しなければいけません。以下のコマンドでそれを実行します。

```shell-session
$ python reshape.py --source_dir 101_ObjectCategories --target_dir reshaped
```

データーを整えたら学習のコードに入力するテキストデータを生成します。
これは `LabeledImageDataset` の引数に渡されます。

ファイルの中身やLabeledImageDatasetの使い方等は

- [chainerのLabeledImageDatasetで読み込める画像リストのテキストを作成する](https://qiita.com/ka10ryu1/items/72797f705e1744326036)

が参考になるかもしれません。

いずれにせよ次のコマンドを実行します。

```shell-session
$ python create_dataset.py reshaped
```

出力として　`train.txt, test.txt, label.txt`　が得られます。
`label.txt` に格納されるのは ImageNetのデータセットのラベル名です。格納されている順番と `train.txt` or `test.txt` に格納される２列目の番号は対応しています。

最後に学習に必要な `mean.npy` を用意しておきます。

```shell-session
$ python compute_mean.py train.txt
```

# 学習

## Chainer のアップグレード

```shell-session
$ pip install -U chainer
```

CuPy も自動でアップグレードされます。

## 学習の実行
学習する方法は次のとおりです。パラメータはお好みで。

```shell-session
$ python train.py train.txt test.txt -a googlenet -E 50 -g 0 -j 8
```

GPUを使うときは `-g 0` をオプションとして加えてください.　デフォルトではCPUで学習が進んでしまいます。

# 推論

iDeep を使うために　`ideep4py` をインストールします。マシーンはUbuntuで確認しました。

```shell-session
$ pip install ideep4py
```

conda の場合は

```shell-session
$ conda install -c intel/label/test ideep4py
```

次の方法でもインストールできます。

```shell-session
$ sudo apt install swig
$ git clone https://github.com/intel/ideep.git
$ cd ideep
$ git submodule update --init && mkdir build && cd build && cmake ..
$ cd ../python
$ python setup.py install
```

Mac でもテストをしているらしいのですが、 OpenMP 周りでうまくビルドができませんでした・・・。

次のステップは iDeep が導入できなくても動くはずです。

## 推論の実行


```shell-session
$ python predict.py
```

仏像画像がうまく推論できるかを確かめています。大体正解率は８８％ほどになりました。

ここで `ideep4py` の導入に成功された方は `--ideep` をオプション引数につけてみましょう。

```
$ python predict.py --ideep
```

MKL でリンクされる conda の Numpyの環境では True 5.6　秒 False ２７秒 という結果になりました。

動作が高速になっていることが確認できますね。pip で導入されるNumpyでは True 8.4, False 39.9 でした。リンクされるライブラリが違っても、iDeepを使ったほうが速くなるのは確実ようです。（とはいえども公式の8.9倍にはとどきませんが・・・）

Numpyのリンク周りは下記が詳しいです。

- [pip で MKL にリンクされた numpy, scipy が自動的にインストールされるようにする](https://qiita.com/grafi/items/3f24b514d46c41cc9c58)
- [numpy, scipyでOpenBLASを使う](https://qiita.com/yukiB/items/bec24db4a5a41db02895)