前回『【Scikit-learn】Olivetti facesデータセットで深層ニューラルネットワーク(DNN)してみる 』これをやって、64×64の画像分類はDNNではまったく歯が立たないことがわかりました。それじゃあ、CNNならどうなるの?をやらないわけにはいきません。ということで、今回は【Scikit-learn】Olivetti facesデータセットこちらで、CNNをやってみようと思います。
データの確認とか準備とか
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use("ggplot")
from keras import models
from keras import layers
from keras.callbacks import EarlyStopping
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_olivetti_faces
faces=fetch_olivetti_faces()
前回と同じですね。
前回1人目(名前:0)の方を見たので、今回は2人目(名前:1)の方を見てみましょう。
fig=plt.figure(figsize=(30,15))
def ax(x):
return fig.add_subplot(2,5,x+1)
for i in range(10):
ax(i)
ax(i).matshow(faces.images[i+10])
plt.gray()
plt.tight_layout()
plt.show()
この方も、表情やら向きやらを微妙に変えておられます。
同じように、データを準備していきます。が、今回はCNNなので、faces.imagesこちらを使います。
x=faces.images
t_=faces.target
t_df=pd.get_dummies(t_)
t=t_df.values
x_train,x_test,t_train,t_test=train_test_split(x,t,test_size=0.3,stratify=t,random_state=0)
x_train,x_train_val,t_train,t_train_val=train_test_split(x_train,t_train,test_size=0.2,stratify=t_train,random_state=0)
print(x_train.shape,x_train_val.shape,x_test.shape)
print(t_train.shape,t_train_val.shape,t_test.shape)
(224, 64, 64) (56, 64, 64) (120, 64, 64)
(224, 40) (56, 40) (120, 40)
これでやっていきます。
CNNモデルの構築と学習
書き方は非常に簡単で、見た目はDNNとそんな変わらないですが、やることは一変します。
model=models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation="relu",input_shape=(64,64,1)))
model.add(layers.MaxPooling2D(2,2))
model.add(layers.Conv2D(64,(3,3),activation="relu"))
model.add(layers.Flatten())
model.add(layers.Dense(256, activation="relu"))
model.add(layers.Dense(40, activation="softmax"))
- 64×64×1(64×64、1色)のデータを入力
- 次に、3×3×1のカーネルを32枚をあて、reluを通して、62×62×32の特徴量マップをつくる
- 62×62×32これを、2×2でマックスプーリングして、31×31×32に変換
- 今度は、3×3×32のカーネルを64セット用意、各々先の31×31×32にあてて、reluを通して、
29×29×64の特徴量マップをつくる - 29×29×64=53,824次元のベクトル化、256個のニューロンと全結合、reluで出力
- 40個のニューロンに全結合、softmaxで各々の確立を出力
こんなことを書いたと理解しています。
以下は、DNNと同じように、
model.compile(optimizer="adam",
loss="categorical_crossentropy",
metrics=["accuracy"])
callbacks=[EarlyStopping(monitor="val_accuracy",patience=5)]
results=model.fit(x_train,
t_train,
epochs=100,
batch_size=20,
verbose=1,
callbacks=callbacks,
validation_data=(x_train_val,t_train_val))
こうして、学習です。
Epoch 16/100
loss: 0.0046 - accuracy: 1.0000 - val_loss: 0.1576 - val_accuracy: 0.9821
Epoch 17/100
loss: 0.0035 - accuracy: 1.0000 - val_loss: 0.1541 - val_accuracy: 0.9643
Epoch 18/100
loss: 0.0032 - accuracy: 1.0000 - val_loss: 0.1536 - val_accuracy: 0.9821
Epoch 19/100
loss: 0.0028 - accuracy: 1.0000 - val_loss: 0.1532 - val_accuracy: 0.9821
エポック19で止まって、ご覧の通りの正解率です。CNNすげえ。
print(model.evaluate(x_train,t_train))
print(model.evaluate(x_train_val,t_train_val))
print(model.evaluate(x_test,t_test))
loss: 0.0026 - accuracy: 1.0000
loss: 0.1532 - accuracy: 0.9821
loss: 0.3027 - accuracy: 0.9250
テストデータに対して、92.5%の正解率となり、
前回『【Scikit-learn】Olivetti facesデータセットで深層ニューラルネットワーク(DNN)してみる 』のlightGBMの結果を大幅に上回りました。