精度が下がった理由は“学習しすぎ”?KerasのEarlyStoppingで過学習を防止してみた

2025年5月29日木曜日

Google Colab Keras TensorFlow 画像分類 機械学習

X f B! P L
アイキャッチ画像 精度が下がった理由は“学習しすぎ”?KerasのEarlyStoppingで過学習を防止してみた

はじめに

こんにちは、SHOUです。

以前ご紹介した以下の記事:

5エポック→40エポック!学習回数でAIの精度はどこまで伸びる?【Keras転移学習で検証】では、学習回数を増やすことで精度が上がることを確認しました。

しかし、学習を続けすぎると、ある問題が発生することがあります。それが過学習(オーバーフィッティング)です。

過学習とは、訓練データにだけ極端に適合してしまい、未知のデータ(テストデータ)への汎用性が低下する現象です。AIが「覚えすぎてしまう」状態とも言えます。

今回は、Kerasで実装可能なEarlyStopping(早期終了)という手法を使って、この過学習をどのように防げるかを試してみます。

学習の準備

Google Driveのマウント

学習用のデータを読み込むために、Google Driveをマウントします。

  1. from google.colab import drive
  2. drive.mount('/content/drive')

ベースモデルの作成(MNISTで事前学習)

まずはKerasのMNISTデータセットで、シンプルなベースモデルを作成・学習します。

  1. import tensorflow as tf
  2. from tensorflow import keras
  3. (x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
  4. x_train = x_train / 255.0
  5. x_test = x_test / 255.0
  6. model = keras.Sequential([
  7. keras.Input(shape=(28, 28, 1)),
  8. keras.layers.Flatten(),
  9. keras.layers.Dense(128, activation='relu'),
  10. keras.layers.Dropout(0.2),
  11. keras.layers.Dense(10, activation='softmax')
  12. ])
  13. model.compile(optimizer='adam',
  14. loss='sparse_categorical_crossentropy',
  15. metrics=['accuracy'])
  16. # MNISTで事前学習
  17. model.fit(x_train, y_train, epochs=5)

Dropoutによる過学習対策について

ベースモデルの構築時に、以下のように Dropout(0.2) を設定しています:

  1. keras.layers.Dropout(0.2)

この Dropout(ドロップアウト) 層は、学習時にランダムに20%のニューロンを無効化(出力をゼロ)することで、特定のニューロンへの依存を減らし、 過学習を防ぐために用いられます。

モデルが訓練データに過度に適合してしまうと、未知のデータに対する性能が低下する(=過学習)傾向があります。 Dropoutを使うことで、学習中にモデルがさまざまな経路を通って情報を伝えるようになり、より汎化性能の高いモデルが構築されやすくなります。

今回の実験では、DropoutとEarlyStoppingを組み合わせることで、過学習の抑制効果をより強化しています。

EarlyStoppingを導入した転移学習

画像データの読み込みと前処理

次に、独自の手書き画像データ(digits)を使って転移学習を行います。ここでは白地に黒文字の画像を黒地に白文字に変換しています。

  1. from tensorflow.keras.preprocessing.image import ImageDataGenerator
  2. datagen = ImageDataGenerator(
  3. rescale=1./255,
  4. preprocessing_function=lambda x: 1.0 - x, # 白黒反転
  5. validation_split=0.2
  6. )
  7. train_generator = datagen.flow_from_directory(
  8. '/content/drive/MyDrive/Colab/digits',
  9. target_size=(28, 28),
  10. color_mode='grayscale',
  11. batch_size=32,
  12. class_mode='sparse',
  13. subset='training'
  14. )
  15. val_generator = datagen.flow_from_directory(
  16. '/content/drive/MyDrive/Colab/digits',
  17. target_size=(28, 28),
  18. color_mode='grayscale',
  19. batch_size=32,
  20. class_mode='sparse',
  21. subset='validation'
  22. )

EarlyStoppingの設定と学習

  1. from tensorflow.keras.callbacks import EarlyStopping
  2. # EarlyStopping のコールバックを定義
  3. early_stopping = EarlyStopping(
  4. monitor='val_loss', # モニター対象(val_loss または val_accuracy)
  5. patience=3, # 何エポック待つか(改善がなければ停止)
  6. restore_best_weights=True # 最良モデルの重みを復元
  7. )
  8. # モデルの学習
  9. history = model.fit(
  10. train_generator,
  11. epochs=40,
  12. validation_data=val_generator,
  13. callbacks=[early_stopping] # コールバックに渡す
  14. )

val_lossを監視対象にした理由は、損失の方が過学習の兆候を早く捉えられるケースがあるためです。 精度(accuracy)では過学習を見逃す可能性もあるため、通常はval_lossを使うのが一般的です。

学習結果

40回学習するところを19回で終了しています。

  1. /usr/local/lib/python3.11/dist-packages/keras/src/trainers/data_adapters/py_dataset_adapter.py:121: UserWarning: Your `PyDataset` class should call `super().__init__(**kwargs)` in its constructor. `**kwargs` can include `workers`, `use_multiprocessing`, `max_queue_size`. Do not pass these arguments to `fit()`, as they will be ignored.
  2. self._warn_if_super_not_called()
  3. Epoch 1/40
  4. 3/3 ━━━━━━━━━━━━━━━━━━━━ 13s 5s/step - accuracy: 0.1172 - loss: 59.9990 - val_accuracy: 0.2500 - val_loss: 27.6637
  5. Epoch 2/40
  6. 3/3 ━━━━━━━━━━━━━━━━━━━━ 8s 174ms/step - accuracy: 0.1823 - loss: 26.6123 - val_accuracy: 0.4000 - val_loss: 14.0175
  7. Epoch 3/40
  8. 3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 175ms/step - accuracy: 0.2646 - loss: 18.4386 - val_accuracy: 0.2000 - val_loss: 18.6816
  9. Epoch 4/40
  10. 3/3 ━━━━━━━━━━━━━━━━━━━━ 1s 146ms/step - accuracy: 0.2242 - loss: 19.3921 - val_accuracy: 0.4500 - val_loss: 12.4235
  11. Epoch 5/40
  12. 3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 148ms/step - accuracy: 0.4187 - loss: 9.3592 - val_accuracy: 0.3000 - val_loss: 12.3827
  13. ・・・
  14. Epoch 15/40
  15. 3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 144ms/step - accuracy: 0.6914 - loss: 0.7664 - val_accuracy: 0.6500 - val_loss: 1.1976
  16. Epoch 16/40
  17. 3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 174ms/step - accuracy: 0.7948 - loss: 0.4655 - val_accuracy: 0.6500 - val_loss: 1.1874
  18. Epoch 17/40
  19. 3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 145ms/step - accuracy: 0.7688 - loss: 0.4918 - val_accuracy: 0.5500 - val_loss: 1.2928
  20. Epoch 18/40
  21. 3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 142ms/step - accuracy: 0.9302 - loss: 0.3289 - val_accuracy: 0.5500 - val_loss: 1.5007
  22. Epoch 19/40
  23. 3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 199ms/step - accuracy: 0.9115 - loss: 0.3047 - val_accuracy: 0.5500 - val_loss: 1.4863

学習をプロット

  1. import matplotlib.pyplot as plt
  2. # 精度をプロット
  3. plt.plot(history.history['accuracy'])
  4. plt.title('Model Accuracy')
  5. plt.ylabel('Accuracy')
  6. plt.xlabel('Epoch')
  7. plt.show()
  8. # 損失をプロット
  9. plt.plot(history.history['loss'])
  10. plt.title('Model Loss')
  11. plt.ylabel('Loss')
  12. plt.xlabel('Epoch')
  13. plt.show()

精度のプロット

損失のプロット

予測

  1. from tensorflow.keras.preprocessing import image
  2. import numpy as np
  3. img_path = '/content/drive/MyDrive/Colab/handwritten_digit.png'
  4. img = image.load_img(img_path, target_size=(28, 28), color_mode='grayscale')
  5. img_array = image.img_to_array(img)
  6. img_array = np.expand_dims(img_array, axis=0) / 255.0
  7. img_array = 1.0 - img_array # ←★ 追加:白黒反転
  8. prediction = model.predict(img_array)
  9. print('予測ラベル:', np.argmax(prediction))

実行結果は以下です:

  1. 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 73ms/step
  2. 予測ラベル: 4

予測の結果、「4」と書かれた画像が「4」と認識されました。

今回のEarlyStoppingの導入により、必要以上に学習を続けず、汎用性のあるモデルを目指せた点は大きな成果です。

まとめ

  • 過学習とは、「覚えすぎ」によって新しいデータに弱くなる現象
  • EarlyStoppingを使うことで、過学習を防ぎ、より実用的なモデルが作れる
  • 誤認識の原因は、データの多様性や前処理の精度にも関係する

AIの精度を高めるには、モデル構造だけでなく「いつ学習を止めるか」も重要なポイントです。今後はEarlyStoppingだけでなく、Fine-tuningやデータ拡張なども組み合わせて、さらに高精度なモデル構築にチャレンジしてみます。


参考リンク:
Keras公式:EarlyStoppingコールバック

このブログを検索

自己紹介

はじめまして、機械学習を独学中のSHOU TAKEと申します。本ブログでは、Python・Keras・Google Colabを活用した画像分類やニューラルネットワークの実験記事を中心に発信しています。初学者の方にも分かりやすく、学んだことをそのまま実験形式でまとめるスタイルです。これまで取り組んだテーマには、学習率やOptimizerの比較、Batch Sizeの検証、事前学習の活用などがあります。ご質問やご感想は、お問い合わせフォームからお気軽にどうぞ。

お問い合わせフォーム

名前

メール *

メッセージ *

プライバシーポリシー

QooQ