はじめに:Optimizer(SGD・Adam・RMSprop)を比較する意義
ニューラルネットワークでモデル精度や収束速度に強く影響するのがオプティマイザ(Optimizer)です。 本記事では代表的な3種類、SGD・Adam・RMSpropをMNIST画像分類タスクで比較し、 「どのOptimizerがいつ、どう優れるか」を視覚化でわかりやすく解説します。 機械学習初心者から中級者まで、オプティマイザ選定に悩んでいる方に役立つ内容です。
使用環境と前提条件:Google Colab + TensorFlow/Kerasで実験
- 実行環境:Google Colab(GPU推奨)
- ライブラリ:TensorFlow / Keras(バージョン指定推奨)
Colabなら初期セットアップ不要で、すぐにGPUを使った深層学習実験を始められます。 本手順はすべてブラウザ上で再現可能です。
データ準備: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]
MNISTは機械学習入門で定番のデータセットです。ここでは読み込みから正規化、形状変換までを一括処理しています。
モデル定義:汎用CNNの構築関数(Optimizer を引数で切替可能)
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を引数として渡す設計にすることで、 後続の評価処理がシンプルで汎用的になります。
実験内容:SGD・Adam・RMSprop各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
}
各Optimizerを用いて学習し、最終の検証精度とテスト精度も合わせて記録します。 比較のための再現性が確保されています。
学習ログ:各Optimizerの収束速度と精度の推移(5エポック)
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
ログには各Epochごとの訓練精度、検証精度、損失の推移が表示されています。
SGD → 安定だが収束が緩やか
Adam → 初動が非常に速く精度向上が大きい
RMSprop → 高精度ながら滑らかな収束という傾向が見られました。
可視化:検証精度と損失のグラフで性能比較
以下のコードで学習結果と精度と損失をグラフ化します
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別パフォーマンスまとめ表
Optimizer | 最終EpochのVal Accuracy | Test Accuracy | 特性 |
---|---|---|---|
SGD | ~0.957 | ~0.960 | 安定だが収束緩やか |
Adam | ~0.984 | ~0.985 | 高速収束、やや揺れ |
RMSprop | ~0.986 | ~0.986 | 高精度、安定 |
各オプティマイザの詳細分析
◆ 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 | ◎ 速い | ◎ | ◯ | 高性能・汎用向け |
まとめ:タスクに応じたOptimizer選定のポイント
本実験ではAdamは収束速度重視、RMSpropは安定性と高精度、SGDは堅実性といった傾向が確認できました。 タスクによっては以下を意識すると効果的です:
- 高速初期収束を狙う→ Adam
- 安定した精度重視→ RMSprop
- 細かい調整・過学習対策→ SGD
今後は学習率スケジューラやEarlyStoppingとの併用もおすすめです。次回記事で詳しく解説予定です!
0 件のコメント:
コメントを投稿