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サンプルでは以下の83、84行部分

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とかでグラフ化して比較できる。

比較対象

比較対象は以下
(1)通常のSGD
(2)Momentum
(3)AdaGrad
http://www.jmlr.org/papers/volume12/duchi11a/duchi11a.pdf
(4)Adam
https://arxiv.org/pdf/1412.6980v8.pdf
(5)RMSProp

mnist_train.pyの設定を変更する

変更点1:parserにoptimizerを追加
コマンドからoptimizerを選択できるようにするため、parser内に以下を追加。

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

変更点2: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()

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

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。

Adamは予想通りいいが、Momentumが意外と頑張ってる。条件を変えればまた違ってくるかも。

コードの場所

今回のコードはこちらにあげてます。
https://github.com/masataka46/compare_opt_by_chainer