先日、Kerasを使ったニューラルネットワークモデルでアヤメの分類をおこなう方法を紹介した。

さて、今回は同様の手順でニューラルネットワークモデルを構築し、scikit-learnで提供されている手書き文字データの分類をやってみる。

データセットの読み込み

アヤメの分類の時と同じように、まずはscikit-learnからデータを読み込む。

from sklearn import datasets

digits = datasets.load_digits()

x = digits.data
print(x.shape)

y = digits.target
print(y.shape)

# (1797, 64)
# (1797,)

正解データ(目的変数y)をOne-Hotに変換

説明変数xは全て色情報で構成されており単位に違いがないので、今回は正規化は不要だ。

目的変数yは0〜9の質的データなので、One-Hot形式へのエンコーディングが必要だ。

from keras.utils import np_utils

y = np_utils.to_categorical(y)
y[:5]
# array([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
#        [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
#        [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
#        [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
#        [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.]], dtype=float32)

訓練用データとテスト用データに分ける

データの前処理ができたら、次にxとyをそれぞれ訓練用データとテスト用データに分ける。

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=0)

ニューラルネットワークモデルの作成と学習

アヤメの分類に関する記事で詳細は触れたので、ここでの詳しい説明は割愛する。

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

model = Sequential()
model.add(Dense(16, input_shape=(64,)))
model.add(Activation('relu'))
model.add(Dense(10))
model.add(Activation('softmax'))

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(x_train, y_train, epochs=30, batch_size=1, verbose=1)

パラメータの調整は任意で良いが、今回はニューラルネットワークの隠れ層を16(5行目)とし、学習回数を30(11行目)とした。

なお、分類は0〜9までで行われるので、出力層は10となる(7行目)。

コードを実行すると、しばらくの間ログが流れ、学習が進んでいく。

Epoch 1/30
1347/1347 [==============================] - 1s 791us/step - loss: 2.3889 - accuracy: 0.3111
Epoch 2/30
1347/1347 [==============================] - 1s 627us/step - loss: 0.9609 - accuracy: 0.6526
Epoch 3/30
1347/1347 [==============================] - 1s 630us/step - loss: 0.4250 - accuracy: 0.8471
...
...
Epoch 28/30
1347/1347 [==============================] - 1s 635us/step - loss: 0.0198 - accuracy: 0.9963
Epoch 29/30
1347/1347 [==============================] - 1s 649us/step - loss: 0.0057 - accuracy: 0.9993
Epoch 30/30
1347/1347 [==============================] - 1s 651us/step - loss: 0.0207 - accuracy: 0.9926

loss値はかなりゼロに近づいた。

モデルの精度を評価

最後に、作成したモデルの精度を評価して終ろう。

loss, accuracy = model.evaluate(x_test, y_test, verbose=0)
print(accuracy)
# 0.9422222375869751

結果は94%を超えており、高い精度のモデルが完成した。

実際にこのモデル(分類器)にテストデータを入れてみよう。
今回はfor文を用いて全てのテストデータの予測結果を確認する。

loss_cnt = 0
size = len(x_test)

for i in range(size):
    m_predict = model.predict_classes(x_test[i:i+1], batch_size=1)

    if y_test[i][m_predict]:
        print('{}: 正解'.format(i))
    else:
        print('{}: 不正解'.format(i) + ' 予測:{0}, 正解:{1}'.format(m_predict, y_test[i]))
        loss_cnt+=1
    
print('正解率: {}'.format((size - loss_cnt) / size))

確認用のコードの内容はfor文やif文など、特に難しい内容ではないので理解するのは難しくないはずだ。

実行すると以下のとおり、1要素ごとに正解か不正解かが出力される。

0: 正解
1: 正解
2: 正解
...
43: 正解
44: 不正解 予測:[9], 正解:[0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
45: 正解
...
448: 正解
449: 正解
正解率: 0.9422222222222222

モデルの精度は100%とは言えないので、所々に不正解の予測が混じっている。

このあとは学習の際に設定したモデルのパラメータを調整しながら精度を検証し、微調整していく。