KerasによるMNIST/cifar10の分類


※以下、個人的な勉強のためのレポートです。
※間違い多々あると存じますが、現在の理解レベルのスナップショットのようなものです。
※勉強のためWebサイトや書籍からとても参考になったものを引用させていただいております。
http://ai999.careers/rabbit/

jupyter notebookの補完機能
https://qiita.com/simonritchie/items/d7dccb798f0b9c8b1ec5

Kerasによる実装

# モデル作成
# 入力層784ノード、中間層512ノード、中間層512ノード、出力層10ノード
# 中間層の活性化関数はRelu、出力層はsoftmax関数
model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(784,)))
model.add(Dropout(0.2))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(10, activation='softmax'))
model.summary()

結果


Epoch 20/20
60000/60000 [==============================] - 21s 354us/step - loss: 0.0157 - acc: 0.9948 - val_loss: 0.0794 - val_acc: 0.9826A: 3s - loss: 0.0155 - acc: 0.994 - ETA: 3s - loss: 0.0153 - acc:
Test loss: 0.07941742087971507
Test accuracy: 0.9826

正解データの与え方を、one hotから変更する
sparse_categorical_crossentropyのときには、5,7,2…のような正解の与え方を、
categorical_crossentropyのときには、one-hot形式で与えないとエラーになってしまう。
⇒使用する正解データと、目的関数の対応が必要

eochs=5、Adamの学習率を0.1に変更
学習率を上げて、学習が早く終わるように意図したとしても、逆に学習がうまくいかなくなる事象を観測することができる。

Epoch 5/5
60000/60000 [==============================] - 21s 347us/step - loss: 14.5173 - acc: 0.0993 - val_loss: 14.4547 - val_acc: 0.10328s - loss: 14.6333 - acc: 0.09 - ETA: 37s - loss: 14.6397 - acc: 0 - ETA: 31s - loss: 14.6105 - acc: - ETA: 15s - loss: 14.4946 - acc: 0.10 - ETA: 15s - loss: 14.4971 - acc: 0.100 - ETA: 15s - loss: 14.4949 - ETA: 13s - loss: 14.4980 - acc: 0. - ETA: 12s - loss: 14.5007 - ac - ETA: 11s - loss: 1 - ETA: 5s - loss: 14.4968 - acc: - ETA: 3s - ETA: 2s - loss: 14.5141 - ETA: 1s - loss: 14.5139 - acc: 0.09 - ETA: 1s - los - ETA: 1s - loss: 14.5160 - ETA: 0s - loss: 14.5189
Test loss: 14.454709132385254
Test accuracy: 0.1032
⇒学習率は重要なパラメータ

CNNによる実装

#Kerasではconv2dとMaxPooling2Dが用意されているので、CNNを簡単に組みやすい
model = Sequential()
#Kernel_size:畳み込み層のフィルターサイズ。今回は3*3
#「32」は出力のチャネル数
#入力時1チャネルだったものが、32チャンネルになり、次に64チャネルになる
model.add(Conv2D(32, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
#一次元に直す
model.add(Flatten())
#全結合層で128時限にする
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.summary()

model.summary()の表示

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_3 (Conv2D)            (None, 26, 26, 32)        320       
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 24, 24, 64)        18496     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 12, 12, 64)        0         
_________________________________________________________________
dropout_3 (Dropout)          (None, 12, 12, 64)        0         
_________________________________________________________________
flatten_2 (Flatten)          (None, 9216)              0         
_________________________________________________________________
dense_3 (Dense)              (None, 128)               1179776   
_________________________________________________________________
dropout_4 (Dropout)          (None, 128)               0         
_________________________________________________________________
dense_4 (Dense)              (None, 10)                1290      
=================================================================
Total params: 1,199,882
Trainable params: 1,199,882
Non-trainable params: 0
_________________________________________________________________

⇒Kerasの利点として、入力サイズをきちんと決めていれば、自動でshapeを計算してくれる。

実行

このままだと非常に負荷が大きいので、データサイズおよび学習回数を小さくして実行

(x_train, d_train), (x_test, d_test) = load_mnist(normalize=True, one_hot_label=True)
x_train = x_train[:1000]
d_train = d_train[:1000]
x_test = x_test[:1000]
d_test = d_test[:1000]

epochs = 3

結果


Epoch 20/20
1000/1000 [==============================] - 8s 8ms/step - loss: 0.0486 - acc: 0.9840 - val_loss: 0.2686 - val_acc: 0.9270

改造

padding = "same"
層を増やす
VGG16にする
⇒KerasにはapplicationsにVGG16が入っている
 ※他にも、ResNet/ResNet50なども入っている
 VGG16はサイズが48*48にしないと使えない
 3チャネル化しないといけない

cifar10

http://aidiary.hatenablog.com/entry/20151014/1444827123
一般物体認識のベンチマーク。
〇80 million tiny imagesのサブセット
〇全部で60000枚
〇画像サイズは32ピクセルx32ピクセル
〇RGBの3チャンネルカラー画像
〇クラスラベルはairplane, automobile, bird, cat, deer, dog, frog, horse, ship, truckで10クラス
〇50000枚(各クラス5000枚)の訓練画像と10000枚(各クラス1000枚)のテスト画像に分割されている
〇クラスラベルは排他的
〇PythonのcPickle形式で提供されている

データセットの確認

x_train.shape
(50000, 32, 32, 3)

⇒32*32*3チャネル

d_train
array([[0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 1.],
       [0., 0., 0., ..., 0., 0., 1.],
       ...,
       [0., 0., 0., ..., 0., 0., 1.],
       [0., 1., 0., ..., 0., 0., 0.],
       [0., 1., 0., ..., 0., 0., 0.]], dtype=float32)

⇒one_hot

一枚目の画像を確認

import matplotlib.pyplot as plt
plt.imshow(x_train[0])


⇒犬?

データの数値が0~255のRGBであるため、NNに処理させるための正規化を行う必要がある。
255で割ってやり、NNに処理させるため0~1のスケールにする必要がある。

実装

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_5 (Conv2D)            (None, 32, 32, 32)        896       
_________________________________________________________________
activation_7 (Activation)    (None, 32, 32, 32)        0         
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 30, 30, 32)        9248      
_________________________________________________________________
activation_8 (Activation)    (None, 30, 30, 32)        0         
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 15, 15, 32)        0         
_________________________________________________________________
dropout_4 (Dropout)          (None, 15, 15, 32)        0         
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 15, 15, 64)        18496     
_________________________________________________________________
activation_9 (Activation)    (None, 15, 15, 64)        0         
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 13, 13, 64)        36928     
_________________________________________________________________
activation_10 (Activation)   (None, 13, 13, 64)        0         
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 6, 6, 64)          0         
_________________________________________________________________
dropout_5 (Dropout)          (None, 6, 6, 64)          0         
_________________________________________________________________
flatten_2 (Flatten)          (None, 2304)              0         
_________________________________________________________________
dense_3 (Dense)              (None, 512)               1180160   
_________________________________________________________________
activation_11 (Activation)   (None, 512)               0         
_________________________________________________________________
dropout_6 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_4 (Dense)              (None, 10)                5130      
_________________________________________________________________
activation_12 (Activation)   (None, 10)                0         
=================================================================
Total params: 1,250,858
Trainable params: 1,250,858
Non-trainable params: 0
_________________________________________________________________

Epoch 20/20
1000/1000 [==============================] - 17s 17ms/step - loss: 0.5567 - acc: 0.8000
1000/1000 [==============================] - 4s 4ms/step
[2.088559553146362, 0.417]

# モデルの保存
model.saveしてあげることで、学習済みのモデルを後で使うことができる。
model.save('./CIFAR-10.h5')

# 保存したモデルの呼び出し

model.load_wights('./CIFAR-10.h5')
print(model.evaluate(x_test, d_test))
```

汎化性能が出ないときの対処

BachNormalizationの追加
⇒Kerasではこのような追加が用意にできる