chainerが1.11.0になってから結構変わっていたので、それのコードの解説メモ
コードは ここ にあります。
train_mnist.pyってやつです。
from __future__ import print_function import argparse import chainer import chainer.functions as F import chainer.links as L from chainer import training from chainer.training import extensions # Network definition class MLP(chainer.Chain): def __init__(self, n_in, n_units, n_out): super(MLP, self).__init__( l1=L.Linear(n_in, n_units), l2=L.Linear(n_units, n_units), l3=L.Linear(n_units, n_out), ) def __call__(self, x): h1 = F.relu(self.l1(x)) h2 = F.relu(self.l2(h1)) return self.l3(h2) def main(): parser = argparse.ArgumentParser(description='Chainer example: MNIST') parser.add_argument('--batchsize', '-b', type=int, default=100, help='Number of images in each mini-batch') parser.add_argument('--epoch', '-e', type=int, default=20, help='Number of sweeps over the dataset to train') parser.add_argument('--gpu', '-g', type=int, default=-1, help='GPU ID (negative value indicates CPU)') parser.add_argument('--out', '-o', default='result', help='Directory to output the result') parser.add_argument('--resume', '-r', default='', help='Resume the training from snapshot') parser.add_argument('--unit', '-u', type=int, default=1000, help='Number of units') args = parser.parse_args() print('GPU: {}'.format(args.gpu)) print('# unit: {}'.format(args.unit)) print('# Minibatch-size: {}'.format(args.batchsize)) print('# epoch: {}'.format(args.epoch)) print('') # Set up a neural network to train # Classifier reports softmax cross entropy loss and accuracy at every # iteration, which will be used by the PrintReport extension below. model = L.Classifier(MLP(args.unit, 10)) if args.gpu >= 0: chainer.cuda.get_device(args.gpu).use() # Make a specified GPU current model.to_gpu() # Copy the model to the GPU # Setup an optimizer optimizer = chainer.optimizers.Adam() optimizer.setup(model) # Load the MNIST dataset train, test = chainer.datasets.get_mnist() train_iter = chainer.iterators.SerialIterator(train, args.batchsize) test_iter = chainer.iterators.SerialIterator(test, args.batchsize, repeat=False, shuffle=False) # Set up a trainer updater = training.StandardUpdater(train_iter, optimizer, device=args.gpu) trainer = training.Trainer(updater, (args.epoch, 'epoch'), out=args.out) # Evaluate the model with the test dataset for each epoch trainer.extend(extensions.Evaluator(test_iter, model, device=args.gpu)) # Dump a computational graph from 'loss' variable at the first iteration # The "main" refers to the target link of the "main" optimizer. trainer.extend(extensions.dump_graph('main/loss')) # Take a snapshot at each epoch trainer.extend(extensions.snapshot(), trigger=(args.epoch, 'epoch')) # Write a log of evaluation statistics for each epoch trainer.extend(extensions.LogReport()) # Print selected entries of the log to stdout # Here "main" refers to the target link of the "main" optimizer again, and # "validation" refers to the default name of the Evaluator extension. # Entries other than 'epoch' are reported by the Classifier link, called by # either the updater or the evaluator. trainer.extend(extensions.PrintReport( ['epoch', 'main/loss', 'validation/main/loss', 'main/accuracy', 'validation/main/accuracy'])) # Print a progress bar to stdout trainer.extend(extensions.ProgressBar()) if args.resume: # Resume from a snapshot chainer.serializers.load_npz(args.resume, trainer) # Run the training trainer.run() if __name__ == '__main__': main()
参考
https://www.monthly-hack.com/entry/2016/07/15/105005
ここのほうがぶっちゃけちゃんと説明してくれてる。
ただ比較とかはしない。
大まかな流れ
うえのほうで必要なchainerのいろいろをimport
その下でネットワークの定義
データを用意
trainerの設定・実行
ネットワークの定義
# Network definition class MLP(chainer.Chain): def __init__(self, n_in, n_units, n_out): super(MLP, self).__init__( l1=L.Linear(n_in, n_units), l2=L.Linear(n_units, n_units), l3=L.Linear(n_units, n_out), ) def __call__(self, x): h1 = F.relu(self.l1(x)) h2 = F.relu(self.l2(h1)) return self.l3(h2)
__init__には、l1,l2,l3などがあるが、何層にもなるネットワークのつながりの定義
n_inが入力層の数、n_unitsが中間層の数、n_outが出力層の数
mnistだと、28×28の数字が書かれた画像を入力層とし、0~9の数のどれが書かれているかという10通りの出力層があるので、n_inは784、n_outは10になる。
__call__には、__init__で定義したそれぞれをリンクをつかって、具体的にどうネットワークを組み立てるかの定義をする。
ここでは普通に順々に伝搬していく。
F.reluは活性化関数。ほかにはsigmoidとかがあったきが
Parser
一応parserのメモ
parser = argparse.ArgumentParser(description='Chainer example: MNIST') parser.add_argument('--batchsize', '-b', type=int, default=100, help='Number of images in each mini-batch') parser.add_argument('--epoch', '-e', type=int, default=20, help='Number of sweeps over the dataset to train') parser.add_argument('--gpu', '-g', type=int, default=-1, help='GPU ID (negative value indicates CPU)') parser.add_argument('--out', '-o', default='result', help='Directory to output the result') parser.add_argument('--resume', '-r', default='', help='Resume the training from snapshot') parser.add_argument('--unit', '-u', type=int, default=1000, help='Number of units') args = parser.parse_args() print('GPU: {}'.format(args.gpu)) print('# unit: {}'.format(args.unit)) print('# Minibatch-size: {}'.format(args.batchsize)) print('# epoch: {}'.format(args.epoch)) print('')
parser君はpythonを実行するときにいろいろなパラメータを指定しやすくする奴?と認識している
ターミナル(コマンドプロンプト)でpythonを実行するときに
python train_mnist.py -g 0 -u 100
とすると、
GPU: 0 # unit: 100 # Minibatch-size: 100 # epoch: 20
と表示される
add_argumentでひとつひとつ欲しいやつを加えていくのだが、使い方は
add_argument('後で呼ぶための名前', '-ターミナルでの指定方法', 数字ならtype=int, 指定のなかった場合のdefault値)
あとはなんとなくわかるはず。
データの初期化
chainerではtrainデータと、testデータを用意します。
train, test = chainer.datasets.get_mnist()
これはmnitsで使われるデータを取ってきてtrainとtestに入れてるだけです。
なかがどんなカタチになっているかというと、一つの行(train[0])に
[[.234809284, .324039284, .34809382 …. .04843098], 3]
というように、左に入力値と右にその答え(ラベル値)がセットで入っています。
イテレータ
従来では自分でfor分を用意して何回も回して学習させてとやっていたのですが、1.11.0からはtrainのようにデータに値を入れていて、これを使いますと言ってあげればfor分を書く必要はありません。
train_iter = chainer.iterators.SerialIterator(train, args.batchsize) test_iter = chainer.iterators.SerialIterator(test, args.batchsize, repeat=False, shuffle=False)
もうこれでいいらしい。おまじない感ある
trainer
trainerというものが追加されてこれがもうほぼほぼ勝手にいろいろやってくれるそう
まず、trainerを設定する。
updater = training.StandardUpdater(train_iter, optimizer, device=args.gpu) trainer = training.Trainer(updater, (args.epoch, 'epoch'), out=args.out)
以下については必ずしも必要なわけではないものもある。
trainer.extend(extensions.Evaluator(test_iter, model, device=args.gpu)) # これはいる。test_iterを使ってepochごとに評価してる(と思う) trainer.extend(extensions.dump_graph('main/loss')) # main/loss情報をファイルに落としている。json形式 trainer.extend(extensions.snapshot(), trigger=(args.epoch, 'epoch')) # epochごとのtrainerの情報を保存する。それを読み込んで、途中から再開などができる。これけすと結構早くなったりした? trainer.extend(extensions.LogReport()) # epochごとにlogをだす trainer.extend(extensions.PrintReport( ['epoch', 'main/loss', 'validation/main/loss', 'main/accuracy', 'validation/main/accuracy'])) # logで出す情報を指定する。 trainer.extend(extensions.ProgressBar()) # 今全体と、epochごとでどのぐらい進んでいるかを教えてくれる。 trainer.run() # trainerをいろいろ設定した後、これをやって実際に実行する。これは必須
すごい雑に自分なりにちょっとメモ。
なんでここ説明して、あそこ説明しないのとかになると思うけどそれはまだ良くわかって無いからだったり
実際にどう弄ったかなどは、まだ上げる予定