ChainerX とりあえず入れてみよう

# この記事を読む前に

この記事は2018年のChainerアドベントカレンダーの一つとしてかかれました。
当時のChainerXはリリースされたばかりであり、動作するプラットフォームは限られていましたが、ChainerのV6の正式版がリリースされている現在では多くのOS,プラットフォームでChainerXの導入が可能となっています。（ただし、あくまでもインストールのみを確認しており、プログラマの意図通りに動作するかは非自明です。）


# 本日は

師走の月になってきました。

Chainerのカレンダー空いていたというのと


<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ChainerXどうやら無事にマージされたようだ。めでたい☺<a href="https://t.co/Iw4zLszbvN">https://t.co/Iw4zLszbvN</a></p>&mdash; Keisuke Umezawa (Chainer Evangelist) (@kmechann) <a href="https://twitter.com/kmechann/status/1068359627161591808?ref_src=twsrc%5Etfw">2018年11月30日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ChainerXでAdvent Calender 書くマンおらんか〜 <a href="https://t.co/zPrwAmpQQl">https://t.co/zPrwAmpQQl</a></p>&mdash; Keisuke Umezawa (Chainer Evangelist) (@kmechann) <a href="https://twitter.com/kmechann/status/1068359771617558528?ref_src=twsrc%5Etfw">2018年11月30日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

のもあったので書くマンになります。

ふだん、Chainerにはおせわになっているし、なにか貢献できれば・・・。

# ChainerX

[ChainerのPR #5725](https://github.com/chainer/chainer/pull/5725#issue-233827466) でマージされました。

> ChainerX is a new ndarray+autograd implementation for Chainer. It aims at reducing Python overhead for host-heavy workloads, providing Python-free basis for application coding, and making device support pluggable.

> This PR is to move the development to the main repository. It includes:

> 
- C++ implementation of the new ndarray and related routines (chainerx_cc),
- Python binding of ChainerX (chainerx_cc/python and chainerx),
- Modifications on Chainer to support the new ndarray, and
- Documentation of ChainerX
We are planning to include this feature in the next beta release.

>
This PR is very big so that it's impossible to run review here, but we still use PR instead of silently merging it for visibility of changes included in the release. I'd like to merge it once CI is made ready and we confirm that this PR passes that.

cupy とか ideep4py のように多次元配列をあつかう（しかも自動微分付き）新しいバックエンドの追加のようなものでしょうか？？
下記のTweetがよくまとまっています。


<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ChainerXをざっと眺めた<br>・Chainer自体の更新ではなく、backendの追加<br>・C++で書かれたNumPy/CuPy風のライブラリ<br>・CPU/GPU両方で動く<br>・Pythonのオーバーヘッドを削減することによる高速化を目指す<br>・ChainerXそのものにNN用の関数や自動微分が入っている<a href="https://t.co/IMWdeJlKc1">https://t.co/IMWdeJlKc1</a></p>&mdash; not (@not_522) <a href="https://twitter.com/not_522/status/1067579599758872576?ref_src=twsrc%5Etfw">2018年11月28日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

出たばかりでなんとも言えませんが、PythonをさけてC++での深層学習の CPU/GPU　の学習・（および推論も？）できるのかもしれませんね。

# 入れてみよう

ChainerのGitHubのページからたどると [ChainerXのインストール方法がかかれています](https://github.com/chainer/chainer/blob/master/docs/source/chainerx/install/index.rst)

```console
$ export CHAINER_BUILD_CHAINERX=1
$ export MAKEFLAGS=-j8  # Using 8 parallel jobs.
$ pip install --pre chainer
Collecting chainer
Requirement already satisfied: filelock in /home/terasaki/miniconda3/lib/python3.6/site-packages (from chainer) (3.0.9)
Requirement already satisfied: protobuf>=3.0.0 in /home/terasaki/miniconda3/lib/python3.6/site-packages (from chainer) (3.6.1)
Requirement already satisfied: numpy>=1.9.0 in /home/terasaki/miniconda3/lib/python3.6/site-packages (from chainer) (1.15.4)
Requirement already satisfied: six>=1.9.0 in /home/terasaki/miniconda3/lib/python3.6/site-packages (from chainer) (1.11.0)
Requirement already satisfied: setuptools in /home/terasaki/miniconda3/lib/python3.6/site-packages (from protobuf>=3.0.0->chainer) (40.4.3)
Installing collected packages: chainer
Successfully installed chainer-6.0.0a1
terasaki@wizzard:~/tmp$ 

```

お？楽勝かな？？

`--pre` は [pypaのドキュメント](https://pip.pypa.io/en/stable/reference/pip_install/) で次のような説明があります。
> Include pre-release and development versions. By default, pip only finds stable versions.

はじめてしった・・・。ちなみにバージョンはChainer６に昇格するので開発中のPCでは取り扱い注意です（普段Dockerをつかっていれば問題ないですが）

## つかってみよう

[ChainerXのチュートリアル](https://github.com/chainer/chainer/blob/master/docs/source/chainerx/tutorial/index.rst)
によると Pythonからは `import chainerx` でモジュールをインポートしていろいろできるとのこと

```python
>>> import chainer
>>> chainer.__version__
'6.0.0a1'
>>> import chainerx
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'chainerx'
```

ん？？？

# 入れてみよう


```console
$ pip uninstall chainer
Uninstalling chainer-6.0.0a1:
  Would remove:
    /home/terasaki/miniconda3/lib/python3.6/site-packages/chainer-6.0.0a1.dist-info/*
    /home/terasaki/miniconda3/lib/python3.6/site-packages/chainer/*
    /home/terasaki/miniconda3/lib/python3.6/site-packages/chainermn/*
Proceed (y/n)? y
  Successfully uninstalled chainer-6.0.0a1
$ git clone https://github.com/chainer/chainer.git
$ cd chainer
$ pip install .
Processing /home/terasaki/tmp/chainer
Requirement already satisfied: setuptools in /home/terasaki/miniconda3/lib/python3.6/site-packages (from chainer==6.0.0a1) (40.4.3)
Requirement already satisfied: filelock in /home/terasaki/miniconda3/lib/python3.6/site-packages (from chainer==6.0.0a1) (3.0.9)
Requirement already satisfied: numpy>=1.9.0 in /home/terasaki/miniconda3/lib/python3.6/site-packages (from chainer==6.0.0a1) (1.15.4)
Requirement already satisfied: protobuf>=3.0.0 in /home/terasaki/miniconda3/lib/python3.6/site-packages (from chainer==6.0.0a1) (3.6.1)
Requirement already satisfied: six>=1.9.0 in /home/terasaki/miniconda3/lib/python3.6/site-packages (from chainer==6.0.0a1) (1.11.0)
Building wheels for collected packages: chainer
  Running setup.py bdist_wheel for chainer ... done
  Stored in directory: /tmp/pip-ephem-wheel-cache-nolm7ktr/wheels/dc/eb/02/fad9e4ce07b707b8063e7e245d168846851a2b3cf05d432b96
Successfully built chainer
Installing collected packages: chainer
Successfully installed chainer-6.0.0a1
```

なにかしらのビルドは通ったっぽい。

# サンプルを動かす

Ubuntu上でしています。

```python:study_x.py
import chainerx as chx

x = chx.array([[0, 1, 2], [3, 4, 5]], dtype=chx.float32)

print(x.shape)
print(x.dtype)
print(x.device)
```

```console
$ python3 study_x.py
(2, 3)
float32
native:0
```

UGOITA・HAGOITA・DEKITA（歓喜）

# GPU 版も動かしたい

CuPy のインストールが時間かかります（CuPyは読み方`くーぱい` らしいけれど `くぴー` のほうが可愛い気がする.でもそうするとNumPyが`ぬむぴー`になって変か・・・）

```console
$ export CHAINER_BUILD_CHAINERX=1
$ export CHAINERX_BUILD_CUDA=1
$ export CUDNN_ROOT_DIR=path/to/cudnn
$ export MAKEFLAGS=-j8  # Using 8 parallel jobs.
$ git clone https://github.com/cupy/cupy.git
$ cd cupy 
$ pip install .
$ cd ../chainer
$ pip install .
```


```python
>>> import chainerx
>>> cuda_x = chainerx.array([1,2,3],device='cuda:0')
>>> cuda_x
array([1, 2, 3], shape=(3,), dtype=int64, device='cuda:0')
>>> cuda_x. # ここでタブを連打
cuda_x.T                      cuda_x.fill(                  cuda_x.reshape(
cuda_x.argmax(                cuda_x.get_grad(              cuda_x.set_grad(
cuda_x.as_grad_stopped(       cuda_x.grad                   cuda_x.shape
cuda_x.astype(                cuda_x.is_backprop_required(  cuda_x.size
cuda_x.backward(              cuda_x.is_contiguous          cuda_x.squeeze(
cuda_x.cleargrad(             cuda_x.is_grad_required(      cuda_x.strides
cuda_x.clip(                  cuda_x.itemsize               cuda_x.sum(
cuda_x.copy(                  cuda_x.max(                   cuda_x.take(
cuda_x.data_ptr               cuda_x.nbytes                 cuda_x.to_device(
cuda_x.data_size              cuda_x.ndim                   cuda_x.transpose(
cuda_x.device                 cuda_x.offset                 cuda_x.view(
cuda_x.dot(                   cuda_x.ravel(                 
cuda_x.dtype                  cuda_x.require_grad(          
>>> cuda_x.to_device('native:0')
array([1, 2, 3], shape=(3,), dtype=int64, device='native:0')
```

うっかり `export CUDNN_ROOT_DIR=path/to/cudnn` 抜かしてしまったんですけれど、動いています. ローカルにすでにcuDNNいれていたからかな？ ~~(ドキュメントにExampleがほしいです)。~~

追記 2019/06/06：

cuDNN のインストール方法によって格納場所が異なるみたいなので

https://stackoverflow.com/questions/31326015/how-to-verify-cudnn-installation

の議論にあるパスを眺めてみると良いです。この後

```
$ pip install cupy -vvvv
```

をした際に出力されるログにおいてcuDNNのパスが認識されていれば大丈夫なはず。


# ラズパイ3でいけるかな？？？

ideep の恩恵受けられないので動くとうれしみが。

```shell_session
pi@raspberrypi:~ $ git clone https://github.com/chainer/chainer.git
Cloning into 'chainer'...
remote: Enumerating objects: 25, done.
remote: Counting objects: 100% (25/25), done.
remote: Compressing objects: 100% (18/18), done.
remote: Total 157873 (delta 9), reused 19 (delta 7), pack-reused 157848
Receiving objects: 100% (157873/157873), 37.95 MiB | 940.00 KiB/s, done.
Resolving deltas: 100% (115947/115947), done.
pi@raspberrypi:~ $ cd chainer/
pi@raspberrypi:~/chainer $ ls
LICENSE       chainer_bibtex.txt        chainerx_cc      setup.cfg
MANIFEST.in   chainermn                 codecov.yml      setup.py
README.md     chainermn_bibtex.txt      docker           tests
appveyor      chainerx                  docs
appveyor.yml  chainerx.md               examples
chainer       chainerx_build_helper.py  readthedocs.yml
pi@raspberrypi:~/chainer $ export CHAINER_BUILD_CHAINERX=1
pi@raspberrypi:~/chainer $ export MAKEFLAGS=-j4
pi@raspberrypi:~/chainer $ sudo pip3 install .
Processing /home/pi/chainer
Requirement already satisfied: filelock in /usr/local/lib/python3.5/dist-packages (from chainer==6.0.0a1)
Requirement already satisfied: numpy>=1.9.0 in /usr/local/lib/python3.5/dist-packages (from chainer==6.0.0a1)
Requirement already satisfied: protobuf>=3.0.0 in /usr/local/lib/python3.5/dist-packages (from chainer==6.0.0a1)
Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (from chainer==6.0.0a1)
Requirement already satisfied: six>=1.9.0 in /usr/lib/python3/dist-packages (from chainer==6.0.0a1)
Installing collected packages: chainer
  Found existing installation: chainer 5.0.0
    Uninstalling chainer-5.0.0:
      Successfully uninstalled chainer-5.0.0
  Running setup.py install for chainer ... done
Successfully installed chainer-6.0.0a1
```

```python:python3
pi@raspberrypi:~ $ python3
Python 3.5.3 (default, Sep 27 2018, 17:25:39) 
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import chainerx
>>> chainerx.__version__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'chainerx' has no attribute '__version__'
>>> import chainerx as chx
>>> x=chx.array([1,2,3,4],dtype=chx.float32)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'chainerx' has no attribute 'array'
```

あぁぁ・・・いぃぃ・・・うぅぅ。

# Macだと？

~~ざんねんながらビルドでこけてしまいます。~~
更新：2019/06/06更新: Chainerの V6.0.0 ではビルド成功できました！！！！

```
$ export CHAINER_BUILD_CHAINERX=1
$ pip uninstall chainer # 古いChainerを削除
$ pip install chainer
$ python
>>> import chainerx as chx
>>> chx.array([1,2,3])
array([1, 2, 3], shape=(3,), dtype=int64, device='native:0')
>>> import chainer
>>> chainer.__version__
'6.0.0'
```

# そんなわけで

すこし寄り道しましたが、Ubuntuでは ChainerX の導入はいけそうです。Chainer５触ったばかりの人間ですが、Chainer6を導入して背伸びすることができ、良い経験をすることができたとおもいます。以下、うごいたUbuntu16.04マシーンでMNIST学習してみます。


# MNIST

https://github.com/chainer/chainer/tree/master/chainerx_cc/examples/mnist を参考にしました。

```console
$ cd chainer/chainerx_cc/example/mnist
$ bash download.sh
$ ls
download.sh  mnist  README.md  train_mnist.py
$ python train_mnist.py --device=cuda:0
epoch 1... loss=0.483272021484375,	accuracy=0.8827,	elapsed_time=0.9652724266052246
epoch 2... loss=0.3484232666015625,	accuracy=0.9055,	elapsed_time=1.627737283706665
epoch 3... loss=0.3021266845703125,	accuracy=0.9153,	elapsed_time=2.283825159072876
epoch 4... loss=0.277078173828125,	accuracy=0.9199,	elapsed_time=2.9371321201324463
epoch 5... loss=0.2530198974609375,	accuracy=0.9293,	elapsed_time=3.594005823135376
epoch 6... loss=0.2379763427734375,	accuracy=0.9335,	elapsed_time=4.25266695022583
epoch 7... loss=0.224865869140625,	accuracy=0.9369,	elapsed_time=4.911699056625366
epoch 8... loss=0.214370947265625,	accuracy=0.9392,	elapsed_time=5.569540739059448
epoch 9... loss=0.2032531982421875,	accuracy=0.9426,	elapsed_time=6.233461380004883
epoch 10... loss=0.1948798583984375,	accuracy=0.9437,	elapsed_time=6.891218423843384
epoch 11... loss=0.1849767578125,	accuracy=0.9466,	elapsed_time=7.554072856903076
epoch 12... loss=0.1776248291015625,	accuracy=0.9474,	elapsed_time=8.219156503677368
epoch 13... loss=0.16978060302734374,	accuracy=0.95,	elapsed_time=8.877105951309204
epoch 14... loss=0.16511090087890626,	accuracy=0.9513,	elapsed_time=9.53380298614502
epoch 15... loss=0.1575286376953125,	accuracy=0.9538,	elapsed_time=10.190188884735107
epoch 16... loss=0.15317554931640626,	accuracy=0.9543,	elapsed_time=10.849192380905151
epoch 17... loss=0.14726854248046875,	accuracy=0.9571,	elapsed_time=11.506675243377686
epoch 18... loss=0.1426803955078125,	accuracy=0.9567,	elapsed_time=12.164527416229248
epoch 19... loss=0.138498828125,	accuracy=0.9592,	elapsed_time=12.825119733810425
epoch 20... loss=0.1334173828125,	accuracy=0.96,	elapsed_time=13.483542919158936
```

`watch nvidia-smi` を眺めながらするとGPUがむぉおおおおと言わんばかりに動いているのがわかります。

CPU だとこれぐらい

```
$ python train_mnist.py
epoch 1... loss=0.479378076171875,	accuracy=0.8823,	elapsed_time=21.332125425338745
epoch 2... loss=0.3438715087890625,	accuracy=0.9064,	elapsed_time=39.776408195495605
epoch 3... loss=0.2983966064453125,	accuracy=0.9183,	elapsed_time=54.61747431755066
epoch 4... loss=0.2714416748046875,	accuracy=0.9253,	elapsed_time=69.31229591369629
epoch 5... loss=0.2527154541015625,	accuracy=0.9285,	elapsed_time=84.05134153366089
epoch 6... loss=0.2373039306640625,	accuracy=0.9346,	elapsed_time=98.87632894515991
epoch 7... loss=0.223982470703125,	accuracy=0.9378,	elapsed_time=118.0163414478302
```



# もっとこまかい Example ほしい？

- https://github.com/chainer/chainer/tree/master/tests/chainerx_tests/acceptance_tests

とかが参考になりそうです。

以上初めてのアドベントカレンダーでした。