異なるOptimizer(SGD, Adam, RMSprop)の比較実験!

2025年6月8日日曜日

Google Colab Keras Optimizer 画像分類

X f B! P L
Keras Adam RMSprop SGD オプティマイザー比較
アイキャッチ画像 異なるOptimizer(SGD, Adam, RMSprop)の比較実験!

はじめに

ニューラルネットワークの学習で重要な役割を果たすのが「オプティマイザ(Optimizer)」です。
今回は、SGDAdamRMSpropの3種類を比較し、それぞれの性能や学習の挙動を見ていきます。

使用する環境

  • Google Colab(GPU推奨)
  • TensorFlow / Keras

準備:MNISTデータの読み込み

from tensorflow import keras
from tensorflow.keras import layers

# MNISTデータの読み込み
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()

# 正規化とチャンネル次元追加
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
x_train = x_train[..., None]
x_test = x_test[..., None]

モデル構築関数

def create_model(optimizer):
    model = keras.Sequential([
        layers.Input(shape=(28, 28, 1)),
        layers.Conv2D(32, 3, activation='relu'),
        layers.MaxPooling2D(),
        layers.Flatten(),
        layers.Dense(64, activation='relu'),
        layers.Dense(10, activation='softmax')
    ])

    model.compile(
        optimizer=optimizer,
        loss="sparse_categorical_crossentropy",
        metrics=["accuracy"]
    )
    return model

それぞれのOptimizerで学習

optimizers = {
    "SGD": keras.optimizers.SGD(),
    "Adam": keras.optimizers.Adam(),
    "RMSprop": keras.optimizers.RMSprop()
}

results = {}
histories = {}

for name, opt in optimizers.items():
    print(f"Training with {name}...")
    model = create_model(opt)
    histories[name] = model.fit(
        x_train, y_train,
        validation_split=0.2,
        epochs=5
    )
    test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
    results[name] = {
        "val_acc": histories[name].history["val_accuracy"][-1],
        "test_acc": test_acc
    }

学習結果

Training with SGD...
Epoch 1/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 7s 4ms/step - accuracy: 0.7468 - loss: 0.9370 - val_accuracy: 0.9219 - val_loss: 0.2655
Epoch 2/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9203 - loss: 0.2698 - val_accuracy: 0.9400 - val_loss: 0.2035
Epoch 3/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9397 - loss: 0.2011 - val_accuracy: 0.9490 - val_loss: 0.1741
Epoch 4/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9499 - loss: 0.1679 - val_accuracy: 0.9525 - val_loss: 0.1604
Epoch 5/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 4s 3ms/step - accuracy: 0.9568 - loss: 0.1424 - val_accuracy: 0.9572 - val_loss: 0.1406
Training with Adam...
Epoch 1/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 7s 3ms/step - accuracy: 0.8911 - loss: 0.3793 - val_accuracy: 0.9787 - val_loss: 0.0736
Epoch 2/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9814 - loss: 0.0628 - val_accuracy: 0.9821 - val_loss: 0.0569
Epoch 3/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9873 - loss: 0.0394 - val_accuracy: 0.9821 - val_loss: 0.0588
Epoch 4/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9917 - loss: 0.0259 - val_accuracy: 0.9846 - val_loss: 0.0544
Epoch 5/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9948 - loss: 0.0172 - val_accuracy: 0.9838 - val_loss: 0.0565
Training with RMSprop...
Epoch 1/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 3ms/step - accuracy: 0.8923 - loss: 0.3632 - val_accuracy: 0.9778 - val_loss: 0.0769
Epoch 2/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9789 - loss: 0.0682 - val_accuracy: 0.9824 - val_loss: 0.0612
Epoch 3/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9875 - loss: 0.0420 - val_accuracy: 0.9843 - val_loss: 0.0556
Epoch 4/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 4s 3ms/step - accuracy: 0.9914 - loss: 0.0289 - val_accuracy: 0.9862 - val_loss: 0.0533
Epoch 5/5
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9927 - loss: 0.0218 - val_accuracy: 0.9858 - val_loss: 0.0564

学習結果の確認

以下のコードで学習結果と精度と損失をグラフ化します

import matplotlib.pyplot as plt

for name, opt in optimizers.items():
    print(f"{name}: {results[name]}")

for name, history in histories.items():
    plt.plot(history.history['val_accuracy'], label=f'{name} val_accuracy')

plt.title('Validation Accuracy per Epoch')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.grid(True)
plt.show()

for name, history in histories.items():
    plt.plot(history.history['val_loss'], label=f'{name} val_loss')

plt.title('Validation Loss per Epoch')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.grid(True)
plt.show()

学習結果の確認

SGD: {'val_acc': 0.984416663646698, 'test_acc': 0.9605000019073486}
Adam: {'val_acc': 0.984416663646698, 'test_acc': 0.9846000075340271}
RMSprop: {'val_acc': 0.984416663646698, 'test_acc': 0.9858999848365784}

精度と損失のグラフ確認

精度グラフ

オプティマイザごとの精度グラフ

損失グラフ

オプティマイザごとの損失グラフ

結果比較サマリ

Optimizer 最終Epochの Accuracy 最終Epochの Val_Accuracy 特徴的な挙動
SGD 0.9568 0.9572 着実に収束。やや遅いが安定。
Adam 0.9948 0.9838 高速に収束。過学習傾向も。
RMSprop 0.9927 0.9858 バランスよく高精度。滑らかな学習。

各オプティマイザの詳細分析

◆ SGD(確率的勾配降下法)

  • 初期精度は低め(0.74)が、エポックごとに安定して向上。
  • 最終的に val_accuracy = 95.7% に到達。
  • 学習率に敏感だが、ロスが順調に下がり過学習は少ない。
  • 安定型で、長期訓練向け。

◆ Adam(適応的モーメンタム)

  • 初回から精度が非常に高く(0.89→0.98)急速に収束。
  • val_accuracy ≒ 98.3% と非常に高い。
  • ただし val_loss にやや揺れがあり、過学習傾向あり。
  • 学習初期で効果大、ハイパラ調整も少なめ。

◆ RMSprop(勾配平方平均調整)

  • Adamに近いが、学習曲線がやや滑らか。
  • val_accuracy ≒ 98.6% と最も良好。
  • やや安定性が高く、過学習にも強め。
  • 画像認識など汎用的におすすめ。

総合比較表

Optimizer 学習速度 汎化性能 安定性 コメント
SGD △ 遅め 安定・堅実。微調整に向く
Adam ◎ 非常に速い △ やや不安定 初期学習や高速トライに
RMSprop ◎ 速い 高性能・汎用向け

まとめ

実験の結果、Adamは高速な収束が得られ、RMSpropはその精度と安定性のバランスで優れていました。
一方で、SGDは時間はかかりますが過学習が少なく、チューニング次第では十分な性能を発揮します。

おすすめの記事

このブログを検索

自己紹介

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

お問い合わせフォーム

名前

メール *

メッセージ *

プライバシーポリシー

QooQ