学習率を変えると精度はどうなる?Keras×CNNで画像分類の比較実験【MNIST】

2025年6月11日水曜日

Google Colab Keras Learning Rate Optimizer 画像分類 学習率

X f B! P L
アイキャッチ画像 学習率を変えると精度はどうなる?【画像分類で比較】

はじめに|Kerasで学習率の違いを比較してみよう

ディープラーニングにおいて学習率(Learning Rate)は、モデルの精度や訓練の安定性に大きく影響する重要なハイパーパラメータです。学習率が適切でないと、学習が遅すぎたり、逆に発散してモデルが不安定になることもあります。

本記事では、KerasMNIST(手書き数字データセット)を使い、異なる学習率(0.0001, 0.001, 0.01, 0.1)でモデルを訓練し、精度や損失の違いを比較しました。

特に初心者の方にもわかりやすいように、学習率がどのように影響するのかを表やグラフを交えて丁寧に解説しています。「Keras 学習率の調整方法」や「最適な学習率の見つけ方」に興味がある方は、ぜひ最後までご覧ください。

学習率とは?

学習率とは、ニューラルネットワークを訓練する際に、パラメータ(重み)をどの程度更新するかを決める係数です。

学習率が小さい場合 学習率が大きい場合
学習が遅くなる 学習は速いが不安定になりやすい
収束は安定しやすい 発散して精度が上がらないことがある
精度の向上がゆっくり 最適解に到達できないことがある

このように、学習率の設定はモデルの性能に直接関わる重要なポイントです。特にSGD(確率的勾配降下法)のような単純なオプティマイザでは、学習率の影響が顕著に現れるため、今回はあえてSGDを使用して比較実験を行いました。

実験の概要|Kerasで学習率ごとのモデル精度を比較

ここでは、学習率の違いがディープラーニングモデルの性能に与える影響を検証するため、KerasとMNISTデータセットを使って実験を行いました。

Kerasは使いやすさと柔軟性を兼ね備えた深層学習フレームワークであり、学習率の設定や変更が非常に簡単です。今回は、画像分類タスクを通じて、以下の条件でモデルを訓練しました。

  • 使用データセット:MNIST(0〜9の手書き数字画像、28×28ピクセル)
  • モデル構成:シンプルなCNN(Conv2D + MaxPooling + Dense)
  • オプティマイザ:SGD(確率的勾配降下法)
  • 比較する学習率:0.0001, 0.001, 0.01, 0.1

学習率はモデルの学習の「スピード」と「安定性」を左右するため、最適な値を見つけることが重要です。今回は、以下のような理由でSGDオプティマイザを採用しました。

  • SGDはもっとも基本的な最適化手法で、学習率の影響が明確に現れやすい
  • AdamやRMSpropなどの最適化手法は内部で学習率を自動調整するが、それでも初期学習率の設定が結果に影響する

この実験では、「学習率がモデルの性能(精度と損失)にどう影響するのか?」を初心者でも理解しやすく可視化していきます。

準備:MNISTデータセットの読み込みと前処理

実験では、手書き数字画像の分類タスクとして有名な「MNISTデータセット」を使用します。 MNISTには、0〜9の手書き数字画像(28×28ピクセル、モノクロ)が含まれており、ディープラーニングの学習実験に最適なデータセットです。

まず、Kerasからデータを読み込み、モデルが学習しやすいように前処理(正規化とチャンネル次元の追加)を行います。

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]

モデル定義|シンプルなCNN構造を採用

今回の分類タスクには、畳み込みニューラルネットワーク(CNN)を使用します。 構造はシンプルで、Conv2D → MaxPooling → Flatten → Dense の流れになっています。

このような基本的な構造でも、学習率の設定次第で性能が大きく変わることが分かる実験になっています。

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

学習率を変えてモデルを訓練|0.0001〜0.1の4種類で比較

いよいよ本実験の中心である、学習率(Learning Rate)ごとの比較訓練を行います。 使用する最適化手法(Optimizer)は、先述のとおり「SGD(確率的勾配降下法)」です。

学習率は以下の4種類で比較します:

  • 0.0001:非常に小さい
  • 0.001:一般的な値
  • 0.01:やや大きめ
  • 0.1:かなり大きい

それぞれの学習率に対して、同じモデルを10エポック学習させ、検証精度(val_accuracy)とテスト精度(test_accuracy)を記録します。

results = {}
histories = {}

for lr in [0.0001, 0.001, 0.01, 0.1]:
    print(f"Learning rate: {lr}")
    optimizer = keras.optimizers.SGD(learning_rate=lr)
    model.compile(optimizer=optimizer,
                  loss='sparse_categorical_crossentropy',
                  metrics=['accuracy'])
    histories[lr] = model.fit(x_train, y_train, epochs=10, validation_split=0.2)
    
    test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
    results[lr] = {
        "val_acc": histories[lr].history["val_accuracy"][-1],
        "test_acc": test_acc
    }

このようにして、学習率によるパフォーマンスの違いを数値として記録し、後ほどグラフで可視化していきます。

実際の訓練状況

Learning rate: 0.0001
Epoch 1/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9987 - loss: 0.0055 - val_accuracy: 0.9847 - val_loss: 0.0610
Epoch 2/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 9s 3ms/step - accuracy: 0.9989 - loss: 0.0049 - val_accuracy: 0.9851 - val_loss: 0.0605
Epoch 3/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9993 - loss: 0.0045 - val_accuracy: 0.9851 - val_loss: 0.0601
Epoch 4/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9993 - loss: 0.0044 - val_accuracy: 0.9851 - val_loss: 0.0597
Epoch 5/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9994 - loss: 0.0041 - val_accuracy: 0.9852 - val_loss: 0.0594
Epoch 6/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9992 - loss: 0.0042 - val_accuracy: 0.9852 - val_loss: 0.0591
Epoch 7/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 4s 3ms/step - accuracy: 0.9993 - loss: 0.0041 - val_accuracy: 0.9852 - val_loss: 0.0589
Epoch 8/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9996 - loss: 0.0038 - val_accuracy: 0.9854 - val_loss: 0.0587
Epoch 9/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9995 - loss: 0.0041 - val_accuracy: 0.9852 - val_loss: 0.0585
Epoch 10/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9996 - loss: 0.0037 - val_accuracy: 0.9852 - val_loss: 0.0583
Learning rate: 0.001
Epoch 1/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9993 - loss: 0.0037 - val_accuracy: 0.9855 - val_loss: 0.0572
Epoch 2/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9998 - loss: 0.0031 - val_accuracy: 0.9856 - val_loss: 0.0566
Epoch 3/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 10s 3ms/step - accuracy: 0.9998 - loss: 0.0029 - val_accuracy: 0.9855 - val_loss: 0.0562
Epoch 4/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9997 - loss: 0.0028 - val_accuracy: 0.9852 - val_loss: 0.0558
Epoch 5/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9998 - loss: 0.0027 - val_accuracy: 0.9852 - val_loss: 0.0556
Epoch 6/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9998 - loss: 0.0024 - val_accuracy: 0.9852 - val_loss: 0.0554
Epoch 7/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 12s 5ms/step - accuracy: 0.9998 - loss: 0.0024 - val_accuracy: 0.9852 - val_loss: 0.0553
Epoch 8/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9998 - loss: 0.0024 - val_accuracy: 0.9853 - val_loss: 0.0552
Epoch 9/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9997 - loss: 0.0025 - val_accuracy: 0.9853 - val_loss: 0.0551
Epoch 10/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 4s 3ms/step - accuracy: 0.9998 - loss: 0.0025 - val_accuracy: 0.9856 - val_loss: 0.0550
Learning rate: 0.01
Epoch 1/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9999 - loss: 0.0022 - val_accuracy: 0.9862 - val_loss: 0.0549
Epoch 2/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9999 - loss: 0.0019 - val_accuracy: 0.9861 - val_loss: 0.0547
Epoch 3/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9998 - loss: 0.0018 - val_accuracy: 0.9866 - val_loss: 0.0549
Epoch 4/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9999 - loss: 0.0016 - val_accuracy: 0.9868 - val_loss: 0.0555
Epoch 5/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9999 - loss: 0.0016 - val_accuracy: 0.9867 - val_loss: 0.0559
Epoch 6/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 8s 5ms/step - accuracy: 0.9999 - loss: 0.0015 - val_accuracy: 0.9866 - val_loss: 0.0557
Epoch 7/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9999 - loss: 0.0015 - val_accuracy: 0.9862 - val_loss: 0.0559
Epoch 8/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 1.0000 - loss: 0.0014 - val_accuracy: 0.9862 - val_loss: 0.0562
Epoch 9/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 1.0000 - loss: 0.0014 - val_accuracy: 0.9864 - val_loss: 0.0566
Epoch 10/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 1.0000 - loss: 0.0013 - val_accuracy: 0.9863 - val_loss: 0.0567
Learning rate: 0.1
Epoch 1/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 8s 4ms/step - accuracy: 0.9998 - loss: 0.0018 - val_accuracy: 0.9849 - val_loss: 0.0633
Epoch 2/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 4s 3ms/step - accuracy: 0.9992 - loss: 0.0033 - val_accuracy: 0.9865 - val_loss: 0.0598
Epoch 3/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 4s 3ms/step - accuracy: 0.9999 - loss: 0.0013 - val_accuracy: 0.9843 - val_loss: 0.0708
Epoch 4/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 7s 4ms/step - accuracy: 0.9999 - loss: 0.0015 - val_accuracy: 0.9862 - val_loss: 0.0624
Epoch 5/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 12s 5ms/step - accuracy: 1.0000 - loss: 6.9728e-04 - val_accuracy: 0.9866 - val_loss: 0.0631
Epoch 6/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 1.0000 - loss: 5.1740e-04 - val_accuracy: 0.9861 - val_loss: 0.0636
Epoch 7/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 1.0000 - loss: 4.5181e-04 - val_accuracy: 0.9868 - val_loss: 0.0644
Epoch 8/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 9s 3ms/step - accuracy: 1.0000 - loss: 4.4254e-04 - val_accuracy: 0.9865 - val_loss: 0.0654
Epoch 9/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 3ms/step - accuracy: 1.0000 - loss: 3.8648e-04 - val_accuracy: 0.9864 - val_loss: 0.0656
Epoch 10/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 4s 3ms/step - accuracy: 1.0000 - loss: 3.3382e-04 - val_accuracy: 0.9865 - val_loss: 0.0668

学習結果の可視化:精度と損失

検証精度と損失の推移を可視化することで、学習率ごとの安定性や過学習傾向を確認します。以下に各グラフを表示します。

import matplotlib.pyplot as plt

for lr in [0.0001, 0.001, 0.01, 0.1]:
    print(f"{lr}: {results[lr]}")

for lr in [0.0001, 0.001, 0.01, 0.1]:
    plt.plot(histories[lr].history['val_accuracy'], label=f'{lr} val_accuracy')

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

for lr in [0.0001, 0.001, 0.01, 0.1]:
    plt.plot(histories[lr].history['val_loss'], label=f'{lr} val_loss')

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

最終評価結果

各学習率での最終的な検証精度(val_accuracy)とテスト精度(test_accuracy)は以下の通りです。

0.0001: {'val_acc': 0.9852499961853027, 'test_acc': 0.9868000149726868}
0.001: {'val_acc': 0.9855833053588867, 'test_acc': 0.9872999787330627}
0.01: {'val_acc': 0.9863333106040955, 'test_acc': 0.9872999787330627}
0.1: {'val_acc': 0.9865000247955322, 'test_acc': 0.9868999719619751}

精度グラフ

精度グラフ

損失グラフ

損失グラフ

結果を表で整理

学習率 Val Accuracy Val Loss 特徴と考察
0.0001 0.9852 0.0583 学習が非常に安定だが、改善の速度が遅い
0.001 0.9856 0.0550 最もバランスが良く、実用的な学習率
0.01 0.9863 0.0567 高精度だが損失に不安定な傾向あり
0.1 0.9865 0.0668 精度は出るが過学習の可能性が高い

学習率の違いによる影響の考察

  • 0.001:バランスが非常に良く、推奨される学習率
  • 0.01:精度は良いがval_lossの変動がやや大きい
  • 0.1:学習が速い反面、過学習しやすく安定性に欠ける
  • 0.0001:学習は安定するが、収束に時間がかかる

まとめ:適切な学習率の選定が鍵

学習率は、モデルの性能に直接影響を与える重要なハイパーパラメータです。本記事では、0.001が最も安定かつ高性能であることが確認できました。タスクやデータセットによって最適な学習率は異なるため、必ず複数の学習率で検証することが望まれます。

今後の応用

学習率は「固定値」ではなく、「学習率スケジューラ(Learning Rate Scheduler)」や「EarlyStopping」などと組み合わせることで、より洗練された学習が可能になります。

最後に

学習率を意識するだけで、モデルの性能を大きく改善することができます。ぜひ、あなたのプロジェクトでも試行錯誤しながら最適な学習率を見つけてみてください。


付録:Kerasのデフォルト学習率(learning rate)

Optimizer名 クラス名 デフォルトのlearning_rate 特徴
SGD tf.keras.optimizers.SGD 0.01 最も基本的な手法。学習率調整が重要。
Adam tf.keras.optimizers.Adam 0.001 自動調整あり。ほとんどのケースで高性能。
RMSprop tf.keras.optimizers.RMSprop 0.001 勾配の分散を利用して調整。RNN系でよく使われる。
Adagrad tf.keras.optimizers.Adagrad 0.001 学習率が段々小さくなる。疎なデータに強い。
Adadelta tf.keras.optimizers.Adadelta 1.0 学習率指定不要の工夫あり。
Nadam tf.keras.optimizers.Nadam 0.001 Adam + Nesterov Momentum。収束が速い。

このブログを検索

自己紹介

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

お問い合わせフォーム

名前

メール *

メッセージ *

プライバシーポリシー

QooQ