【Keras】EarlyStopping 完全ガイド|patience の決め方・monitor の選び方・誤作動の原因まで解説

投稿日:2025年12月6日土曜日 最終更新日:

EarlyStopping Google Colab Keras

X f B! P L
アイキャッチ画像【Keras】EarlyStopping 完全ガイド|patience の決め方・monitor の選び方・誤作動の原因まで解説

EarlyStopping とは?

EarlyStopping(アーリーストッピング)は、検証指標(validation)に改善が見られなくなった時点で学習を自動的に停止する Keras のコールバックです。主な目的は以下の2点です。

まずは EarlyStopping の基本的な仕組みや使い方を確認したい方は、
【Keras】EarlyStoppingで過学習防止:精度低下の原因と対策 から読むと理解しやすいです。

  • 過学習(overfitting)の防止 — 訓練データに「覚えすぎ」ないようにする。
  • 計算コストの削減 — 無駄に多くの epoch を回さない。

仕組み:monitor / patience / restore_best_weights

monitor(監視指標)

`monitor` はどの指標の「改善」を見るかを指定します。よく使われる値は `val_loss`(検証損失)と `val_accuracy`(検証精度)です。 一般には `val_loss` を推奨します — 損失は勾配の微細な変化を反映するため、精度よりも早く改善の停滞を検出できるからです。

patience(猶予)

`patience` は「改善が見られなかった epoch をどれだけ許すか」を指定します。例えば `patience=3` の場合、3 エポック連続で改善がなければ学習を停止します。

restore_best_weights(最良重みの復元)

EarlyStopping が動作した時点のモデルは、最後の epoch(改善が止まった直後)の重みです。多くの場合、これは最良の状態ではありません。 `restore_best_weights=True` を指定すると、学習中に最も良かった epoch の重みに戻してから終了します。実運用ではほぼ必須です。 EarlyStoppingの停止点は最良重みからpatience分遅れているため。

【実装】Keras の EarlyStopping(基本コード)

最小コード例

from tensorflow.keras.callbacks import EarlyStopping

es = EarlyStopping(
    monitor='val_loss',
    patience=3,
    restore_best_weights=True
)

history = model.fit(
    x_train, y_train,
    validation_split=0.2,
    epochs=50,
    callbacks=[es],
    batch_size=32
)

実務でよく使う拡張例(ReduceLROnPlateau と併用)

from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau

es = EarlyStopping(monitor='val_loss', patience=7, restore_best_weights=True)
rlr = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3, min_lr=1e-6)

model.fit(
    x_train, y_train,
    validation_split=0.2,
    epochs=200,            	# patienceを長めに取るため、最大epoch数も大きく設定
    callbacks=[es, rlr],
    batch_size=64
)
TIP: 大きなデータセットでは epoch 数を多めにし、`patience` を長めに取る運用が安定しやすいです(後述の「patience の決め方」を参照)。

monitor の選び方(val_loss / val_accuracy / その他)

分類問題

基本的には val_loss を監視するのが安全です。val_accuracy は変動が大きく、改善判定にノイズが入ることがあります。

Keras 3 以降では、カスタム指標を model.compile() に渡すことで EarlyStopping の監視対象として使用しやすくなっています。

回帰問題

回帰は損失(MSE, MAE 等)を直接見るため、val_loss 一択です。

不均衡データ

クラス不均衡がある場合は、val_f1val_auc のような指標を自作コールバックで監視するのが有効です。 (Keras 標準では直接使えない指標もあるため、カスタムコールバックか、バリデーション時に別途計算してログする実装が必要です。)

patience の最適な決め方(データ量別)

patience はデータ量やノイズ量によって最適値が変わります。ノイズが多く、損失がガタつきやすい環境では、より長い猶予期間が必要です。以下は経験則です:

  • 小規模データセット(数千サンプル未満)patience=3~5
  • 中規模データセット(数千~数万)patience=5~10
  • 大規模データセット(数万~)patience=10~20

理由:大きいデータほど学習曲線の安定化に時間がかかるため、短すぎる patience は誤検知(早すぎる停止)につながります。

よくある失敗と対処法

① 早すぎる(すぐ止まる)

原因と対策:

  • 学習率が高すぎる → 学習率を下げる(例:1e-3 → 1e-4)
  • batch_size が小さい → バッチサイズを増やす(ノイズ低減)
  • patience が小さすぎる → patience を伸ばす(+2〜5)

② 止まらない(何十 epoch も続く)

原因と対策:

  • monitor が不適切(例:val_accuracy) → val_loss へ切替え
  • patience が大きすぎる → 妥当な値に縮小
  • データに極端なノイズがある → データクリーニングを行う

③ val_loss がガタガタで安定しない

原因と対策:

  • validation_split が小さすぎる → validation を増やす(または k-fold 検証)
  • モデルが複雑すぎる → 正則化や Dropout を導入
  • データ正規化が不十分 → 前処理をチェック
注意:EarlyStopping は万能ではありません。適切な monitor / patience / データ前処理が揃って初めて有効に働きます。

ReduceLROnPlateau との違い・併用例

ReduceLROnPlateau は「改善が止まったときに学習率を下げて様子を見る」ための仕組みです。 そのため EarlyStopping よりも一段階前に動作する “安全装置” として考えると理解しやすいです。

役割の違いはシンプルです。EarlyStopping は学習を止めるReduceLROnPlateau は学習率を下げて続行を試みる、という点です。 したがって、高精度化を目指す際は両方を併用するのがよく使われるパターンです(上のコード参照)。

併用のポイント

  • まず ReduceLROnPlateau で学習率を下げ、改善が出なければ EarlyStopping で止める(patience はやや長めに)。
  • ReduceLROnPlateau の patience を小さめ(例:2〜3)、EarlyStopping をやや大きめ(例:5〜8)に設定すると相性が良い。

【参考】EarlyStopping が発動するログ例


import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.callbacks import EarlyStopping

# ====== Load dataset ======
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

# ====== Define model ======
model = keras.Sequential([
            layers.Input(shape=(28, 28)),
            layers.Flatten(),
            layers.Dense(128, activation='relu'),
            layers.Dropout(0.2),
            layers.Dense(10, activation='softmax')
])

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

es = EarlyStopping(
    monitor='val_loss',
    patience=3,
    restore_best_weights=True,
    verbose=1
)

history = model.fit(
    x_train, y_train,
    validation_split=0.2,
    epochs=50,
    callbacks=[es],
    batch_size=32,
    verbose=1
)

実行ログサンプル

Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11490434/11490434 ━━━━━━━━━━━━━━━━━━━━ 2s 0us/step
Epoch 1/50
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 15s 7ms/step - accuracy: 0.8398 - loss: 0.5378 - val_accuracy: 0.9553 - val_loss: 0.1566
Epoch 2/50
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 17s 7ms/step - accuracy: 0.9500 - loss: 0.1663 - val_accuracy: 0.9631 - val_loss: 0.1202
Epoch 3/50
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 20s 7ms/step - accuracy: 0.9635 - loss: 0.1216 - val_accuracy: 0.9701 - val_loss: 0.1050
Epoch 4/50
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 13s 8ms/step - accuracy: 0.9700 - loss: 0.0940 - val_accuracy: 0.9737 - val_loss: 0.0904
Epoch 5/50
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 8s 5ms/step - accuracy: 0.9745 - loss: 0.0811 - val_accuracy: 0.9729 - val_loss: 0.0900
Epoch 6/50
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 10s 7ms/step - accuracy: 0.9785 - loss: 0.0672 - val_accuracy: 0.9725 - val_loss: 0.0886
Epoch 7/50
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 11s 7ms/step - accuracy: 0.9797 - loss: 0.0615 - val_accuracy: 0.9767 - val_loss: 0.0830
Epoch 8/50
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 11s 7ms/step - accuracy: 0.9843 - loss: 0.0508 - val_accuracy: 0.9771 - val_loss: 0.0799
Epoch 9/50
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 10s 7ms/step - accuracy: 0.9858 - loss: 0.0452 - val_accuracy: 0.9783 - val_loss: 0.0802
Epoch 10/50
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 10s 7ms/step - accuracy: 0.9850 - loss: 0.0437 - val_accuracy: 0.9762 - val_loss: 0.0875
Epoch 11/50
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 10s 7ms/step - accuracy: 0.9873 - loss: 0.0388 - val_accuracy: 0.9762 - val_loss: 0.0958
Epoch 11: early stopping
Restoring model weights from the end of the best epoch: 8.

まとめ

  • EarlyStopping は過学習防止と計算コスト削減に有効なコールバック。
  • monitor は基本的に val_loss、patience はデータ量に応じて調整。
  • restore_best_weights=True はほぼ必須で、最良重みに復元して終了できる。
  • ReduceLROnPlateau と併用することで、より高い精度を狙える。
  • 学習が安定しない場合は、EarlyStopping だけでなく、データ前処理・モデルの簡略化・学習率調整も同時に見直すと改善しやすい。

参考:Keras 公式 - EarlyStopping

問題があればこの記事のコードをコピペして Colab で動かし、結果を貼ってください。最適な patience のとり方を一緒に調整します。