コンテンツにスキップするには Enter キーを押してください

chainer メモ(その1)1.11.0以降の mnist のメモ

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をいろいろ設定した後、これをやって実際に実行する。これは必須

すごい雑に自分なりにちょっとメモ。
なんでここ説明して、あそこ説明しないのとかになると思うけどそれはまだ良くわかって無いからだったり
 
実際にどう弄ったかなどは、まだ上げる予定




コメントする

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です