EarlyStoppingは本当に効く?restore_best_weightsとpatienceを実験で比較【Keras×CIFAR-10】

投稿日:2026年4月19日日曜日 最終更新日:

callbacks CIFAR-10 CNN EarlyStopping Google Colab Keras 過学習

X f B! P L
アイキャッチ画像 EarlyStoppingは本当に効く?restore_best_weightsとpatienceを実験で比較【Keras×CIFAR-10】

KerasのEarlyStoppingは「過学習を自動で止めてくれる便利なcallback」として有名ですが、実際にどれくらい精度が変わるのか、数値で確認したことはありますか?

特に restore_best_weights=TrueFalse の差は「設定の説明」として目にすることが多いですが、実験で精度の差を見た記事はあまりありません。今回はGoogle ColabとCIFAR-10を使い、2つの観点から実験します。

  • 実験①: restore_best_weights=True vs False — 最良重みの復元は精度にどう影響するか
  • 実験②: patience=3 vs patience=10 vs EarlyStoppingなし — patienceの長さで何が変わるか

EarlyStoppingの基本的な仕組みや patience / monitor の選び方については既存記事をご参照ください。
【Keras】EarlyStopping の使い方|patience・monitor の設定と誤作動の原因

📘 この記事でわかること

  • restore_best_weights=True/Falseで精度がどれだけ変わるか
  • patienceを短くすると何が起きるか・長くすると何が変わるか
  • EarlyStoppingなしとの精度・エポック数の比較

実験①:restore_best_weights の効果を数値で確認

実験設定

EarlyStoppingを使い、restore_best_weights=TrueFalse の2パターンを比較します。それ以外の条件(patience・モデル構成・エポック数)は同一です。

restore_best_weights=True の場合、EarlyStopping発動時に「学習中で最もval_lossが低かったエポックの重み」に自動で戻ります。False の場合は停止直前(改善が止まった後)の重みがそのまま残ります。

実験コード

環境準備(最初に一度だけ実行)

# ── 環境準備(最初に一度だけ実行)──────────────────────
!apt-get -y install fonts-ipafont-gothic
!rm -rf /root/.cache/matplotlib
!pip install -q japanize_matplotlib
print("環境準備完了")
実行結果をクリックして内容を開く
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  fonts-ipafont-mincho
The following NEW packages will be installed:
  fonts-ipafont-gothic fonts-ipafont-mincho
0 upgraded, 2 newly installed, 0 to remove and 42 not upgraded.
Need to get 8,237 kB of archives.
After this operation, 28.7 MB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy/universe amd64 fonts-ipafont-gothic all 00303-21ubuntu1 [3,513 kB]
Get:2 http://archive.ubuntu.com/ubuntu jammy/universe amd64 fonts-ipafont-mincho all 00303-21ubuntu1 [4,724 kB]
Fetched 8,237 kB in 2s (3,968 kB/s)
Selecting previously unselected package fonts-ipafont-gothic.
(Reading database ... 122354 files and directories currently installed.)
Preparing to unpack .../fonts-ipafont-gothic_00303-21ubuntu1_all.deb ...
Unpacking fonts-ipafont-gothic (00303-21ubuntu1) ...
Selecting previously unselected package fonts-ipafont-mincho.
Preparing to unpack .../fonts-ipafont-mincho_00303-21ubuntu1_all.deb ...
Unpacking fonts-ipafont-mincho (00303-21ubuntu1) ...
Setting up fonts-ipafont-mincho (00303-21ubuntu1) ...
update-alternatives: using /usr/share/fonts/opentype/ipafont-mincho/ipam.ttf to provide /usr/share/fonts/truetype/fonts-japanese-mincho.ttf (fonts-japanese-mincho.ttf) in auto mode
Setting up fonts-ipafont-gothic (00303-21ubuntu1) ...
update-alternatives: using /usr/share/fonts/opentype/ipafont-gothic/ipag.ttf to provide /usr/share/fonts/truetype/fonts-japanese-gothic.ttf (fonts-japanese-gothic.ttf) in auto mode
Processing triggers for fontconfig (2.13.1-4.2ubuntu5) ...
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.1/4.1 MB 82.0 MB/s eta 0:00:00
  Preparing metadata (setup.py) ... done
  Building wheel for japanize_matplotlib (setup.py) ... done
環境準備完了

import・データ準備・モデル構築関数

import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import japanize_matplotlib
import time

# CIFAR-10データの読み込み・前処理
(x_train, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data()
x_train = x_train.astype('float32') / 255.0
x_test  = x_test.astype('float32')  / 255.0

# 共通モデル(全実験で同じ構成を使う)
def build_model(name):
    return keras.Sequential([
        keras.layers.Input(shape=(32, 32, 3)),
        keras.layers.Conv2D(64, (3, 3), activation='relu', padding='same'),
        keras.layers.MaxPooling2D((2, 2)),
        keras.layers.Conv2D(128, (3, 3), activation='relu', padding='same'),
        keras.layers.MaxPooling2D((2, 2)),
        keras.layers.GlobalAveragePooling2D(),
        keras.layers.Dense(128, activation='relu'),
        keras.layers.Dropout(0.2),
        keras.layers.Dense(10, activation='softmax'),
    ], name=name)

def compile_and_fit(model, callbacks=None, epochs=50):
    model.compile(
        optimizer='adam',
        loss='sparse_categorical_crossentropy',
        metrics=['accuracy']
    )
    start = time.time()
    history = model.fit(
        x_train, y_train,
        epochs=epochs,
        batch_size=64,
        validation_split=0.2,
        callbacks=callbacks,
        verbose=1
    )
    elapsed = time.time() - start
    return history, elapsed
実行結果をクリックして内容を開く
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170498071/170498071 ━━━━━━━━━━━━━━━━━━━━ 20s 0us/step

restore_best_weights 比較実験

from tensorflow.keras.callbacks import EarlyStopping

# Pattern A:restore_best_weights=True
print("\n=== Pattern A:restore_best_weights=True ===")
model_A = build_model('A_restore_true')
es_A = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True, verbose=1)
history_A, time_A = compile_and_fit(model_A, callbacks=[es_A], epochs=50)
score_A = model_A.evaluate(x_test, y_test, verbose=0)
print(f"停止エポック:{len(history_A.history['loss'])} test_accuracy:{score_A[1]:.4f}")

# Pattern B:restore_best_weights=False
print("\n=== Pattern B:restore_best_weights=False ===")
model_B = build_model('B_restore_false')
es_B = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=False, verbose=1)
history_B, time_B = compile_and_fit(model_B, callbacks=[es_B], epochs=50)
score_B = model_B.evaluate(x_test, y_test, verbose=0)
print(f"停止エポック:{len(history_B.history['loss'])} test_accuracy:{score_B[1]:.4f}")
実行結果をクリックして内容を開く
=== Pattern A:restore_best_weights=True ===
Epoch 1/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 13s 11ms/step - accuracy: 0.2558 - loss: 1.9466 - val_accuracy: 0.3541 - val_loss: 1.7310
Epoch 2/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 13s 6ms/step - accuracy: 0.3668 - loss: 1.6893 - val_accuracy: 0.4106 - val_loss: 1.5880
Epoch 3/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4212 - loss: 1.5711 - val_accuracy: 0.4459 - val_loss: 1.4930
Epoch 4/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4557 - loss: 1.4818 - val_accuracy: 0.4787 - val_loss: 1.4218
Epoch 5/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4825 - loss: 1.4173 - val_accuracy: 0.4982 - val_loss: 1.3770
Epoch 6/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5023 - loss: 1.3681 - val_accuracy: 0.4959 - val_loss: 1.3526
Epoch 7/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5152 - loss: 1.3229 - val_accuracy: 0.5330 - val_loss: 1.2808
Epoch 8/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5296 - loss: 1.2914 - val_accuracy: 0.5453 - val_loss: 1.2440
Epoch 9/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5377 - loss: 1.2632 - val_accuracy: 0.5448 - val_loss: 1.2746
Epoch 10/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5510 - loss: 1.2354 - val_accuracy: 0.5680 - val_loss: 1.1839
Epoch 11/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.5599 - loss: 1.2072 - val_accuracy: 0.5606 - val_loss: 1.2088
Epoch 12/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5701 - loss: 1.1851 - val_accuracy: 0.5607 - val_loss: 1.2009
Epoch 13/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5756 - loss: 1.1667 - val_accuracy: 0.5818 - val_loss: 1.1405
Epoch 14/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5840 - loss: 1.1454 - val_accuracy: 0.5889 - val_loss: 1.1373
Epoch 15/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5929 - loss: 1.1221 - val_accuracy: 0.5989 - val_loss: 1.1070
Epoch 16/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5991 - loss: 1.1033 - val_accuracy: 0.6007 - val_loss: 1.0922
Epoch 17/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6112 - loss: 1.0829 - val_accuracy: 0.6171 - val_loss: 1.0611
Epoch 18/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6162 - loss: 1.0670 - val_accuracy: 0.6217 - val_loss: 1.0423
Epoch 19/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6187 - loss: 1.0513 - val_accuracy: 0.6294 - val_loss: 1.0265
Epoch 20/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6266 - loss: 1.0338 - val_accuracy: 0.6289 - val_loss: 1.0322
Epoch 21/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6331 - loss: 1.0193 - val_accuracy: 0.6430 - val_loss: 0.9961
Epoch 22/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.6390 - loss: 1.0057 - val_accuracy: 0.6326 - val_loss: 1.0154
Epoch 23/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6467 - loss: 0.9872 - val_accuracy: 0.6425 - val_loss: 0.9945
Epoch 24/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6488 - loss: 0.9774 - val_accuracy: 0.6429 - val_loss: 0.9900
Epoch 25/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6555 - loss: 0.9609 - val_accuracy: 0.6311 - val_loss: 1.0125
Epoch 26/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6567 - loss: 0.9554 - val_accuracy: 0.6607 - val_loss: 0.9440
Epoch 27/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6622 - loss: 0.9416 - val_accuracy: 0.6616 - val_loss: 0.9423
Epoch 28/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6672 - loss: 0.9254 - val_accuracy: 0.6629 - val_loss: 0.9498
Epoch 29/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6696 - loss: 0.9226 - val_accuracy: 0.6631 - val_loss: 0.9368
Epoch 30/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6747 - loss: 0.9032 - val_accuracy: 0.6667 - val_loss: 0.9317
Epoch 31/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.6812 - loss: 0.8869 - val_accuracy: 0.6671 - val_loss: 0.9296
Epoch 32/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6829 - loss: 0.8900 - val_accuracy: 0.6709 - val_loss: 0.9245
Epoch 33/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6868 - loss: 0.8744 - val_accuracy: 0.6643 - val_loss: 0.9247
Epoch 34/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.6902 - loss: 0.8682 - val_accuracy: 0.6789 - val_loss: 0.8940
Epoch 35/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6954 - loss: 0.8523 - val_accuracy: 0.6839 - val_loss: 0.8833
Epoch 36/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6955 - loss: 0.8487 - val_accuracy: 0.6764 - val_loss: 0.8961
Epoch 37/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6998 - loss: 0.8375 - val_accuracy: 0.6866 - val_loss: 0.8785
Epoch 38/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7032 - loss: 0.8293 - val_accuracy: 0.6840 - val_loss: 0.8771
Epoch 39/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7063 - loss: 0.8201 - val_accuracy: 0.6849 - val_loss: 0.8846
Epoch 40/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7112 - loss: 0.8104 - val_accuracy: 0.6830 - val_loss: 0.8961
Epoch 41/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7117 - loss: 0.8082 - val_accuracy: 0.6815 - val_loss: 0.8920
Epoch 42/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7176 - loss: 0.7926 - val_accuracy: 0.6869 - val_loss: 0.8619
Epoch 43/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7200 - loss: 0.7860 - val_accuracy: 0.6986 - val_loss: 0.8515
Epoch 44/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7207 - loss: 0.7851 - val_accuracy: 0.6961 - val_loss: 0.8462
Epoch 45/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7232 - loss: 0.7743 - val_accuracy: 0.6914 - val_loss: 0.8621
Epoch 46/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7276 - loss: 0.7615 - val_accuracy: 0.7061 - val_loss: 0.8319
Epoch 47/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7261 - loss: 0.7664 - val_accuracy: 0.6857 - val_loss: 0.8897
Epoch 48/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7302 - loss: 0.7574 - val_accuracy: 0.6957 - val_loss: 0.8547
Epoch 49/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - accuracy: 0.7325 - loss: 0.7498 - val_accuracy: 0.7093 - val_loss: 0.8179
Epoch 50/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7345 - loss: 0.7411 - val_accuracy: 0.7106 - val_loss: 0.8287
Restoring model weights from the end of the best epoch: 49.
停止エポック:50 test_accuracy:0.7058

=== Pattern B:restore_best_weights=False ===
Epoch 1/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 8ms/step - accuracy: 0.2746 - loss: 1.9073 - val_accuracy: 0.3586 - val_loss: 1.7019
Epoch 2/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.3874 - loss: 1.6436 - val_accuracy: 0.4234 - val_loss: 1.5604
Epoch 3/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4437 - loss: 1.5118 - val_accuracy: 0.4683 - val_loss: 1.4729
Epoch 4/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4751 - loss: 1.4372 - val_accuracy: 0.4850 - val_loss: 1.4217
Epoch 5/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4940 - loss: 1.3830 - val_accuracy: 0.5237 - val_loss: 1.3183
Epoch 6/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5117 - loss: 1.3316 - val_accuracy: 0.5048 - val_loss: 1.3159
Epoch 7/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5281 - loss: 1.2932 - val_accuracy: 0.5461 - val_loss: 1.2515
Epoch 8/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5414 - loss: 1.2581 - val_accuracy: 0.5478 - val_loss: 1.2530
Epoch 9/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5584 - loss: 1.2216 - val_accuracy: 0.5663 - val_loss: 1.1858
Epoch 10/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5660 - loss: 1.1921 - val_accuracy: 0.5743 - val_loss: 1.1671
Epoch 11/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5774 - loss: 1.1663 - val_accuracy: 0.5761 - val_loss: 1.1601
Epoch 12/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5882 - loss: 1.1400 - val_accuracy: 0.5968 - val_loss: 1.1202
Epoch 13/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5943 - loss: 1.1221 - val_accuracy: 0.6068 - val_loss: 1.0891
Epoch 14/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6048 - loss: 1.0984 - val_accuracy: 0.6054 - val_loss: 1.0979
Epoch 15/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6126 - loss: 1.0828 - val_accuracy: 0.6242 - val_loss: 1.0507
Epoch 16/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6194 - loss: 1.0540 - val_accuracy: 0.6298 - val_loss: 1.0377
Epoch 17/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6268 - loss: 1.0398 - val_accuracy: 0.6308 - val_loss: 1.0193
Epoch 18/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6321 - loss: 1.0236 - val_accuracy: 0.6355 - val_loss: 1.0299
Epoch 19/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6389 - loss: 1.0064 - val_accuracy: 0.6327 - val_loss: 1.0135
Epoch 20/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6431 - loss: 0.9897 - val_accuracy: 0.6340 - val_loss: 1.0208
Epoch 21/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6485 - loss: 0.9778 - val_accuracy: 0.6502 - val_loss: 0.9811
Epoch 22/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6578 - loss: 0.9596 - val_accuracy: 0.6515 - val_loss: 0.9658
Epoch 23/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6611 - loss: 0.9493 - val_accuracy: 0.6654 - val_loss: 0.9360
Epoch 24/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6622 - loss: 0.9378 - val_accuracy: 0.6647 - val_loss: 0.9390
Epoch 25/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6683 - loss: 0.9235 - val_accuracy: 0.6477 - val_loss: 0.9954
Epoch 26/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6761 - loss: 0.9096 - val_accuracy: 0.6710 - val_loss: 0.9121
Epoch 27/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6798 - loss: 0.8982 - val_accuracy: 0.6813 - val_loss: 0.9028
Epoch 28/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6820 - loss: 0.8902 - val_accuracy: 0.6716 - val_loss: 0.9398
Epoch 29/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6870 - loss: 0.8775 - val_accuracy: 0.6781 - val_loss: 0.9000
Epoch 30/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6916 - loss: 0.8650 - val_accuracy: 0.6856 - val_loss: 0.8902
Epoch 31/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6966 - loss: 0.8534 - val_accuracy: 0.6857 - val_loss: 0.8852
Epoch 32/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6982 - loss: 0.8439 - val_accuracy: 0.6808 - val_loss: 0.9080
Epoch 33/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7043 - loss: 0.8297 - val_accuracy: 0.6952 - val_loss: 0.8634
Epoch 34/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7061 - loss: 0.8244 - val_accuracy: 0.6949 - val_loss: 0.8715
Epoch 35/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.7103 - loss: 0.8166 - val_accuracy: 0.6912 - val_loss: 0.8799
Epoch 36/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7126 - loss: 0.8068 - val_accuracy: 0.6897 - val_loss: 0.8708
Epoch 37/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7188 - loss: 0.7955 - val_accuracy: 0.7012 - val_loss: 0.8482
Epoch 38/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7208 - loss: 0.7873 - val_accuracy: 0.6867 - val_loss: 0.8926
Epoch 39/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7207 - loss: 0.7856 - val_accuracy: 0.6967 - val_loss: 0.8480
Epoch 40/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7255 - loss: 0.7705 - val_accuracy: 0.7094 - val_loss: 0.8197
Epoch 41/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7275 - loss: 0.7633 - val_accuracy: 0.7107 - val_loss: 0.8252
Epoch 42/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7312 - loss: 0.7523 - val_accuracy: 0.7069 - val_loss: 0.8353
Epoch 43/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7360 - loss: 0.7397 - val_accuracy: 0.7038 - val_loss: 0.8466
Epoch 44/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7355 - loss: 0.7409 - val_accuracy: 0.7149 - val_loss: 0.8031
Epoch 45/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7398 - loss: 0.7341 - val_accuracy: 0.7087 - val_loss: 0.8333
Epoch 46/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7419 - loss: 0.7290 - val_accuracy: 0.7074 - val_loss: 0.8234
Epoch 47/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7425 - loss: 0.7246 - val_accuracy: 0.7085 - val_loss: 0.8268
Epoch 48/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7479 - loss: 0.7131 - val_accuracy: 0.7085 - val_loss: 0.8178
Epoch 49/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7473 - loss: 0.7067 - val_accuracy: 0.7179 - val_loss: 0.8077
Epoch 49: early stopping
停止エポック:49 test_accuracy:0.7110

グラフ

fig, axes = plt.subplots(1, 2, figsize=(14, 5))
for label, h in [('A:restore=True', history_A), ('B:restore=False', history_B)]:
    axes[0].plot(h.history['val_accuracy'], label=label)
    axes[1].plot(h.history['val_loss'],     label=label)
axes[0].set_title('val_accuracy の比較')
axes[1].set_title('val_loss の比較')
for ax in axes:
    ax.set_xlabel('Epoch'); ax.legend(); ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('earlystopping_restore.png', dpi=150)
plt.show()

実験①の結果

精度グラフ

EarlyStopping 精度グラフ

損失グラフ

EarlyStopping 損失グラフ
パターン 停止エポック test_accuracy 備考
A:restore_best_weights=True 50 70.58% 最良重みに復元して終了
B:restore_best_weights=False 49 71.10% 停止直前の重みをそのまま使用

実験②:patienceの長さで何が変わるか

実験設定

restore_best_weights=True で固定し、patience=3 / patience=10 / EarlyStoppingなし(50エポック固定)の3パターンを比較します。

パターン patience 期待される挙動
C:patience=3 3 早めに停止。過学習前に止まるが、収束しきれない可能性あり
D:patience=10 10 ゆっくり停止。収束を待てるが、過学習が進む可能性も
E:EarlyStoppingなし 50エポック固定。過学習が進んだ状態で終了する可能性あり

patience 比較実験

# Pattern C:patience=3
print("\n=== Pattern C:patience=3 ===")
model_C = build_model('C_patience3')
es_C = EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True, verbose=1)
history_C, time_C = compile_and_fit(model_C, callbacks=[es_C], epochs=50)
score_C = model_C.evaluate(x_test, y_test, verbose=0)
print(f"停止エポック:{len(history_C.history['loss'])} test_accuracy:{score_C[1]:.4f}")

# Pattern D:patience=10
print("\n=== Pattern D:patience=10 ===")
model_D = build_model('D_patience10')
es_D = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True, verbose=1)
history_D, time_D = compile_and_fit(model_D, callbacks=[es_D], epochs=50)
score_D = model_D.evaluate(x_test, y_test, verbose=0)
print(f"停止エポック:{len(history_D.history['loss'])} test_accuracy:{score_D[1]:.4f}")

# Pattern E:EarlyStoppingなし(50エポック固定)
print("\n=== Pattern E:EarlyStoppingなし ===")
model_E = build_model('E_no_earlystop')
history_E, time_E = compile_and_fit(model_E, callbacks=None, epochs=50)
score_E = model_E.evaluate(x_test, y_test, verbose=0)
print(f"停止エポック:50(固定) test_accuracy:{score_E[1]:.4f}")
実行結果をクリックして内容を開く
=== Pattern C:patience=3 ===
Epoch 1/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 15s 16ms/step - accuracy: 0.2580 - loss: 1.9365 - val_accuracy: 0.3324 - val_loss: 1.7495
Epoch 2/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.3660 - loss: 1.6774 - val_accuracy: 0.3862 - val_loss: 1.6134
Epoch 3/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - accuracy: 0.4209 - loss: 1.5694 - val_accuracy: 0.4530 - val_loss: 1.4880
Epoch 4/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4584 - loss: 1.4740 - val_accuracy: 0.4702 - val_loss: 1.4439
Epoch 5/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4889 - loss: 1.3960 - val_accuracy: 0.5165 - val_loss: 1.3261
Epoch 6/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5082 - loss: 1.3482 - val_accuracy: 0.5160 - val_loss: 1.3168
Epoch 7/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 7ms/step - accuracy: 0.5217 - loss: 1.3079 - val_accuracy: 0.5413 - val_loss: 1.2499
Epoch 8/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.5346 - loss: 1.2690 - val_accuracy: 0.5506 - val_loss: 1.2341
Epoch 9/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 8ms/step - accuracy: 0.5441 - loss: 1.2466 - val_accuracy: 0.5482 - val_loss: 1.2327
Epoch 10/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 8ms/step - accuracy: 0.5572 - loss: 1.2146 - val_accuracy: 0.5660 - val_loss: 1.1807
Epoch 11/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5687 - loss: 1.1870 - val_accuracy: 0.5578 - val_loss: 1.1901
Epoch 12/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5732 - loss: 1.1707 - val_accuracy: 0.5732 - val_loss: 1.1609
Epoch 13/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5839 - loss: 1.1400 - val_accuracy: 0.5918 - val_loss: 1.1092
Epoch 14/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5939 - loss: 1.1186 - val_accuracy: 0.6033 - val_loss: 1.0832
Epoch 15/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5993 - loss: 1.1046 - val_accuracy: 0.5896 - val_loss: 1.1132
Epoch 16/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6108 - loss: 1.0852 - val_accuracy: 0.6009 - val_loss: 1.1045
Epoch 17/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6119 - loss: 1.0696 - val_accuracy: 0.6176 - val_loss: 1.0507
Epoch 18/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6194 - loss: 1.0550 - val_accuracy: 0.6192 - val_loss: 1.0454
Epoch 19/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6238 - loss: 1.0442 - val_accuracy: 0.6264 - val_loss: 1.0286
Epoch 20/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6317 - loss: 1.0214 - val_accuracy: 0.6296 - val_loss: 1.0140
Epoch 21/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6356 - loss: 1.0086 - val_accuracy: 0.6342 - val_loss: 1.0051
Epoch 22/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6405 - loss: 0.9976 - val_accuracy: 0.6388 - val_loss: 1.0067
Epoch 23/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6461 - loss: 0.9835 - val_accuracy: 0.6472 - val_loss: 0.9924
Epoch 24/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6508 - loss: 0.9693 - val_accuracy: 0.6538 - val_loss: 0.9564
Epoch 25/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6535 - loss: 0.9626 - val_accuracy: 0.6303 - val_loss: 1.0078
Epoch 26/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6598 - loss: 0.9453 - val_accuracy: 0.6599 - val_loss: 0.9458
Epoch 27/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6644 - loss: 0.9359 - val_accuracy: 0.6542 - val_loss: 0.9526
Epoch 28/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6679 - loss: 0.9240 - val_accuracy: 0.6656 - val_loss: 0.9320
Epoch 29/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6718 - loss: 0.9155 - val_accuracy: 0.6373 - val_loss: 0.9935
Epoch 30/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6755 - loss: 0.8995 - val_accuracy: 0.6697 - val_loss: 0.9220
Epoch 31/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6820 - loss: 0.8908 - val_accuracy: 0.6767 - val_loss: 0.9002
Epoch 32/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6837 - loss: 0.8830 - val_accuracy: 0.6763 - val_loss: 0.9075
Epoch 33/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6865 - loss: 0.8759 - val_accuracy: 0.6706 - val_loss: 0.9148
Epoch 34/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6926 - loss: 0.8609 - val_accuracy: 0.6790 - val_loss: 0.8949
Epoch 35/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6952 - loss: 0.8566 - val_accuracy: 0.6648 - val_loss: 0.9316
Epoch 36/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6996 - loss: 0.8456 - val_accuracy: 0.6773 - val_loss: 0.8962
Epoch 37/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6992 - loss: 0.8369 - val_accuracy: 0.6835 - val_loss: 0.8889
Epoch 38/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7052 - loss: 0.8210 - val_accuracy: 0.6829 - val_loss: 0.8901
Epoch 39/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7084 - loss: 0.8213 - val_accuracy: 0.6811 - val_loss: 0.8960
Epoch 40/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7103 - loss: 0.8120 - val_accuracy: 0.6749 - val_loss: 0.9063
Epoch 40: early stopping
Restoring model weights from the end of the best epoch: 37.
停止エポック:40 test_accuracy:0.6789

=== Pattern D:patience=10 ===
Epoch 1/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 8ms/step - accuracy: 0.2731 - loss: 1.8996 - val_accuracy: 0.3517 - val_loss: 1.7210
Epoch 2/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3721 - loss: 1.6749 - val_accuracy: 0.4040 - val_loss: 1.6279
Epoch 3/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4348 - loss: 1.5455 - val_accuracy: 0.4639 - val_loss: 1.4569
Epoch 4/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4711 - loss: 1.4481 - val_accuracy: 0.4785 - val_loss: 1.4087
Epoch 5/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4987 - loss: 1.3821 - val_accuracy: 0.5082 - val_loss: 1.3407
Epoch 6/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5131 - loss: 1.3327 - val_accuracy: 0.5272 - val_loss: 1.2870
Epoch 7/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5293 - loss: 1.2918 - val_accuracy: 0.5538 - val_loss: 1.2344
Epoch 8/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5412 - loss: 1.2610 - val_accuracy: 0.5572 - val_loss: 1.2171
Epoch 9/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5524 - loss: 1.2284 - val_accuracy: 0.5518 - val_loss: 1.2141
Epoch 10/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 7ms/step - accuracy: 0.5624 - loss: 1.2048 - val_accuracy: 0.5709 - val_loss: 1.1797
Epoch 11/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5742 - loss: 1.1740 - val_accuracy: 0.5763 - val_loss: 1.1706
Epoch 12/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5849 - loss: 1.1495 - val_accuracy: 0.5780 - val_loss: 1.1481
Epoch 13/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5932 - loss: 1.1246 - val_accuracy: 0.6051 - val_loss: 1.0896
Epoch 14/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.5993 - loss: 1.1053 - val_accuracy: 0.5996 - val_loss: 1.1032
Epoch 15/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6112 - loss: 1.0868 - val_accuracy: 0.6078 - val_loss: 1.0791
Epoch 16/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6176 - loss: 1.0642 - val_accuracy: 0.6232 - val_loss: 1.0388
Epoch 17/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6233 - loss: 1.0447 - val_accuracy: 0.6189 - val_loss: 1.0509
Epoch 18/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6329 - loss: 1.0235 - val_accuracy: 0.6282 - val_loss: 1.0350
Epoch 19/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6376 - loss: 1.0148 - val_accuracy: 0.6370 - val_loss: 1.0015
Epoch 20/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6397 - loss: 1.0001 - val_accuracy: 0.6353 - val_loss: 1.0138
Epoch 21/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6497 - loss: 0.9786 - val_accuracy: 0.6498 - val_loss: 0.9659
Epoch 22/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6507 - loss: 0.9708 - val_accuracy: 0.6354 - val_loss: 1.0086
Epoch 23/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6582 - loss: 0.9558 - val_accuracy: 0.6499 - val_loss: 0.9668
Epoch 24/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6640 - loss: 0.9383 - val_accuracy: 0.6444 - val_loss: 0.9913
Epoch 25/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6661 - loss: 0.9318 - val_accuracy: 0.6575 - val_loss: 0.9498
Epoch 26/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6707 - loss: 0.9149 - val_accuracy: 0.6590 - val_loss: 0.9416
Epoch 27/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6772 - loss: 0.9049 - val_accuracy: 0.6570 - val_loss: 0.9467
Epoch 28/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6794 - loss: 0.8923 - val_accuracy: 0.6758 - val_loss: 0.9033
Epoch 29/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6862 - loss: 0.8766 - val_accuracy: 0.6616 - val_loss: 0.9384
Epoch 30/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6839 - loss: 0.8754 - val_accuracy: 0.6621 - val_loss: 0.9298
Epoch 31/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6895 - loss: 0.8674 - val_accuracy: 0.6649 - val_loss: 0.9298
Epoch 32/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6947 - loss: 0.8541 - val_accuracy: 0.6748 - val_loss: 0.9158
Epoch 33/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6963 - loss: 0.8437 - val_accuracy: 0.6783 - val_loss: 0.8953
Epoch 34/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7006 - loss: 0.8318 - val_accuracy: 0.6840 - val_loss: 0.8759
Epoch 35/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7055 - loss: 0.8179 - val_accuracy: 0.6844 - val_loss: 0.8947
Epoch 36/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7080 - loss: 0.8136 - val_accuracy: 0.6889 - val_loss: 0.8759
Epoch 37/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7136 - loss: 0.7998 - val_accuracy: 0.6762 - val_loss: 0.9050
Epoch 38/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7137 - loss: 0.7984 - val_accuracy: 0.6932 - val_loss: 0.8604
Epoch 39/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7183 - loss: 0.7825 - val_accuracy: 0.7024 - val_loss: 0.8351
Epoch 40/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7207 - loss: 0.7804 - val_accuracy: 0.6944 - val_loss: 0.8610
Epoch 41/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7262 - loss: 0.7716 - val_accuracy: 0.7022 - val_loss: 0.8376
Epoch 42/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7268 - loss: 0.7649 - val_accuracy: 0.6970 - val_loss: 0.8482
Epoch 43/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7341 - loss: 0.7495 - val_accuracy: 0.7120 - val_loss: 0.8317
Epoch 44/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7310 - loss: 0.7515 - val_accuracy: 0.7084 - val_loss: 0.8247
Epoch 45/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7354 - loss: 0.7428 - val_accuracy: 0.6984 - val_loss: 0.8548
Epoch 46/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7382 - loss: 0.7332 - val_accuracy: 0.7017 - val_loss: 0.8489
Epoch 47/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7426 - loss: 0.7194 - val_accuracy: 0.7047 - val_loss: 0.8478
Epoch 48/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7451 - loss: 0.7149 - val_accuracy: 0.7084 - val_loss: 0.8333
Epoch 49/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7445 - loss: 0.7149 - val_accuracy: 0.7135 - val_loss: 0.8216
Epoch 50/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7501 - loss: 0.7008 - val_accuracy: 0.7183 - val_loss: 0.8167
Restoring model weights from the end of the best epoch: 50.
停止エポック:50 test_accuracy:0.7128

=== Pattern E:EarlyStoppingなし ===
Epoch 1/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 8ms/step - accuracy: 0.2720 - loss: 1.9188 - val_accuracy: 0.3502 - val_loss: 1.7200
Epoch 2/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.3819 - loss: 1.6538 - val_accuracy: 0.4302 - val_loss: 1.5504
Epoch 3/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4369 - loss: 1.5305 - val_accuracy: 0.4643 - val_loss: 1.4698
Epoch 4/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.4763 - loss: 1.4303 - val_accuracy: 0.4986 - val_loss: 1.3715
Epoch 5/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.4962 - loss: 1.3803 - val_accuracy: 0.5089 - val_loss: 1.3309
Epoch 6/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5133 - loss: 1.3317 - val_accuracy: 0.5273 - val_loss: 1.2994
Epoch 7/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5344 - loss: 1.2908 - val_accuracy: 0.5440 - val_loss: 1.2557
Epoch 8/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5429 - loss: 1.2543 - val_accuracy: 0.5404 - val_loss: 1.2816
Epoch 9/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5562 - loss: 1.2246 - val_accuracy: 0.5617 - val_loss: 1.2166
Epoch 10/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5661 - loss: 1.1972 - val_accuracy: 0.5731 - val_loss: 1.1748
Epoch 11/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5729 - loss: 1.1789 - val_accuracy: 0.5853 - val_loss: 1.1423
Epoch 12/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.5849 - loss: 1.1502 - val_accuracy: 0.5962 - val_loss: 1.1192
Epoch 13/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.5925 - loss: 1.1266 - val_accuracy: 0.5999 - val_loss: 1.0957
Epoch 14/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6010 - loss: 1.1033 - val_accuracy: 0.6146 - val_loss: 1.0690
Epoch 15/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6099 - loss: 1.0873 - val_accuracy: 0.6155 - val_loss: 1.0754
Epoch 16/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6162 - loss: 1.0671 - val_accuracy: 0.6159 - val_loss: 1.0598
Epoch 17/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.6217 - loss: 1.0524 - val_accuracy: 0.6162 - val_loss: 1.0527
Epoch 18/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6269 - loss: 1.0351 - val_accuracy: 0.6391 - val_loss: 1.0140
Epoch 19/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6371 - loss: 1.0161 - val_accuracy: 0.6321 - val_loss: 1.0237
Epoch 20/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6391 - loss: 1.0016 - val_accuracy: 0.6310 - val_loss: 1.0161
Epoch 21/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6449 - loss: 0.9890 - val_accuracy: 0.6405 - val_loss: 0.9980
Epoch 22/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6520 - loss: 0.9688 - val_accuracy: 0.6449 - val_loss: 0.9983
Epoch 23/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6557 - loss: 0.9610 - val_accuracy: 0.6526 - val_loss: 0.9651
Epoch 24/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6600 - loss: 0.9455 - val_accuracy: 0.6519 - val_loss: 0.9698
Epoch 25/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6661 - loss: 0.9360 - val_accuracy: 0.6542 - val_loss: 0.9699
Epoch 26/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6704 - loss: 0.9214 - val_accuracy: 0.6545 - val_loss: 0.9674
Epoch 27/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6730 - loss: 0.9119 - val_accuracy: 0.6584 - val_loss: 0.9447
Epoch 28/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6794 - loss: 0.8960 - val_accuracy: 0.6747 - val_loss: 0.9159
Epoch 29/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6829 - loss: 0.8820 - val_accuracy: 0.6756 - val_loss: 0.9056
Epoch 30/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6861 - loss: 0.8761 - val_accuracy: 0.6762 - val_loss: 0.9052
Epoch 31/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6921 - loss: 0.8643 - val_accuracy: 0.6744 - val_loss: 0.9200
Epoch 32/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6953 - loss: 0.8519 - val_accuracy: 0.6686 - val_loss: 0.9131
Epoch 33/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.6961 - loss: 0.8490 - val_accuracy: 0.6845 - val_loss: 0.8969
Epoch 34/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 7ms/step - accuracy: 0.7016 - loss: 0.8375 - val_accuracy: 0.6677 - val_loss: 0.9156
Epoch 35/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7027 - loss: 0.8283 - val_accuracy: 0.6871 - val_loss: 0.8746
Epoch 36/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7091 - loss: 0.8191 - val_accuracy: 0.6878 - val_loss: 0.8801
Epoch 37/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7099 - loss: 0.8087 - val_accuracy: 0.6852 - val_loss: 0.8855
Epoch 38/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.7119 - loss: 0.8001 - val_accuracy: 0.6982 - val_loss: 0.8490
Epoch 39/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7187 - loss: 0.7884 - val_accuracy: 0.7015 - val_loss: 0.8351
Epoch 40/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7187 - loss: 0.7850 - val_accuracy: 0.6946 - val_loss: 0.8468
Epoch 41/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7230 - loss: 0.7715 - val_accuracy: 0.6977 - val_loss: 0.8642
Epoch 42/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 6ms/step - accuracy: 0.7230 - loss: 0.7697 - val_accuracy: 0.7007 - val_loss: 0.8607
Epoch 43/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7288 - loss: 0.7577 - val_accuracy: 0.7116 - val_loss: 0.8205
Epoch 44/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7318 - loss: 0.7534 - val_accuracy: 0.7030 - val_loss: 0.8381
Epoch 45/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7335 - loss: 0.7438 - val_accuracy: 0.7063 - val_loss: 0.8321
Epoch 46/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7379 - loss: 0.7348 - val_accuracy: 0.7114 - val_loss: 0.8196
Epoch 47/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7411 - loss: 0.7266 - val_accuracy: 0.6988 - val_loss: 0.8499
Epoch 48/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7410 - loss: 0.7198 - val_accuracy: 0.7086 - val_loss: 0.8242
Epoch 49/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7449 - loss: 0.7148 - val_accuracy: 0.6982 - val_loss: 0.8621
Epoch 50/50
625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7482 - loss: 0.7063 - val_accuracy: 0.7062 - val_loss: 0.8403
停止エポック:50(固定) test_accuracy:0.7050

グラフ

histories2 = {
    'C:patience=3':       history_C,
    'D:patience=10':      history_D,
    'E:EarlyStoppingなし': history_E,
}

fig2, axes2 = plt.subplots(1, 2, figsize=(14, 5))
for label, h in histories2.items():
    axes2[0].plot(h.history['val_accuracy'], label=label)
    axes2[1].plot(h.history['val_loss'],     label=label)
axes2[0].set_title('val_accuracy の比較')
axes2[1].set_title('val_loss の比較')
for ax in axes2:
    ax.set_xlabel('Epoch'); ax.legend(); ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('earlystopping_patience.png', dpi=150)
plt.show()

# ── サマリー出力 ─────────────────────────────────
print("\n===== 実験②:最終結果サマリー =====")
results = [
    ('C:patience=3',       len(history_C.history['loss']), score_C[1], time_C),
    ('D:patience=10',      len(history_D.history['loss']), score_D[1], time_D),
    ('E:EarlyStoppingなし', 50,                            score_E[1], time_E),
]
print(f"{'Pattern':>24} | {'停止Ep':>6} | {'Test Acc':>9} | {'Time(s)':>8}")
print("-" * 58)
for name, ep, acc, t in results:
    print(f"{name:>24} | {ep:>6} | {acc:>9.4f} | {t:>8.1f}")

実験②の結果

精度グラフ

精度グラフ

損失グラフ

損失グラフ
パターン 停止エポック test_accuracy 学習時間
C:patience=3 40 67.89% 180.2秒
D:patience=10 50 71.28% 201.1秒
E:EarlyStoppingなし 50(固定) 70.50% 208.2秒

考察

① restore_best_weights の効果:予想外の逆転結果

実験①の結果は B(False)の71.10%がA(True)の70.58%を上回るという予想外の逆転になりました。「restore_best_weights=Trueの方が精度が高いはず」という直感とは逆です。

この結果の背景を考えます。AはEp50まで学習し、EarlyStoppingが発動した時点で「学習中に最もval_lossが低かったエポックの重み」に戻されています。一方BはEp49で停止し、その時点の重みをそのまま使っています。

実験②のログからわかるように、このモデルはval_lossが50エポック時点でもまだ緩やかに改善中です。そのため「最良エポック」がEp50に近い後半に来ており、Aで復元される重みとBの最終重みがほぼ同じエポックのものになっている可能性があります。差が0.52%と小さい点もこれを裏付けています。

この結果は「restore_best_weightsが不要」という意味ではありません。今回のモデルは50エポック時点で過学習しておらず、最良重みと最終重みの差が小さかったため差が出にくかっただけです。過学習が進むモデルでは効果が顕著に現れます。実際、実験②のDとEの比較(同条件で0.78%差)がその証拠です。

② EarlyStoppingが「早期停止」として機能しなかった理由

今回の実験では、3パターンとも50エポック付近まで走りました。EarlyStoppingが「早めに打ち切る」という期待通りには動かなかったことになります。

理由はモデルの収束速度にあります。今回のGAP+Dropout=0.2構成はval_lossが50エポック時点でもまだ緩やかに下降中でした。Dのログを見るとEp50でもval_lossが0.8167と最良値を更新し続けており、「改善が止まる」タイミング自体が50エポック以降に来るモデルです。つまりepochsの上限設定(50)が先に来てしまったという状況です。

EarlyStoppingを「早期停止」として活用するには、epochs=100〜200のように上限を十分大きく設定した上で使うのが本来の使い方です。今回の実験はその前提が揃っていませんでした。

③ patience=3 の早期停止は「誤検知」だったか

Cのログを見ると、Ep37でval_loss=0.8889の最良値を記録した後、Ep38・39・40と3エポック連続で改善がなかったため停止しています。これは正常な動作ですが、問題はEp37時点でモデルがまだ収束途中だったことです。

実際、DとEはそこから学習を続けてEp39〜50でval_lossをさらに0.82〜0.83台まで改善しています。patience=3は「短すぎてモデルの伸びしろを切り捨ててしまった」結果、test_accuracyがD比で約3.4%低くなりました。

④ D(patience=10)とE(EarlyStoppingなし)の差はrestore_best_weightsの効果

DとEは同じ50エポックを走りましたが、test_accuracyに差が出ました(D:71.28% vs E:70.50%)。

Dは restore_best_weights=True により、50エポック中の最良重み(Ep50のval_loss=0.8167)に自動で戻っています。一方EはEp50の最終重みをそのまま使用しており、val_loss=0.8403でDより悪い状態です。

同じエポック数でも restore_best_weights=True があるだけで約0.8%の精度差が生まれました。設定1つの違いがこれだけ影響することが数値で確認できます。

⑤ このモデルでEarlyStoppingを有効に使うには

今回の結果から、CIFAR-10+GAP+Dropout=0.2の構成でEarlyStoppingを本来の用途(無駄なエポックのカット)として使うには以下の設定が適切です。

early_stopping = EarlyStopping(
    monitor='val_loss',
    patience=10,               # ← 短すぎると収束前に止まる
    restore_best_weights=True, # ← 必須。精度に直接影響する
    verbose=1
)
 
history = model.fit(
    x_train, y_train,
    epochs=200,                # ← 上限を十分大きくする
    batch_size=64,
    validation_split=0.2,
    callbacks=[early_stopping]
)

epochsを200に増やせば、学習が本当に頭打ちになったタイミングで自動停止し、計算コストの削減効果が得られます。

まとめ

  • EarlyStoppingはepochsの上限を十分大きく設定して使うのが前提。上限が低すぎると早期停止として機能しない
  • patience=3 は収束途中で止まり、DよりもTest Accが約3.4%低くなった。このモデルでは短すぎる
  • restore_best_weights=True は同じ50エポックでもEなしと比べ約0.8%の精度差を生んだ。必ず設定すべき
  • GAP+Dropout=0.2構成ではval_lossの収束が遅いため、patience=10以上・epochs=100〜200が実用的な設定

関連記事もあわせてどうぞ: