深層学習用ライブラリKerasを使って深層学習モデルを作成する

  • 前回同様、lfw_peopleデータの分類学習を行います
  • Kerasを使います
In [1]:
# sklearnから
# データセットfetch_lfw_people
# 学習データと検証用データ分割用モジュール
# 標準化/正規化モジュール
from sklearn.datasets        import fetch_lfw_people
from sklearn.model_selection import train_test_split
from sklearn.preprocessing   import StandardScaler, MinMaxScaler

# Kerasから
# モデル作成用モジュール
from keras       import models, optimizers,layers
from keras.utils import np_utils

from matplotlib import pyplot as plt
plt.tight_layout() # グラフを並べた場合にラベルが重ならないように

import numpy as np
np.set_printoptions(precision=3) # 表示桁数を少数点以下2桁にします
Using TensorFlow backend.
<Figure size 432x288 with 0 Axes>

分類結果の混同マトリックスを表示するための関数

In [ ]:
def _report_cfmatrix (test, testPred, names, fname=None) :
    # 混同行列用ライブラリ
    from sklearn.metrics  import classification_report,confusion_matrix,ConfusionMatrixDisplay
    from matplotlib import pyplot as plt
    
    print('\n [classification_report]\n', classification_report(test, testPred, target_names=names))
    print('\n [confusion_matrix]\n',      confusion_matrix(test, testPred))
    ConfusionMatrixDisplay(confusion_matrix=confusion_matrix(test, testPred), display_labels=lfw.target_names).plot(cmap='YlGn', values_format='d', xticks_rotation=90)
    if( fname != None) :
        plt.savefig('.\cmat_cnn.jpg') 

データの準備

データをロード

In [3]:
lfw = fetch_lfw_people(data_home='./scikit_learn_data/', min_faces_per_person=100, resize=0.5)
Downloading LFW metadata: https://ndownloader.figshare.com/files/5976012
Downloading LFW metadata: https://ndownloader.figshare.com/files/5976009
Downloading LFW metadata: https://ndownloader.figshare.com/files/5976006
Downloading LFW data (~200MB): https://ndownloader.figshare.com/files/5976015

学習用データと検証用データの分離

In [4]:
X = lfw.data
y = lfw.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=0)
v,h = lfw.images.shape[1:3] # 画像の垂直・水平サイズを保持する
n_train = X_train.shape[0]  # 学習データ数を保持する
n_test  = X_test.shape[0]   # 検証データ数を保持する
print('Image Size        [{0}, {1}]'.format(v,h))
print('num of train data [{0}]'.format(n_train))
print('num of test  data [{0}]'.format(n_test))
Image Size        [62, 47]
num of train data [855]
num of test  data [285]

標準化と正規化

In [ ]:
sc = StandardScaler()
sc.fit(X_train)
X_train_sc = sc.transform(X_train)
X_test_sc  = sc.transform(X_test)

ms = MinMaxScaler(feature_range=(0,1))
ms.fit(X_train_sc)
X_train_sc = ms.transform(X_train_sc)
X_test_sc  = ms.transform(X_test_sc)

X_train_sc = X_train_sc.reshape([n_train, v, h, 1])
X_test_sc  = X_test_sc.reshape([n_test, v, h, 1])

正解データをカテゴリ変数化する(One-Hot Encoding)

In [6]:
y_train_cat = np_utils.to_categorical(y_train,5)
y_test_cat  = np_utils.to_categorical(y_test,5)
print(y_train_cat.shape)
print(y_train_cat)
(855, 5)
[[0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]
 [1. 0. 0. 0. 0.]
 ...
 [1. 0. 0. 0. 0.]
 [1. 0. 0. 0. 0.]
 [0. 0. 0. 0. 1.]]

モデルの定義

In [ ]:
model = models.Sequential()
# 入力: サイズがvxhで1チャンネルをもつ画像 -> (v, h, 1) のテンソル
# それぞれのlayerで3x3の畳み込み処理を適用している
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(v, h, 1)))
model.add(layers.Conv2D(32, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D(pool_size=(2, 2)))
model.add(layers.Dropout(0.25))

model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D(pool_size=(2, 2)))
model.add(layers.Dropout(0.25))

model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(5, activation='softmax'))
In [8]:
model.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 60, 45, 32)        320       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 58, 43, 32)        9248      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 29, 21, 32)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 29, 21, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 27, 19, 64)        18496     
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 25, 17, 64)        36928     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 12, 8, 64)         0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 12, 8, 64)         0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 6144)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 256)               1573120   
_________________________________________________________________
dropout_3 (Dropout)          (None, 256)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 5)                 1285      
=================================================================
Total params: 1,639,397
Trainable params: 1,639,397
Non-trainable params: 0
_________________________________________________________________

モデルのコンパイル

  • 最適化関数 Adam
  • 損失関数 categorical_crossentropy
  • 評価指標 accuracy
In [ ]:
lr     = 0.001
beta_1 = 0.9
beta_2 = 0.999
decay  = 0.0
optimizers.Adam(lr=lr, beta_1=beta_1, beta_2=beta_2, epsilon=None, decay=decay, amsgrad=False)
model.compile(optimizer = 'Adam',
              loss      = 'categorical_crossentropy',
              metrics   = ['acc'])

学習させる

In [ ]:
n_epoc   = 200
hist = model.fit(X_train_sc, y_train_cat, epochs=n_epoc, validation_data=(X_test_sc, y_test_cat), verbose=0)

検証用データに対する予測結果をカテゴリ変数で確認

In [11]:
y_test_pred_cls = model.predict_classes(X_test_sc)
y_test_pred_cls
Out[11]:
array([0, 1, 2, 0, 2, 2, 2, 4, 2, 2, 1, 4, 2, 2, 2, 0, 2, 2, 2, 2, 2, 1,
       2, 1, 0, 2, 1, 4, 2, 2, 0, 3, 0, 2, 0, 2, 2, 2, 2, 4, 4, 2, 0, 2,
       3, 2, 4, 2, 2, 4, 3, 0, 0, 0, 2, 2, 0, 2, 4, 2, 0, 2, 2, 0, 2, 3,
       1, 2, 4, 2, 3, 3, 3, 2, 2, 2, 2, 3, 3, 1, 3, 2, 0, 0, 0, 3, 2, 1,
       1, 4, 4, 3, 4, 0, 2, 2, 2, 2, 4, 2, 2, 2, 1, 2, 0, 4, 2, 2, 2, 0,
       1, 0, 3, 0, 2, 0, 1, 2, 4, 2, 2, 2, 2, 2, 2, 2, 0, 2, 1, 2, 1, 0,
       1, 2, 1, 0, 0, 1, 0, 1, 4, 0, 2, 2, 4, 2, 2, 3, 2, 1, 2, 2, 2, 2,
       0, 0, 3, 2, 2, 0, 2, 2, 2, 2, 2, 3, 1, 0, 0, 2, 2, 2, 0, 2, 4, 2,
       4, 3, 3, 4, 3, 2, 0, 2, 0, 2, 2, 2, 2, 2, 2, 1, 2, 3, 1, 2, 1, 4,
       3, 2, 2, 1, 2, 2, 2, 0, 0, 0, 0, 0, 1, 0, 0, 3, 3, 2, 2, 0, 0, 2,
       4, 2, 4, 1, 0, 0, 0, 2, 2, 2, 2, 2, 1, 2, 3, 0, 2, 0, 0, 2, 0, 1,
       2, 1, 0, 4, 0, 2, 2, 1, 2, 1, 3, 4, 2, 2, 0, 2, 0, 4, 2, 2, 2, 3,
       4, 2, 2, 1, 2, 3, 2, 2, 0, 1, 1, 2, 4, 0, 3, 0, 3, 2, 0, 4, 2])
In [12]:
y_test_pred = model.predict(X_test_sc)
y_test_pred
Out[12]:
array([[1.000e+00, 4.359e-20, 1.655e-15, 3.263e-17, 7.902e-15],
       [8.795e-18, 1.000e+00, 3.130e-10, 8.550e-21, 7.749e-18],
       [1.513e-26, 1.315e-19, 1.000e+00, 4.231e-13, 1.601e-22],
       ...,
       [1.000e+00, 1.127e-15, 1.892e-15, 6.655e-15, 1.085e-14],
       [3.913e-05, 1.125e-09, 9.033e-04, 1.896e-04, 9.989e-01],
       [1.891e-18, 1.916e-14, 1.000e+00, 2.256e-15, 7.479e-19]],
      dtype=float32)

混同マトリックスで指標を確認

In [13]:
_report_cfmatrix (y_test, y_test_pred_cls, lfw.target_names, fname='.\cmat_cnn.jpg')
 [classification_report]
                    precision    recall  f1-score   support

     Colin Powell       0.95      0.95      0.95        61
  Donald Rumsfeld       0.91      0.86      0.89        36
    George W Bush       0.91      0.98      0.94       122
Gerhard Schroeder       0.83      0.77      0.80        31
       Tony Blair       0.93      0.77      0.84        35

         accuracy                           0.91       285
        macro avg       0.91      0.87      0.89       285
     weighted avg       0.91      0.91      0.91       285


 [confusion_matrix]
 [[ 58   0   1   1   1]
 [  0  31   3   1   1]
 [  1   1 120   0   0]
 [  1   2   4  24   0]
 [  1   0   4   3  27]]

epocに対する正解率の推移を表示

In [14]:
hist.history.keys() # ヒストリデータ
Out[14]:
dict_keys(['val_loss', 'val_acc', 'loss', 'acc'])
In [15]:
gr1 = plt.subplot(1, 2, 1)
gr1.plot(range(1, n_epoc+1), hist.history['acc'], label="training")
gr1.plot(range(1, n_epoc+1), hist.history['val_acc'], label="validation")
gr1.set_xlabel('Epochs')
gr1.set_ylabel('Accuracy')
gr1.legend()

gr2 = plt.subplot(1, 2, 2)
gr2.plot(range(1, n_epoc+1), hist.history['loss'], label="training")
gr2.plot(range(1, n_epoc+1), hist.history['val_loss'], label="validation")
gr2.set_xlabel('Epochs')
gr2.set_ylabel('loss')
gr2.legend()
plt.show()