MLP(多層パーセプトロン)のアルゴリズムを利用してMNISTの分類

# MLPでMNISTの分類問題に挑戦
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.optimizers import RMSprop
from keras.datasets import mnist
import matplotlib.pyplot as plt

# 入力と出力を指定
in_size = 28 * 28
out_size = 10

# MNISTのデータを読み込み --- (*1)
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# データを28*28=784の一次元配列に変換
X_train = X_train.reshape(-1, 784).astype('float32') / 255
X_test = X_test.reshape(-1, 784).astype('float32') / 255
# ラベルデータをone-hotベクトルに直す
y_train = keras.utils.to_categorical(y_train.astype('int32'),10)
y_test = keras.utils.to_categorical(y_test.astype('int32'),10)

# MLPモデル構造を定義 --- (*2)
model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(in_size,)))
model.add(Dropout(0.2))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(out_size, activation='softmax'))

# モデルをコンパイル --- (*3)
model.compile(
  loss='categorical_crossentropy',
  optimizer=RMSprop(),
  metrics=['accuracy'])

# 学習を実行 --- (*4)
hist = model.fit(X_train, y_train,
  batch_size=128,
  epochs=50,
  verbose=1,
  validation_data=(X_test, y_test))

# モデルを評価 --- (*5)
score = model.evaluate(X_test, y_test, verbose=1)
print('正解率=', score[1], 'loss=', score[0])

# 学習の様子をグラフへ描画 --- (*6)
# 正解率の推移をプロット
plt.plot(hist.history['accuracy'])
plt.plot(hist.history['val_accuracy'])
plt.title('Accuracy')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

# ロスの推移をプロット
plt.plot(hist.history['loss'])
plt.plot(hist.history['val_loss'])
plt.title('Loss')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

 

実行結果

f:id:hanamichi_sukusuku:20210206165239p:plain

f:id:hanamichi_sukusuku:20210206165302p:plain

f:id:hanamichi_sukusuku:20210206165328p:plain

MLPとは

MLPとは多層パーセプトロン(multilayer perceptron)のことで、特徴としては入力層からデータを入力した後、複数の隠れ層を経て出力層に出力される。これをkerasで表すと

model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(in_size,)))
model.add(Dropout(0.2))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(out_size, activation='softmax'))

 

model.add()メソッドを用いて、複数の隠れ層を追加していくことでMLPの特徴を反映している。

 

MNISTデータの読み込みと一次元の配列に変換

in_size = 28 * 28
out_size = 10

# MNISTのデータを読み込み --- (*1)
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# データを28*28=784の一次元配列に変換
X_train = X_train.reshape(-1, 784).astype('float32') / 255
X_test = X_test.reshape(-1, 784).astype('float32') / 255
# ラベルデータをone-hotベクトルに直す
y_train = keras.utils.to_categorical(y_train.astype('int32'),10)
y_test = keras.utils.to_categorical(y_test.astype('int32'),10)

 

 

モデルの構造を定義

model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(in_size,)))
model.add(Dropout(0.2))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(out_size, activation='softmax'))

 

 

今回ではmodel.add()でDropout()関数を使用していて、これはドロップアウト処理を加えるもの。ドロップアウトというのは入力値のうちいくらかをランダムに0にセットする機能。つまり、覚えたことを忘れることを意味するが、これにより過学習を防ぐことができる。そして、学習精度が上がる。Dropout(0.2)では20%の出力値がランダムに0に置き換わる。

 

モデルコンパイル

model.compile(
  loss='categorical_crossentropy',
  optimizer=RMSprop(),
  metrics=['accuracy'])

 

optimizer(最適化関数)にはRMSprop()を指定しているが、Dropout()関数を使用するときはこれを使った方がいいのかな?わからなかった。

 

学習の実行

hist = model.fit(X_train, y_train,
  batch_size=128,
  epochs=50,
  verbose=1,
  validation_data=(X_test, y_test))

 

 

model.fitのパラメーターにvalidation_dataという配列で評価データを与えるとmodel.fitの返り値のhistoryオブジェクトにepoch毎の訓練データでの評価とvalidation_dataでの評価とそれぞれの結果を残してくれる。

 

モデル評価

score = model.evaluate(X_test, y_test, verbose=1)
print('正解率=', score[1], 'loss=', score[0])

 

正解率の推移をプロット

plt.plot(hist.history['accuracy'])
plt.plot(hist.history['val_accuracy'])
plt.title('Accuracy')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

 

ロスの推移をプロット

plt.plot(hist.history['loss'])
plt.plot(hist.history['val_loss'])
plt.title('Loss')
plt.legend(['train', 'test'], loc='upper left')
plt.show()