Kerasの仕様に疑問を抱いたやつ

投稿に凄まじく間が空いたので実質初投稿です。
タイトルの通りでなんでこうなってるのか謎なところを見つけた。
ネットの闇に投げたら答えが返ってくるのかなと淡い期待を持って書いてみる。

発端

大学で機械学習の簡単な講義のようなものがあったときに、Jpyter下でTensorFlowを入れてKerasを使い機械学習をやってみようという話になった。

でもって教科書の通りにまずは線形分類やってみてPython楽だねってした後MNISTを単純なNNで学習させてみるというお決まりのパターンのものをやったのだが、お決まりっぽくないデータが出たりした。

内容

コードは以下の通り。ほぼ教科書通りだし余計な文があるとか以外は特に問題はないと思う。

import numpy as np
import keras.optimizers

from keras.models import Sequential
from keras.layers.core import Dense, Activation

import matplotlib.pyplot as plt
%matplotlib inline

from keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()

from keras.utils import np_utils

from keras.optimizers import Adam

x_train = x_train.reshape(60000, 784)  ## 学習データ
x_train = x_train.astype('float32')
x_train = x_train / 255
num_classes = 10
y_train = np_utils.to_categorical(y_train, num_classes)

x_test = x_test.reshape(10000, 784)   # テストデータ
x_test = x_test.astype('float32')
x_test = x_test / 255
y_test = np_utils.to_categorical(y_test, num_classes)

model = Sequential()
model.add(Dense(128, input_dim=784, activation='relu')) # 1層目
model.add(Dense(128, input_dim=128, activation='relu')) # 2層目
model.add(Dense(128, input_dim=128, activation='relu')) # 3層目
model.add(Dense(128, input_dim=128, activation='relu')) # 4層目
model.add(Dense(128, input_dim=128, activation='relu')) # 5層目
model.add(Dense(10, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer=Adam(), metrics=['accuracy'])

history = model.fit(x_train, y_train, epochs=10, batch_size=1000, verbose=1, validation_data=(x_test, y_test)) 
score = model.evaluate(x_test, y_test, verbose=0)

print('Test loss:', score[0])
print('Test accuracy:', score[1])

でもってこれを動かすと学習を行ってくれたりするのだが、結果はこんな感じになる。

f:id:kud_wata:20180616205547p:plain

だんだん学習されて行って*1正答率が上がるのはいいのだが、epoch1の結果を見ると妙なことに、トレーニングデータよりもテストデータの方が正答率が良くなっている。
たまたまか?と何度かパラメータを変えてみても初回やまだ最適化が済んでいないときはテストデータの方が良くなるようで……

妙な仕様

でもっていろいろ試したりしてたらKerasのhistoryは妙なところで正答率を計ってるっぽい。

ニューラルネットワークは学習データを順方向に流してから誤差を逆方向に伝播させて学習する仕組みになっているのは常識ではあるが、Kerasはこの時順方向に流した際の正答率を学習データに対する正答率として保存しているらしい。
この結果、学習データの一部はほぼ学習されていない素の状態の学習機を通ることになり見かけ上の正答率が落ちている、というのがこの謎の結果の理由のようだ。


しかしこの仕様、どんな理由があるのか。
計算量下げるにしても順方向なんて誤差みたいなものじゃないのかなぁ。

*1:これは1回目からだいぶ高いけど