こしあん
2018-11-14

KerasのModelCheckpointのsave_best_onlyは何を表すのか?


Pocket
LINEで送る
Delicious にシェア

11k{icon} {views}


Kerasには「モデルの精度が良くなったときだけ係数を保存する」のに便利なModelCheckpointというクラスがあります。ただこのsave_best_onlyがいまいち公式の解説だとピンとこないので調べてみました。

ModelCheckpointとは?

公式ドキュメントより

keras.callbacks.ModelCheckpoint(filepath, monitor=’val_loss’, verbose=0, save_best_only=False, save_weights_only=False, mode=’auto’, period=1)

各エポック終了後にモデルを保存します.

filepath、monitorとかはわかりやすいんでいいんですが、この「save_best_onlyって何?なんでしかもデフォルトでFalseになってるの?」というのが気になって仕方がありませんでした。この公式解説が紛らわしくて

save_best_only: save_best_only=Trueの場合,監視しているデータによって最新の最良モデルが上書きされません.

これを読むと、「じゃあsave_best_only=Falseなら、より精度なりが良くなったときにファイルを上書きしないでどんどん新しいファイルを作るの?」と思ってしまいます。自分は一時期そう思っていました。ただこれは勘違いです。

もしsave_best_only=False(デフォルト)で実行すると

試しにModelCheckpointの「save_best_only=False」で実行してみます。データはMNISTとします。

from keras.layers import Dense, Input, Flatten
from keras.models import Model
from keras.callbacks import ModelCheckpoint

from keras.datasets import mnist
from keras.utils import to_categorical

(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_train, X_test = X_train/255.0, X_test/255.0
y_train, y_test = to_categorical(y_train), to_categorical(y_test)

input = Input((28, 28))
x = Flatten()(input)
x = Dense(128, activation="relu")(x)
x = Dense(10, activation="softmax")(x)

model = Model(input, x)
model.compile("adam", "categorical_crossentropy", ["acc"])

cp = ModelCheckpoint("weights.hdf5", monitor="val_loss", verbose=1,
                     save_best_only=False, save_weights_only=True)
model.fit(X_train, y_train, batch_size=128, epochs=20, callbacks=[cp],
        validation_data=(X_test, y_test))

ここではverbose=1としてログに書き出すようにしています。結果は次のようになります。

Epoch 00011: saving model to weights.hdf5
Epoch 12/20
60000/60000 [==============================] - 3s 49us/step - loss: 0.0208 - acc: 0.9950 - val_loss: 0.0717 - val_acc: 0.9780

Epoch 00012: saving model to weights.hdf5
Epoch 13/20
60000/60000 [==============================] - 3s 49us/step - loss: 0.0178 - acc: 0.9956 - val_loss: 0.0748 - val_acc: 0.9781

Epoch 00013: saving model to weights.hdf5
Epoch 14/20
60000/60000 [==============================] - 3s 49us/step - loss: 0.0146 - acc: 0.9968 - val_loss: 0.0745 - val_acc: 0.979

ここのval_lossを注意深く見てください。val_lossが0.0717→0.0748→0.0745と上がっているにもかかわらず、モデルが上書きされていますよね?。これがsave_best_only=Falseの正体です。

つまり、「save_best_only=False」なら、モニターしている評価値(この場合はval_loss)悪くなったときに上書きしないということではなくて、periodの引数で指定したのエポックごとに必ず保存するという意味なのです。試しにperiod=2としてみましょう。

Epoch 17/20
60000/60000 [==============================] - 3s 49us/step - loss: 0.0101 - acc: 0.9981 - val_loss: 0.0806 - val_acc: 0.9768
Epoch 18/20
60000/60000 [==============================] - 3s 48us/step - loss: 0.0088 - acc: 0.9984 - val_loss: 0.0842 - val_acc: 0.9761

Epoch 00018: saving model to weights.hdf5
Epoch 19/20
60000/60000 [==============================] - 3s 48us/step - loss: 0.0070 - acc: 0.9990 - val_loss: 0.0790 - val_acc: 0.9795
Epoch 20/20
60000/60000 [==============================] - 3s 50us/step - loss: 0.0077 - acc: 0.9984 - val_loss: 0.0877 - val_acc: 0.9771

Epoch 00020: saving model to weights.hdf5

「save_best_only=False, period=2」なら、モニターしている評価値が上がろうが下がろうが、2エポックごとに自動的に保存しているというのが確認できました。

一番いい精度を頼みたい場合(save_best_only=Trueなら)

GANとかモデルが崩壊するおそれのあるケースでもない限り、かなりの場合で「一番いい精度(少ない損失)の係数だけ保存していればいい」と思います。その場合は、save_best_only=Trueにしましょう。これをすることで想定された挙動になります。

ModelCheckpointの設定を以下のように変えます。デフォルトでsave_best_only=Falseなので、設定変更は必須です。

cp = ModelCheckpoint("weights.hdf5", monitor="val_loss", verbose=1,
                     save_best_only=True, save_weights_only=True)
Epoch 13/20
60000/60000 [==============================] - 3s 50us/step - loss: 0.0189 - acc: 0.9954 - val_loss: 0.0675 - val_acc: 0.9798

Epoch 00013: val_loss improved from 0.06868 to 0.06753, saving model to weights.hdf5
Epoch 14/20
60000/60000 [==============================] - 3s 50us/step - loss: 0.0167 - acc: 0.9960 - val_loss: 0.0744 - val_acc: 0.9773

Epoch 00014: val_loss did not improve from 0.06753

このように悪化した場合は「val_loss did not improve from 0.06753」と表示され、改善したときだけ保存されます。おそらくこれが大多数の人がやりたかったことではないでしょうか。

ちなみにモニターする評価値には訓練損失(loss)や訓練精度(acc)を入れることもできます。試しに訓練精度を入れてみましょう。もし訓練損失でいいときは、「monitor=”loss”」でOKです。

cp = ModelCheckpoint("weights.hdf5", monitor="acc", verbose=1,
                     save_best_only=True, save_weights_only=True)
Epoch 1/20
60000/60000 [==============================] - 4s 66us/step - loss: 0.3603 - acc: 0.9002 - val_loss: 0.1877 - val_acc: 0.9450

Epoch 00001: acc improved from -inf to 0.90017, saving model to weights.hdf5

このようにOKですね。デフォルトで組み込みの損失関数や評価関数では、大小の変化で改善か悪化かを自動的に判断してくれるようです。自作の関数だと「mode」の引数で設定必須だと思います

まとめ

  • ModelCheckpointを使うとモデルの係数を自動的に保存してくれる
  • しかし、デフォルトでsave_best_only=Falseなので、改善しようが悪化しようがなんでもかんでも上書きしようとする。save_best_only=Trueへの変更を忘れずに
Pocket
LINEで送る
Delicious にシェア



Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内

技術書コーナー

北海道の駅巡りコーナー


Add a Comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です