今更ながらDropoutを検証してみる
TL;DR;
dropoutで適切なパラメータを振ると学習が安定するよ。
val_accの最大値は更新しませんでした。
Dropoutの効果は本当にあるのか
今までいろんなモデル(つっても画像の異常判定とか、U-NET、オートエンコーダーくらいだけど)を組んできたが、
Dropoutがあんまり機能した記憶がないので、ホンマかいな、というのを試してみた。
みなさん大好きmnistで。
(というより誰でもいつでも使えるものになるとmnistに)
検証モデル
まずは下記投稿で最高結果を出したモデルで。
from keras import datasets import numpy as np ((train_x,train_y),(test_x,test_y)) = datasets.mnist.load_data() train_x = (train_x/255).astype("float32").reshape(-1,28,28,1) test_x = (test_x /255).astype("float32").reshape(-1,28,28,1) train_y = np.eye(10)[train_y] test_y = np.eye(10)[test_y] from tensorflow.keras.layers import * from tensorflow.keras.models import * from tensorflow.keras.optimizers import Adam from tensorflow.keras.callbacks import ModelCheckpoint from tensorflow.keras.losses import categorical_crossentropy prelu_model = Sequential() prelu_model.add(Conv2D(filters=32,kernel_size=(3,3),input_shape=(28,28,1),padding="same")) prelu_model.add(PReLU()) prelu_model.add(BatchNormalization()) prelu_model.add(Conv2D(filters=32,kernel_size=(3,3),padding="same")) prelu_model.add(MaxPool2D(pool_size=(2,2),padding="same")) # 28,28 -> 14,14 prelu_model.add(PReLU()) prelu_model.add(BatchNormalization()) prelu_model.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model.add(PReLU()) prelu_model.add(BatchNormalization()) prelu_model.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model.add(PReLU()) prelu_model.add(MaxPool2D(pool_size=(2,2),padding="same")) # 14,14 -> 7,7 prelu_model.add(BatchNormalization()) prelu_model.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model.add(PReLU()) prelu_model.add(BatchNormalization()) prelu_model.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model.add(PReLU()) prelu_model.add(MaxPool2D(pool_size=(2,2),padding="same")) # 7,7 -> 4,4 prelu_model.add(BatchNormalization()) prelu_model.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model.add(PReLU()) prelu_model.add(BatchNormalization()) prelu_model.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model.add(PReLU()) prelu_model.add(MaxPool2D(pool_size=(2,2),padding="same")) # 4,4 -> 2,2 prelu_model.add(BatchNormalization()) prelu_model.add(Conv2D(filters=128,kernel_size=(2,2),padding="same")) prelu_model.add(PReLU()) prelu_model.add(BatchNormalization()) prelu_model.add(Conv2D(filters=128,kernel_size=(2,2),padding="same")) prelu_model.add(PReLU()) prelu_model.add(MaxPool2D(pool_size=(2,2),padding="same")) # 2,2 -> 1,1 prelu_model.add(BatchNormalization()) prelu_model.add(Flatten()) prelu_model.add(Dense(10,activation="softmax")) prelu_model.summary() prelu_model.compile(optimizer=Adam(lr=0.0001),metrics=['accuracy'],loss="categorical_crossentropy") prelu_model_history = prelu_model.fit(train_x,train_y,batch_size=16,epochs=64,validation_data=(test_x,test_y))
このモデルに対して各アクティベーション層後にDropoutを設定する。
この記事によると、
それではDropoutを適用していこう。 まずは、Hinton氏の提案通り入力層は0.2、隠れ層は0.5にしておく。 TFLearnのdropout関数は1-dropout率を指定する。
ヒントン氏が入力層0.2,隠れ層は0.5と言っているので、それに習い、そのように設定。
ただ、なんとなく出力層直前は0.2にしてみました。
ヒントン氏に敗れた人はなんというか知りませんが…
prelu_model_drop05 = Sequential() prelu_model_drop05.add(Conv2D(filters=32,kernel_size=(3,3),input_shape=(28,28,1),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.2)) prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=32,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(Dropout(0.5)) prelu_model_drop05.add(MaxPool2D(pool_size=(2,2),padding="same")) # 28,28 -> 14,14 prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.5)) prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.5)) prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.5)) prelu_model_drop05.add(MaxPool2D(pool_size=(2,2),padding="same")) # 14,14 -> 7,7 prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.5)) prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.5)) prelu_model_drop05.add(MaxPool2D(pool_size=(2,2),padding="same")) # 7,7 -> 4,4 prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.5)) prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.5)) prelu_model_drop05.add(MaxPool2D(pool_size=(2,2),padding="same")) # 4,4 -> 2,2 prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=128,kernel_size=(2,2),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.5)) prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=128,kernel_size=(2,2),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.2)) prelu_model_drop05.add(MaxPool2D(pool_size=(2,2),padding="same")) # 2,2 -> 1,1 prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Flatten()) prelu_model_drop05.add(Dense(10,activation="softmax")) prelu_model_drop05.summary()
結果
Dropoutはポンコツでした。
Dropout無しが99.47%のval_accだったのに対し(あれ、99.5%超えてない)
Dropout有りが97.47%が限界でした。
検証2
たぶんDropoutの設計がイケてなかったのではないでしょうか…。
Dropoutレイヤが多すぎたか、パラメータの0.2,0.5が行けなかった気がします。
ヒントン氏を信じてパラメータはそのままに、 レイヤを減らしてみましょう。
で、作成したモデルがこちら。 (dropoutしてないヤツは変わらず)
prelu_model_drop05 = Sequential() prelu_model_drop05.add(Conv2D(filters=32,kernel_size=(3,3),input_shape=(28,28,1),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.2)) prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=32,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(Dropout(0.5)) prelu_model_drop05.add(MaxPool2D(pool_size=(2,2),padding="same")) # 28,28 -> 14,14 prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(BatchNormalization())<figure class="figure-image figure-image-fotolife" title="dropout減らし">[f:id:kazuhitogo:20190906102602p:plain]<figcaption>dropout減らし</figcaption></figure> prelu_model_drop05.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.5)) prelu_model_drop05.add(MaxPool2D(pool_size=(2,2),padding="same")) # 14,14 -> 7,7 prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.5)) prelu_model_drop05.add(MaxPool2D(pool_size=(2,2),padding="same")) # 7,7 -> 4,4 prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.5)) prelu_model_drop05.add(MaxPool2D(pool_size=(2,2),padding="same")) # 4,4 -> 2,2 prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Conv2D(filters=128,kernel_size=(2,2),padding="same")) prelu_model_drop05.add(PReLU()) prelu_model_drop05.add(Dropout(0.2)) prelu_model_drop05.add(MaxPool2D(pool_size=(2,2),padding="same")) # 2,2 -> 1,1 prelu_model_drop05.add(BatchNormalization()) prelu_model_drop05.add(Flatten()) prelu_model_drop05.add(Dense(10,activation="softmax")) prelu_model_drop05.summary()
結果2
うーん、いまいちすぎる。 が、dropout無し版がepoch 61にしてval_acc99.6%超えましたね。笑
検証3
ヒントン教授を疑うことにして、 dropoutを全て(0.2)で検証します。
prelu_model_drop02 = Sequential() prelu_model_drop02.add(Conv2D(filters=32,kernel_size=(3,3),input_shape=(28,28,1),padding="same")) prelu_model_drop02.add(PReLU()) prelu_model_drop02.add(Dropout(0.2)) prelu_model_drop02.add(BatchNormalization()) prelu_model_drop02.add(Conv2D(filters=32,kernel_size=(3,3),padding="same")) prelu_model_drop02.add(Dropout(0.2)) prelu_model_drop02.add(MaxPool2D(pool_size=(2,2),padding="same")) # 28,28 -> 14,14 prelu_model_drop02.add(PReLU()) prelu_model_drop02.add(BatchNormalization()) prelu_model_drop02.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop02.add(PReLU()) prelu_model_drop02.add(BatchNormalization()) prelu_model_drop02.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop02.add(PReLU()) prelu_model_drop02.add(Dropout(0.2)) prelu_model_drop02.add(MaxPool2D(pool_size=(2,2),padding="same")) # 14,14 -> 7,7 prelu_model_drop02.add(BatchNormalization()) prelu_model_drop02.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop02.add(PReLU()) prelu_model_drop02.add(BatchNormalization()) prelu_model_drop02.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop02.add(PReLU()) prelu_model_drop02.add(Dropout(0.2)) prelu_model_drop02.add(MaxPool2D(pool_size=(2,2),padding="same")) # 7,7 -> 4,4 prelu_model_drop02.add(BatchNormalization()) prelu_model_drop02.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop02.add(PReLU()) prelu_model_drop02.add(BatchNormalization()) prelu_model_drop02.add(Conv2D(filters=64,kernel_size=(3,3),padding="same")) prelu_model_drop02.add(PReLU()) prelu_model_drop02.add(Dropout(0.2)) prelu_model_drop02.add(MaxPool2D(pool_size=(2,2),padding="same")) # 4,4 -> 2,2 prelu_model_drop02.add(BatchNormalization()) prelu_model_drop02.add(PReLU()) prelu_model_drop02.add(BatchNormalization()) prelu_model_drop02.add(Conv2D(filters=128,kernel_size=(2,2),padding="same")) prelu_model_drop02.add(PReLU()) prelu_model_drop02.add(Dropout(0.2)) prelu_model_drop02.add(MaxPool2D(pool_size=(2,2),padding="same")) # 2,2 -> 1,1 prelu_model_drop02.add(BatchNormalization()) prelu_model_drop02.add(Flatten()) prelu_model_drop02.add(Dense(10,activation="softmax")) prelu_model_drop02.summary() prelu_model_drop02.compile(optimizer=Adam(lr=0.0001),metrics=['accuracy'],loss="categorical_crossentropy") prelu_model_drop02_history = prelu_model_drop05.fit(train_x,train_y,batch_size=16,epochs=64,validation_data=(test_x,test_y))
はてさて。
結果3
かなり改善されました。
最高のval_accこそ負けるものの(dropout0.2有り99.58%,無し99.6%) 学習がかなり安定しております。
もう少しまんべんなくdropoutしてパラメータが0.1とかだとさらなる改善が期待できそうです。
あとは学習率のスケジュールとかをすると更によいかもしれません。
今回はふざけた広告を笑
純愛ドロップアウト 【電子限定特典付き】 (バンブーコミックス 麗人uno!コミックス)
- 作者: 三坂ニウム
- 出版社/メーカー: 竹書房
- 発売日: 2019/07/19
- メディア: Kindle版
- この商品を含むブログを見る