はじめに
ニューラルネットワークの学習で重要な役割を果たすのが「オプティマイザ(Optimizer)」です。
今回は、SGD、Adam、RMSpropの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は時間はかかりますが過学習が少なく、チューニング次第では十分な性能を発揮します。
0 件のコメント:
コメントを投稿