【Keras】 CNNを用いたMNISTクラス分類

概要

KerasでCNNを構築してMNISTクラス分類を行っていきます

ライブラリインポート

import os 
import keras
from keras.models import Sequential
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.layers.core import Activation, Flatten, Dropout, Dense
from keras.datasets import mnist
from keras.optimizers import Adam
from keras.callbacks import TensorBoard
import matplotlib.pyplot as plt
import numpy as np

データセット処理

# ロードデータ
(X_train, y_train), (X_test, y_test) = mnist.load_data() 

# 正規化
X_train = X_train / 255
X_test = X_test / 255

# 画像のshapeを入力用に変換。(28, 28)=>(28, 28, 1) 
X_train = X_train.reshape(X_train.shape[0], 28, 28, 1)
X_test = X_test.reshape(X_test.shape[0], 28, 28, 1)

# ラベルをカテゴリデータにする
y_train_categorical = keras.utils.to_categorical(y_train)
y_test_categorical = keras.utils.to_categorical(y_test)

モデル構築

# ネットワーク定義
model = Sequential()
model.add(Conv2D(20, kernel_size=5, padding="same", input_shape=(28, 28, 1), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(50, kernel_size=5, padding="same",  activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(500, activation="relu",))
model.add(Dropout(0.25))
model.add(Dense(10))
model.add(Activation("softmax"))

model.compile(loss="categorical_crossentropy", optimizer=Adam(), metrics=["accuracy"])

model.summary()
### 出力
Model: "sequential_12"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_13 (Conv2D)           (None, 28, 28, 20)        520       
_________________________________________________________________
max_pooling2d_9 (MaxPooling2 (None, 14, 14, 20)        0         
_________________________________________________________________
dropout_4 (Dropout)          (None, 14, 14, 20)        0         
_________________________________________________________________
conv2d_14 (Conv2D)           (None, 14, 14, 50)        25050     
_________________________________________________________________
max_pooling2d_10 (MaxPooling (None, 7, 7, 50)          0         
_________________________________________________________________
dropout_5 (Dropout)          (None, 7, 7, 50)          0         
_________________________________________________________________
flatten_5 (Flatten)          (None, 2450)              0         
_________________________________________________________________
dense_5 (Dense)              (None, 500)               1225500   
_________________________________________________________________
dropout_6 (Dropout)          (None, 500)               0         
_________________________________________________________________
dense_6 (Dense)              (None, 10)                5010      
_________________________________________________________________
activation_3 (Activation)    (None, 10)                0         
=================================================================
Total params: 1,256,080
Trainable params: 1,256,080
Non-trainable params: 0
_________________________________________________________________

モデル学習

batch_size = 128
epochs = 15
validation_split = 0.2

model.fit(X_train, y_train_categorical, batch_size=batch_size, epochs=epochs, validation_split=validation_split, callbacks=[TensorBoard(log_dir="log")])
### 出力
Train on 48000 samples, validate on 12000 samples
Epoch 1/15
48000/48000 [==============================] - 50s 1ms/step - loss: 0.2431 - accuracy: 0.9225 - val_loss: 0.0604 - val_accuracy: 0.9821
Epoch 2/15
48000/48000 [==============================] - 48s 1ms/step - loss: 0.0696 - accuracy: 0.9785 - val_loss: 0.0441 - val_accuracy: 0.9864
Epoch 3/15
48000/48000 [==============================] - 48s 994us/step - loss: 0.0495 - accuracy: 0.9846 - val_loss: 0.0424 - val_accuracy: 0.9870
Epoch 4/15
48000/48000 [==============================] - 48s 990us/step - loss: 0.0416 - accuracy: 0.9866 - val_loss: 0.0317 - val_accuracy: 0.9914
Epoch 5/15
48000/48000 [==============================] - 48s 1ms/step - loss: 0.0342 - accuracy: 0.9888 - val_loss: 0.0280 - val_accuracy: 0.9921
Epoch 6/15
48000/48000 [==============================] - 48s 993us/step - loss: 0.0303 - accuracy: 0.9902 - val_loss: 0.0347 - val_accuracy: 0.9909
Epoch 7/15
48000/48000 [==============================] - 47s 988us/step - loss: 0.0268 - accuracy: 0.9908 - val_loss: 0.0283 - val_accuracy: 0.9912
Epoch 8/15
48000/48000 [==============================] - 48s 996us/step - loss: 0.0232 - accuracy: 0.9923 - val_loss: 0.0293 - val_accuracy: 0.9918
Epoch 9/15
48000/48000 [==============================] - 48s 990us/step - loss: 0.0212 - accuracy: 0.9925 - val_loss: 0.0299 - val_accuracy: 0.9921
Epoch 10/15
48000/48000 [==============================] - 47s 985us/step - loss: 0.0181 - accuracy: 0.9937 - val_loss: 0.0313 - val_accuracy: 0.9927
Epoch 11/15
48000/48000 [==============================] - 47s 989us/step - loss: 0.0184 - accuracy: 0.9936 - val_loss: 0.0321 - val_accuracy: 0.9912
Epoch 12/15
48000/48000 [==============================] - 47s 988us/step - loss: 0.0176 - accuracy: 0.9942 - val_loss: 0.0305 - val_accuracy: 0.9927
Epoch 13/15
48000/48000 [==============================] - 52s 1ms/step - loss: 0.0142 - accuracy: 0.9949 - val_loss: 0.0278 - val_accuracy: 0.9927
Epoch 14/15
48000/48000 [==============================] - 48s 997us/step - loss: 0.0139 - accuracy: 0.9954 - val_loss: 0.0281 - val_accuracy: 0.9927
Epoch 15/15
48000/48000 [==============================] - 47s 985us/step - loss: 0.0117 - accuracy: 0.9961 - val_loss: 0.0344 - val_accuracy: 0.9912

モデル評価

score = model.evaluate(X_test, y_test_categorical, verbose=0)

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

"""出力
loss: 0.029821792368289163
accuracy: 0.9916999936103821
"""
print(model.predict_classes(X_test[0].reshape(1, 28, 28, 1)))
# 7 (出力)

plt.imshow(X_test[0].reshape(28, 28))

keras-cnn

おまけ

テストデータで99%の精度を出していますが、じゃあ間違えてるやつは一体なんなのだろうか。。。

y_test_predict = model.predict_classes(X_test)

correct_array = y_test == y_test_predict
false_indexes = np.where(correct_array == False)[0]

for false_index in false_indexes:
    print("Miss Label", y_test_predict[false_index])
    print("Correct Label", y_test[false_index])
    plt.imshow(X_test[false_index].reshape(28, 28))
    plt.show()
    plt.clf()

keras-cnn

一部スクショしたもの。