chainerでoptimizerの性能を比較する

#はじめに
chainerのMnistサンプルを使って、optimizerを比較する。

#環境
GPU:GTX1070
OS:Ubuntu14.04
CUDA:8.0RC
cuDNN:5.1
python:2.7.6
chainer:1.14.0
など

#jsonファイルをcsvファイルに変換するコードを作成
mnistサンプルでは以下の８３、８４行部分

```train_mnist.py
#Write a log of evaluation statistics for each epoch
trainer.extend(extensions.LogReport())
```

でlogにlossやaccuracyをjson形式で書き込んでいる。jsonは扱いにくいので、csvに変換するコードをまず作る。

```json2csv.py
#!/usr/bin/env python
import json, csv
import argparse

parser = argparse.ArgumentParser(description='experimentation of json to csv')
parser.add_argument('--logfilename', '-l', default='log',
                    help='name of Log file')
parser.add_argument('--csvfilename', '-c', default='log_csv.csv',
                    help='name of output csv file')
args = parser.parse_args()

filename = args.logfilename

#read json file
json_data = open(filename)
data = json.load(json_data)
json_data.close()

#open csv file
f = open(args.csvfilename, 'ab')
csvWriter = csv.writer(f)


header_list = ['iteration', 'epoch', 'main/loss', 'main/accuracy',
               'validation/main/loss', 'validation/main/accuracy']
csvWriter.writerow(header_list)

print 'len(data[0])',
print len(data[0])

for i in range(len(data)):
    if len(data[i]) == 4:
        contents_list = [data[i]["iteration"], data[i]["epoch"], data[i]["main/loss"], data[i]["main/accuracy"]
                         ]
    elif len(data[i]) == 6:
        contents_list = [data[i]["iteration"], data[i]["epoch"], data[i]["main/loss"], data[i]["main/accuracy"],
                         data[i]["validation/main/loss"], data[i]["validation/main/accuracy"]]


    csvWriter.writerow(contents_list)

f.close()
```

これでExcelとかでグラフ化して比較できる。
#比較対象
比較対象は以下
（１）通常のSGD
（２）Momentum
（３）AdaGrad
http://www.jmlr.org/papers/volume12/duchi11a/duchi11a.pdf
（４）Adam
https://arxiv.org/pdf/1412.6980v8.pdf
（５）RMSProp


#mnist_train.pyの設定を変更する
変更点１：parserにoptimizerを追加
コマンドからoptimizerを選択できるようにするため、parser内に以下を追加。

```train_mnist.py
parser.add_argument('--optimizer', '-p', type=str, default='Adam',
                    help='optimizer')
```

変更点２：optimizerの選択
以下の部分

```train_mnist.py
optimizer = chainer.optimizers.Adam()
```

をargs.optimizerによって選択できるように変更する。

```train_mnist.py
# Setup an optimizer
if args.optimizer == 'AdaGrad':
    optimizer = chainer.optimizers.AdaGrad()
elif args.optimizer == 'SGD':
    optimizer = chainer.optimizers.SGD()
elif args.optimizer == 'MomentumSGD':
    optimizer = chainer.optimizers.MomentumSGD()
elif args.optimizer == 'RMSprop':
    optimizer = chainer.optimizers.RMSprop()
else:
    optimizer = chainer.optimizers.Adam()
```

変更点３：LogReport()の変更
デフォルトでは1 epochごとにlogにlossやaccuracyが記録されるが、1 epoch時点でかなりlossが減少してるため、もっと細かく記録したい。そこで８４行目の以下の部分

```train_mnist.py
trainer.extend(extensions.LogReport())
```

を以下のようにして、100 iterationごとに記録させる。

```train_mnist.py
trainer.extend(extensions.LogReport(trigger=(100, 'iteration')))
```

LogReport()の引数に関しては、`chainer/training/extensions/log_report.py`に説明書きがある。

#実験
隠れ層のユニット数はデフォルトの100、epoch数は10、batchサイズはデフォルトの100で実験した。例えば、RMSpropの場合の実行コマンドは以下。

```
python train_mnist_opt.py -g=0 -e=10 -p='RMSprop' -u=100
```

#結果
結果は以下のグラフ。横軸がiteration、縦軸がtrainingのloss。
![optimizer_graph.png](https://qiita-image-store.s3.amazonaws.com/0/116706/bb4d5dc7-c80e-a610-a943-28d0a00d7688.png)

Adamは予想通りいいが、Momentumが意外と頑張ってる。条件を変えればまた違ってくるかも。
#コードの場所
今回のコードはこちらにあげてます。
https://github.com/masataka46/compare_opt_by_chainer