Python
Keras

無から始めるKeras 第5回

More than 1 year has passed since last update.

無から始める Keras のもくじはこちら

今回から Keras のバージョンが 2.0.5 になったけど多分何も問題ないはず。

前回までのおさらい

前回までは Keras を使って 2 クラス分類をした。

MNIST

機械学習を触ったことがある人なら誰でも聞いたことがあるデータセット。
Modified National Institute of Standards and Technology database の略。

モノクロ画像に 0 から 9 の数字が書いてあって、画像からどの数字かを認識するのが目的。

28×28 pixel、8bit モノクロ。当然ラベル付き。
訓練データは 60000 個、テストデータは 10000 個。

公式サイトはここ。各手法によるエラーレートの記録も載っている。
これを見るとニューラルネットワークが別に特別すごいわけではないと感じるよな。

Keras にはデフォルトでこの MNIST が使えるようになっている。便利。

MNIST を認識してみる

とりあえず普通のネットワークで学習してみよう。

データの読み込み

Keras の MNIST データは、各ピクセルが 0 以上 255 以下の整数になっている。
これだと扱いにくいので、255.0 で割って 0 から 1 の間に収める。

また 2 次元データ(データ方向を含めれば 3 次元)になっているので、reshape によってそれぞれ 1 次元(データ方向を含めれば 2 次元)にしている。
reshape はデータの順番と総数をそのままに、配列の形だけ変える関数。

ラベルの方は 0 から 9 までの整数の配列になっているが、こちらもワンホットになるように変形する。
たとえば 7 であれば [0,0,0,0,0,0,0,1,0,0] になるようにする。
なお y_test はそれをする必要がないので省略。

mnist.load_data() をするときにデータをダウンロードするかもしれない。

from keras.datasets import mnist
from keras.utils import np_utils

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(60000, 784) / 255.0
x_test = x_test.reshape(10000, 784) / 255.0
y_train = np_utils.to_categorical(y_train, num_classes=10)

モデルの設定

ネットワークのモデルを作る。ここでは 784-1300-10 の 2 層ニューラルネットワークを作る。
層の数え方は色々な流派があるが、無 Keras では「前の層からのデータを受け取って何らかの処理(活性化関数をかけるなど)をする」ところまでを 1 層と数える。なので入力層は層と数えない。

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

model = Sequential([
    Dense(1300, input_dim=784, activation='relu'),
    Dropout(0.4),
    Dense(10, activation='softmax')
])
model.compile('adam', 'categorical_crossentropy', metrics=['accuracy'])

Dropout はドロップアウトレイヤー。
Keras では、1 つ前のレイヤー(今回であればノードが 1300 ある Dense レイヤー)のノードのうち、指定した割合(今回であれば 40%)のノードをランダムに選んで出力を 0 にする。
こうすることで過学習を防ぐ効果がある。

学習

from keras.callbacks import EarlyStopping

es = EarlyStopping(monitor='val_acc')
model.fit(x_train, y_train, batch_size=100, validation_split=0.2, callbacks=[es])

EarlyStopping

ここでは新しく EarlyStopping というものを用いる。
適当なところで学習を自動で止めて過学習を防止できる。

monitor には何を観測対象とするかを指定する。
val_acc(バリデーションの正確性)を選んでいるが、val_loss(バリデーションの損失)の方が一般的(?)。

バッチサイズ

上の fit の引数にある batch_size の値。

バッチサイズとは 1 回に計算するデータの数のこと。
全学習データ数と等しい、つまりこの例では 48000 個でも構わない(バリデーションで 20% が切られている)。
バッチサイズを小さくする、たとえば 100 個とかにすると、1 回の計算で 100 個しか扱わないので、全体でこの場合 480 回計算することになる。この 480 回の計算 1 まとまりのことをエポックと呼んでいる。またデータ数よりもバッチサイズがかなり小さい場合はミニバッチ(学習)と呼ぶ。
ちなみにバッチサイズが 1 のときは stochastic と呼んでいる(日本ではあまり馴染みのない言い方みたい)。

バッチサイズを小さくすることで、使用するメモリ量が少なくなる。
また 1 エポックあたりのパラメータ更新回数が増えるので、収束も速くなる。
ただし、バッチサイズを小さくしすぎるとパラメータが暴れてしまうという欠点がある。
したがって、バッチサイズはいい感じに選ぶ必要がある。

ちなみにバッチサイズを指定しないときは、全データの数になる。

テスト

predict = model.predict_classes(x_test)
print(sum(predict == y_test) / 10000.0)

98% くらいの正解率が出るはず。

predict_classes はクラス予測をするやつ。

今回のプログラムまとめ

ドロップアウト率やバッチサイズなどのパラメータもいじってみてね。

from keras.datasets import mnist
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense, Activation, Dropout
from keras.callbacks import EarlyStopping

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(60000, 784) / 255.0
x_test = x_test.reshape(10000, 784) / 255.0
y_train = np_utils.to_categorical(y_train, num_classes=10)

model = Sequential([
    Dense(1300, input_dim=784, activation='relu'),
    Dropout(0.4),
    Dense(10, activation='softmax')
])
model.compile('adam', 'categorical_crossentropy', metrics=['accuracy'])

es = EarlyStopping(monitor='val_acc')
model.fit(x_train, y_train, batch_size=100, validation_split=0.2, callbacks=[es])

predict = model.predict_classes(x_test)
print(sum(predict == y_test) / 10000.0)

本当は今回 CNN を扱って、上で示したものと性能比較をしようと思ったけれど、長くなってしまったので次回にすることにしました。次回こそやります。