※現在、ブログ記事を移行中のため一部表示が崩れる場合がございます。
順次修正対応にあたっておりますので何卒ご了承いただけますよう、お願い致します。

Chainer:学習進行状況を確認しよう


2017年 02月 15日

とりあえず、前回で学習ができているらしいことが確認できた。
しかし、それは、延々と学習した後で、テストデータとして温存しておいたデータにより確認しただけだ。
途中の学習状態、つまり、成功率がどのように変化していくのかを見たい!

ということで、最後にあった成功率を求める部分を、関数としてまとめてみた。

# Testデータで学習成果を確認する
def check(data,answer,model):

xt = Variable(data, volatile='on')	# 学習不要
yy = model.fwd(xt)

ans = yy.data
nrow, ncol = ans.shape
ok = sum([np.argmax(ans[i,:])==answer[i] for i in range(nrow)])
return (ok * 1.0)/nrow	# 正解率
データ、正解、モデルを与えると、このモデルを使ってデータを評価し正解との一致率を返す。

この関数(クラス内でないので、メソッドとは言わない)は、テストデータによる評価に使えるのだが、この形式にデータを合わせさえすれば、学習データを用いた場合の正解率も計算できる。

ということであるが、学習データ(教師データ)の正解の形式が違っているので、リストtransに教師データの答えを入れた。
# 学習データ(xtrain,ytrain)とテストデータ(xtest,yans)に分ける
index  = np.arange(N)
xtrain = X[index[index % 3 != 0],:]
ytrain = Y2[index[index % 3 != 0],:]
trans  = Y[index[index % 3 != 0]]	# 追加
xtest  = X[index[index % 3 == 0],:]
yans   = Y[index[index % 3 == 0]]
必要な追加は済んだので、最後の部分を書き換えた。
# 学習ループ

for i in range(10000):
x = Variable(xtrain)
y = Variable(ytrain)
model.zerograds()
loss = model(x,y)		# lossを求める (forward)
loss.backward()		# 微分(backward)
optimizer.update()		# 調整
if i % 1000 == 0:
print("%6d   %6.4f   %6.4f" % (i,check(xtrain,trans,model),check(xtest,yans,model)))

print("%6d   %6.4f   %6.4f" % (i,check(xtrain,trans,model),check(xtest,yans,model)))

forループの制御変数iを、forループを抜けてからも使っている。
C言語ならエラーになるところだが、Pythonではそんなことはないのだ。

これで、こんな感じに動いた。
Chainer$ python3 digits0ck.py
0   0.0751   0.0634
1000   0.5601   0.5309
2000   0.6820   0.6477
3000   0.7821   0.7379
4000   0.8297   0.7863
5000   0.8706   0.8280
6000   0.8890   0.8715
7000   0.9040   0.8765
8000   0.9124   0.8865
9000   0.9249   0.8948
9999   0.9316   0.9032
Chainer$

数字は、「繰り返し回数、教師データでの正解率、テストデータでの正解率」である。

まだまだ成功率上昇中なので、もっともっとループを繰り返してみた。

226000   0.9958   0.9666
227000   0.9958   0.9666
228000   0.9958   0.9699
229000   0.9958   0.9716

学習データでのテストは99.5%を超えて非常に高いが、テストデータでは 97%を超えるのがやっとであった。つまり、過学習状態になっているのが分かる。
これ以上学習させても、このモデルでは成績は微小な変動を繰り返すのみであった。