久しぶりに Chainer に戻ってみたところ v3.1 まで上がっていて、
これまでのコードでも多少の変更で動かなくはないが、新しい書き方が便利そうなので、
ちょっと勉強してみた。
例題として見つかるコードが mnist を使っているものが多く、
自分でデータを準備する方法が良くわらかなかったので、
とりあえず、2次関数の学習を例に取り組んでみた内容をメモとして残しておく。
以前に Chainer 1.x でしたのと同じ学習内容である。
1 x N x M x 1 の多層パーセプトロンを定義する。
入力はスカラー値 x、教師信号として x*x を使う。
学習用の x (-> train) と、評価用の x (-> test) を別々に作る。
train = np.array(range(-13,13,2), dtype=np.float32)
test = np.array(range(-10,10), dtype=np.float32)+0.5
dtype=np.float32 の numpy の array として作る。
教師データは x*x なので、
train_teacher = np.power(train,2)
test_teacher = np.power(test,2)
となる。
このままでは、[-13, -12, -11, ... ] という1次元の配列になっている。
これではニューラルネットの入力層に入力できない。
[ [-13], [-12], [-11], ... ] という形の2次元の配列に変換する。
reshape() を使って
train = train.reshape(len(train),1)
などとする。入力データも教師データも同様。
ニューラルネットの入力層に2ニューロンあれば、[ [x1, x2], .... ] という配列になる。
更に、chainer の TuppleDataset を用いて、教師データと組み合わせる。
train_set = tuple_dataset.TupleDataset(train, train_teacher)
test_set = tuple_dataset.TupleDataset(test, test_teacher)
最後にイテレータを作る。
batchsize = int(len(train)/2)
train_iter = Ch.iterators.SerialIterator(train_set, batchsize)
test_iter = Ch.iterators.SerialIterator(test_set, args_batchsize, repeat=False, shuffle=False)
モデルやオプティマイザーを作るところは以前と同じ。
データのイテレータを使って updaterを、更にそれを使って trainer を作る。
updater = training.StandardUpdater(train_iter, mopt, device=-1)
trainer = training.Trainer(updater, (800, 'epoch'), out="result")
これで準備完了。
以下に、コードの全容を示す。
========================================
import numpy as np
import matplotlib.pyplot as plt
import chainer as Ch
import chainer.functions as F
import chainer.links as L
from chainer import training
from chainer.datasets import tuple_dataset
from chainer.dataset import convert
from chainer.training import extensions
######################
# Definitions
#
class MyMLP(Ch.Chain):
train = False
def __init__(self, n_unit_h1, n_unit_h2):
super(MyMLP, self).__init__()
n_input = 1
n_output = 1
with self.init_scope():
# the size of the inputs to each layer will be inferred
self.l1 = L.Linear(n_input, n_unit_h1) # n_in -> n_units
self.l2 = L.Linear(n_unit_h1, n_unit_h2) # n_units -> n_units
self.l3 = L.Linear(n_unit_h2, n_output) # n_units -> n_out
def __call__(self, x):
h1 = F.dropout(F.sigmoid(self.l1(x)), ratio=0.05)
h2 = F.dropout(F.sigmoid(self.l2(h1)), ratio=0.05)
return self.l3(h2)
def test_plot(max, xx, mnn):
xd1 = Ch.Variable(xx[0])
xd2 = Ch.Variable(xx[1])
yd1 = mnn(xd1)
yd2 = mnn(xd2)
zd1 = xd1*xd1
zd2 = xd2*xd2
#print yd
plt.figure(figsize=(6, 6))
plt.plot(xd1.data, yd1.data, 'o', color='b')
plt.plot(xd2.data, yd2.data, 'o', color='r')
plt.plot(xd1.data, zd1.data, '.', color='black')
plt.plot(xd2.data, zd2.data, '.', color='black')
plt.show()
def onedim(x):
return x.reshape(len(x),1)
####################
# Data preparation
#
# Create data
train = np.array(range(-13,13,2), dtype=np.float32)
test = np.array(range(-10,10), dtype=np.float32)+0.5
train_teacher = np.power(train,2)
test_teacher = np.power(test,2)
train = onedim(train)
test = onedim(test)
train_teacher = onedim(train_teacher)
test_teacher = onedim(test_teacher)
train_set = tuple_dataset.TupleDataset(train, train_teacher)
test_set = tuple_dataset.TupleDataset(test, test_teacher)
# Iterator
batchsize = int(len(train)/2)
train_iter = Ch.iterators.SerialIterator(train_set, batchsize)
test_iter = Ch.iterators.SerialIterator(test_set, batchsize, repeat=False, shuffle=False)
###################################################
# Set up a neural network to train
# Classifier reports mean_squared_error loss at every iteration,
# which will be used by the PrintReport extension below.
mnn = MyMLP(100, 160)
model = L.Classifier(mnn, lossfun=F.mean_squared_error)
#model.compute_accuracy = False
model.train = True
eval_model = model.copy()
eval_model.train = False
# Setup an optimizer
mopt = Ch.optimizers.SGD(0.0005)
mopt.setup(model)
updater = training.StandardUpdater(train_iter, mopt, device=-1)
trainer = training.Trainer(updater, (800, 'epoch'), out="result")
###################################################
# Learn
#
print "learn-------"
trainer.extend(extensions.Evaluator(test_iter, eval_model, device=-1))
#trainer.extend(extensions.dump_graph('main/loss'))
#trainer.extend(extensions.snapshot(), trigger=(10, 'epoch'))
trainer.extend(extensions.LogReport(), trigger=(10, 'epoch'))
#trainer.extend(extensions.PlotReport(['main/loss', 'validation/main/loss'], x_key='epoch', file_name='loss.png'))
#trainer.extend(extensions.PrintReport(['epoch', 'main/loss']))#, 'validation/main/loss', 'main/accuracy', 'validation/main/accuracy']))
trainer.extend(extensions.ProgressBar())
trainer.run()
print "learning finish---------"
with Ch.using_config('train', False):
test_plot(10, [train,test], mnn)
この方法で学習200回目、400回目、800回目の結果を以下に示す。
青丸は学習に用いた x に対して、ニューラルネットが出力した値、
赤丸は学習には用いなかった x に対して、ニューラルネットが出力した値、
黒丸は x*x の正解。
学習の回数が増えるに従って、ニューラルネットワークの出力が x*x に近づいている様子がわかる。
200回目。
400回目。
800回目。
このモデルの中では、学習中はニューラルネットワーク内 dropout を使ったり、
評価するとき(グラフを書くとき)には dropout しないように
with Ch.using_config('train', False):
を使ったりしている。