ChainerX うごかしてみるよ

# 本日は

カレンダー３日目埋まってないので引き続き書いていこうと思います。
ChainerXの導入を昨日書きましたが、今回は実際に動かしてみましょう

# MNIST 動きました。

カレンダー２日目の記事のようにMNISTは動きました。
実際に動かしてみるとわかるんですけれど通常のMNISTの例とChainerX側のExampleのMNISTを同時に走らせるとその速さが実感できると思います。

ChainerXの `train_mnist.py` では１３秒ほどで終了します。

# ResNet50 の方はどうでしょう？

MNIST の他にも
https://github.com/chainer/chainer/tree/master/chainerx_cc/examples/imagenet
にてImageNetの学習用スクリプトも用意されています。

１０００クラスのデータ落とすと気が遠くなりそうなので [Caltech101](http://www.vision.caltech.edu/Image_Datasets/Caltech101/) を用いた https://github.com/terasakisatoshi/chainer-caltech-101 を使うことにします。



# データの準備

[iDeep を使ってCPUでのChainerの推論速度をアップしよう](https://qiita.com/SatoshiTerasaki/items/c0a5a25b8bb82e95371b) の記事通りに行います。

# 学習

```console
$ python train_chx_resnet.py train.txt test.txt -j 8 -d cuda:0
```
そうすると下記のように進捗が出ます。プログレスバーは `tqdm` をつかっています。

```console
Namespace(batchsize=32, device='cuda:1', epoch=50, iteration=None, loaderjob=8, mean='mean.npy', root='.', test=False, train='train.txt', val='test.txt', val_batchsize=250)
100%|██████████████████████████████████████████████████████████████| 213/213 [00:49<00:00,  4.33it/s]
epoch 1... loss=4.42953271484375,	accuracy=0.112,	elapsed_time=51.761133432388306
100%|██████████████████████████████████████████████████████████████| 213/213 [00:47<00:00,  4.53it/s]
epoch 2... loss=4.365013671875,	accuracy=0.16,	elapsed_time=99.80267882347107
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.55it/s]
epoch 3... loss=4.41390185546875,	accuracy=0.108,	elapsed_time=147.61588311195374
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.54it/s]
epoch 4... loss=4.7586708984375,	accuracy=0.1,	elapsed_time=195.54803729057312
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.55it/s]
epoch 5... loss=4.062323486328125,	accuracy=0.18,	elapsed_time=243.3883125782013
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.55it/s]
epoch 6... loss=4.39565087890625,	accuracy=0.148,	elapsed_time=291.20321798324585
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.54it/s]
epoch 7... loss=4.57482275390625,	accuracy=0.136,	elapsed_time=339.06728291511536
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.55it/s]
epoch 8... loss=4.13157861328125,	accuracy=0.172,	elapsed_time=386.8594512939453
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.55it/s]
epoch 9... loss=4.64961767578125,	accuracy=0.152,	elapsed_time=434.6652834415436
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.55it/s]
epoch 10... loss=4.12386865234375,	accuracy=0.196,	elapsed_time=482.47300910949707
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.55it/s]
epoch 11... loss=4.1064111328125,	accuracy=0.18,	elapsed_time=530.2803256511688
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.55it/s]
epoch 12... loss=4.09931884765625,	accuracy=0.192,	elapsed_time=578.1029961109161
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.55it/s]
epoch 13... loss=3.987043701171875,	accuracy=0.184,	elapsed_time=625.9076073169708
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.55it/s]
epoch 14... loss=4.33284912109375,	accuracy=0.16,	elapsed_time=673.7270267009735
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.55it/s]
epoch 15... loss=4.13598095703125,	accuracy=0.164,	elapsed_time=721.5430347919464
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.55it/s]
epoch 16... loss=3.932227294921875,	accuracy=0.22,	elapsed_time=769.3474335670471
100%|██████████████████████████████████████████████████████████████| 213/213 [00:46<00:00,  4.55it/s]
```

- 動かしてわかったんですけれど、Save機能がついていませんでしたOTL... ChainerX用のレイヤー定義されている `params` のプロパティたちを逐次保存していくことにしていくとできるはずです。
- あと途中で accuracy がヘタるのと epoch 50 じゃたりなさそう。
  - データが１０１種類しかないのに出力が１０００にしていたからかな？？？


いちおう通常のResNet50版も用意しておきました。

```console
$ python train.py train.txt test.txt -j 8 --gpu 0 -a resnet50
Namespace(arch='resnet50', batchsize=32, epoch=50, gpu=1, initmodel=None, loaderjob=8, mean='mean.npy', out='result', resume='', root='.', test=False, train='train.txt', val='test.txt', val_batchsize=250)
epoch       iteration   main/loss   validation/main/loss  main/accuracy  validation/main/accuracy  lr        
4           1000        3.33122                           0.29725                                  0.01        
     total [####..............................................]  9.38%
this epoch [##################################................] 69.14%
      1000 iter, 4 epoch / 50 epochs
    4.6415 iters/sec. Estimated time to finish: 0:34:40.738241.

```

```
Namespace(arch='resnet50', batchsize=32, epoch=50, gpu=1, initmodel=None, loaderjob=8, mean='mean.npy', out='result', resume='', root='.', test=False, train='train.txt', val='test.txt', val_batchsize=250)
end of build_schedule()
Creating new backward schedule...
end of build_schedule()
epoch       iteration   main/loss   validation/main/loss  main/accuracy  validation/main/accuracy  lr        ch [################################..................] 64.45%
4           1000        3.37801                           0.295188                                 0.01        
9           2000        2.07377                           0.4835                                   0.01        
14          3000        1.43291                           0.617625                                 0.01        
18          4000        0.971574                          0.725125                                 0.01        
23          5000        0.65357                           0.80825                                  0.01        
28          6000        0.426234                          0.868156                                 0.01        
32          7000        0.262041                          0.916875                                 0.01        
37          8000        0.181415                          0.942906                                 0.01        
42          9000        0.129002                          0.959125                                 0.01        
46          10000       0.0772636                         0.977                                    0.01        
```

お、、、

```
$ python predict.py -a resnet50 --ideep
total accuracy rate =  0.9647058823529412
```

５０ epoch でよさそうですね。:innocent:

MNISTの場合に比べると学習スピードに大きな速度差は見られません。ResNet50自体大きめのネットワークなので学習時にGPUが常に１００％使うことが多いです。そのためChainerXと学習スピードに大きな違いは出ないんだとおもいます。もっと軽いネットワークであればChainerXのちからでGPUの資源を活用しながら学習スピードを向上させることができると思います。

# 推論方法はどうするんだろうか？

仮にモデルがセーブ出来てロードできる機構があるとすると推論のコードはどうなるんだろう？

学習スクリプトの `evaluate` を見てみます。

```python
def evaluate(model, X_test, Y_test, eval_size, batch_size):
    N_test = X_test.shape[0] if eval_size is None else eval_size

    if N_test > X_test.shape[0]:
        raise ValueError(
            'Test size can be no larger than {}'.format(X_test.shape[0]))

    model.no_grad()

    # TODO(beam2d): make chx.array(0, dtype=...) work
    total_loss = chx.zeros((), dtype=chx.float32)
    num_correct = chx.zeros((), dtype=chx.int64)
    for i in range(0, N_test, batch_size):
        x = X_test[i:min(i + batch_size, N_test)]
        t = Y_test[i:min(i + batch_size, N_test)]

        y = model(x)
        total_loss += compute_loss(y, t) * batch_size
        num_correct += (y.argmax(axis=1).astype(t.dtype)
                        == t).astype(chx.int32).sum()

    model.require_grad()

    mean_loss = float(total_loss) / N_test
    accuracy = int(num_correct) / N_test
    return mean_loss, accuracy
```

この実装にならって書くと良いと思います。

`model.no_grad()` を書いたあとその中で推論作業しているみたいですね。
`model.require_grad` でパラメータ更新を有効にする流れだと思います。

ここの部分は将来的にコンテキストマネージャーで

```python
with chainer.using_config('train', False):
   # do something
```

と同様な書き方ができる設計になると予想しています。

以上高級料理 ChainerX クッキングでした。