Batch Sizeを変えると精度はどう変わる?画像分類で実験!

2025年6月17日火曜日

Google Colab Keras TensorFlow 画像分類

X f B! P L
アイキャッチ画像 Batch Sizeを変えると精度はどう変わる?画像分類で実験!

はじめに

ディープラーニングにおいて、Batch Size(バッチサイズ)は学習の効率や精度に大きく影響する重要なハイパーパラメータです。
しかし実際には「小さすぎると時間がかかる」「大きすぎると不安定になる」といったトレードオフがあり、最適な値を見極めるのは簡単ではありません。
本記事では、Keras を使ってバッチサイズを 16, 32, 64, 128 に変化させながら、MNIST 手書き数字分類タスクの精度・学習時間・損失の推移を比較し、その違いを図表とともに解説します。

実験環境とモデル構成

  • データセット:MNIST(手書き数字画像)
  • モデル:シンプルな CNN(Conv2D → MaxPool → Flatten → Dense)
  • Optimizer:Adam(学習率デフォルト)
  • エポック数:10
  • バッチサイズ:16, 32, 64, 128 の 4 種類
from tensorflow import keras
from tensorflow.keras import layers
import numpy as np

# データセット読み込み
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train[..., np.newaxis] / 255.0
x_test = x_test[..., np.newaxis] / 255.0

# モデル定義
model = keras.Sequential([
    keras.layers.Input(shape=(28, 28, 1)),
    keras.layers.Conv2D(32, (3, 3), activation='relu'),
    keras.layers.MaxPooling2D(),
    keras.layers.Flatten(),
    keras.layers.Dense(64, activation='relu'),
    keras.layers.Dense(10, activation='softmax')
])

model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

実験コード

同じ初期重みを使うため、各バッチサイズごとにモデルを再生成して訓練します。

results = {}
histories = {}

for bs in [16, 32, 64, 128]:
    print(f"Batch Size: {bs}")
    histories[bs] = model.fit(
        x_train, y_train,
        batch_size=bs,      # ← ここでバッチサイズ切り替え
        epochs=10,
        validation_split=0.2
    )

    test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
    results[bs] = {
        "val_acc": histories[bs].history["val_accuracy"][-1],
        "test_acc": test_acc
    }

訓練結果

Batch Size: 16
Epoch 1/10
3000/3000 ━━━━━━━━━━━━━━━━━━━━ 9s 3ms/step - accuracy: 0.9986 - loss: 0.0048 - val_accuracy: 0.9834 - val_loss: 0.0846
Epoch 2/10
3000/3000 ━━━━━━━━━━━━━━━━━━━━ 10s 3ms/step - accuracy: 0.9988 - loss: 0.0036 - val_accuracy: 0.9847 - val_loss: 0.0969
Epoch 3/10
3000/3000 ━━━━━━━━━━━━━━━━━━━━ 9s 3ms/step - accuracy: 0.9981 - loss: 0.0051 - val_accuracy: 0.9870 - val_loss: 0.0787
Epoch 4/10
3000/3000 ━━━━━━━━━━━━━━━━━━━━ 10s 3ms/step - accuracy: 0.9992 - loss: 0.0028 - val_accuracy: 0.9870 - val_loss: 0.0686
Epoch 5/10
3000/3000 ━━━━━━━━━━━━━━━━━━━━ 10s 3ms/step - accuracy: 0.9990 - loss: 0.0028 - val_accuracy: 0.9864 - val_loss: 0.0856
Epoch 6/10
3000/3000 ━━━━━━━━━━━━━━━━━━━━ 9s 3ms/step - accuracy: 0.9990 - loss: 0.0036 - val_accuracy: 0.9854 - val_loss: 0.0897
Epoch 7/10
3000/3000 ━━━━━━━━━━━━━━━━━━━━ 9s 3ms/step - accuracy: 0.9992 - loss: 0.0025 - val_accuracy: 0.9853 - val_loss: 0.0875
Epoch 8/10
3000/3000 ━━━━━━━━━━━━━━━━━━━━ 9s 3ms/step - accuracy: 0.9995 - loss: 0.0017 - val_accuracy: 0.9849 - val_loss: 0.1009
Epoch 9/10
3000/3000 ━━━━━━━━━━━━━━━━━━━━ 9s 3ms/step - accuracy: 0.9997 - loss: 0.0011 - val_accuracy: 0.9846 - val_loss: 0.0985
Epoch 10/10
3000/3000 ━━━━━━━━━━━━━━━━━━━━ 11s 3ms/step - accuracy: 0.9991 - loss: 0.0029 - val_accuracy: 0.9852 - val_loss: 0.1023
Batch Size: 32
Epoch 1/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 3ms/step - accuracy: 0.9997 - loss: 9.8968e-04 - val_accuracy: 0.9866 - val_loss: 0.0857
Epoch 2/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 9s 3ms/step - accuracy: 1.0000 - loss: 5.7384e-05 - val_accuracy: 0.9873 - val_loss: 0.0863
Epoch 3/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 3ms/step - accuracy: 1.0000 - loss: 1.2405e-05 - val_accuracy: 0.9873 - val_loss: 0.0889
Epoch 4/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 1.0000 - loss: 5.5474e-06 - val_accuracy: 0.9872 - val_loss: 0.0902
Epoch 5/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 1.0000 - loss: 3.3598e-06 - val_accuracy: 0.9874 - val_loss: 0.0930
Epoch 6/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 1.0000 - loss: 2.1214e-06 - val_accuracy: 0.9874 - val_loss: 0.0957
Epoch 7/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 11s 4ms/step - accuracy: 1.0000 - loss: 1.0058e-06 - val_accuracy: 0.9876 - val_loss: 0.0983
Epoch 8/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 10s 3ms/step - accuracy: 1.0000 - loss: 5.8998e-07 - val_accuracy: 0.9877 - val_loss: 0.1024
Epoch 9/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 4s 3ms/step - accuracy: 1.0000 - loss: 2.9769e-07 - val_accuracy: 0.9878 - val_loss: 0.1059
Epoch 10/10
1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 3ms/step - accuracy: 1.0000 - loss: 1.7629e-07 - val_accuracy: 0.9868 - val_loss: 0.1169
Batch Size: 64
Epoch 1/10
750/750 ━━━━━━━━━━━━━━━━━━━━ 4s 4ms/step - accuracy: 0.9989 - loss: 0.0044 - val_accuracy: 0.9844 - val_loss: 0.1087
Epoch 2/10
750/750 ━━━━━━━━━━━━━━━━━━━━ 2s 3ms/step - accuracy: 0.9998 - loss: 3.1455e-04 - val_accuracy: 0.9864 - val_loss: 0.0962
Epoch 3/10
750/750 ━━━━━━━━━━━━━━━━━━━━ 3s 3ms/step - accuracy: 1.0000 - loss: 1.0214e-05 - val_accuracy: 0.9863 - val_loss: 0.0964
Epoch 4/10
750/750 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 1.0000 - loss: 5.1206e-06 - val_accuracy: 0.9863 - val_loss: 0.0974
Epoch 5/10
750/750 ━━━━━━━━━━━━━━━━━━━━ 2s 3ms/step - accuracy: 1.0000 - loss: 3.9402e-06 - val_accuracy: 0.9862 - val_loss: 0.0979
Epoch 6/10
750/750 ━━━━━━━━━━━━━━━━━━━━ 2s 3ms/step - accuracy: 1.0000 - loss: 2.8684e-06 - val_accuracy: 0.9864 - val_loss: 0.0985
Epoch 7/10
750/750 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 1.0000 - loss: 1.9861e-06 - val_accuracy: 0.9863 - val_loss: 0.0992
Epoch 8/10
750/750 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 1.0000 - loss: 1.6821e-06 - val_accuracy: 0.9864 - val_loss: 0.0998
Epoch 9/10
750/750 ━━━━━━━━━━━━━━━━━━━━ 2s 3ms/step - accuracy: 1.0000 - loss: 1.3144e-06 - val_accuracy: 0.9864 - val_loss: 0.1006
Epoch 10/10
750/750 ━━━━━━━━━━━━━━━━━━━━ 3s 3ms/step - accuracy: 1.0000 - loss: 1.0312e-06 - val_accuracy: 0.9868 - val_loss: 0.1015
Batch Size: 128
Epoch 1/10
375/375 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - accuracy: 1.0000 - loss: 6.7372e-07 - val_accuracy: 0.9866 - val_loss: 0.1020
Epoch 2/10
375/375 ━━━━━━━━━━━━━━━━━━━━ 1s 4ms/step - accuracy: 1.0000 - loss: 6.0283e-07 - val_accuracy: 0.9865 - val_loss: 0.1026
Epoch 3/10
375/375 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 1.0000 - loss: 5.4752e-07 - val_accuracy: 0.9868 - val_loss: 0.1031
Epoch 4/10
375/375 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 1.0000 - loss: 4.9129e-07 - val_accuracy: 0.9868 - val_loss: 0.1035
Epoch 5/10
375/375 ━━━━━━━━━━━━━━━━━━━━ 2s 4ms/step - accuracy: 1.0000 - loss: 4.1864e-07 - val_accuracy: 0.9869 - val_loss: 0.1041
Epoch 6/10
375/375 ━━━━━━━━━━━━━━━━━━━━ 2s 4ms/step - accuracy: 1.0000 - loss: 3.6648e-07 - val_accuracy: 0.9871 - val_loss: 0.1047
Epoch 7/10
375/375 ━━━━━━━━━━━━━━━━━━━━ 1s 4ms/step - accuracy: 1.0000 - loss: 2.9667e-07 - val_accuracy: 0.9870 - val_loss: 0.1054
Epoch 8/10
375/375 ━━━━━━━━━━━━━━━━━━━━ 1s 4ms/step - accuracy: 1.0000 - loss: 2.6079e-07 - val_accuracy: 0.9871 - val_loss: 0.1061
Epoch 9/10
375/375 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 1.0000 - loss: 2.3504e-07 - val_accuracy: 0.9871 - val_loss: 0.1067
Epoch 10/10
375/375 ━━━━━━━━━━━━━━━━━━━━ 2s 4ms/step - accuracy: 1.0000 - loss: 2.0702e-07 - val_accuracy: 0.9872 - val_loss: 0.1073

結果の可視化

各バッチサイズの検証精度と損失の推移をグラフ化します。

import matplotlib.pyplot as plt

for bs in [16, 32, 64, 128]:
    print(f"{bs}: {results[bs]}")

for bs in [16, 32, 64, 128]:
    plt.plot(histories[bs].history['val_accuracy'], label=f'{bs} val_accuracy')

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

for bs in [16, 32, 64, 128]:
    plt.plot(histories[bs].history['val_loss'], label=f'{bs} val_loss')

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

最終結果

16: {'val_acc': 0.9852499961853027, 'test_acc': 0.9847999811172485}
32: {'val_acc': 0.9868333339691162, 'test_acc': 0.9868000149726868}
64: {'val_acc': 0.9867500066757202, 'test_acc': 0.9868999719619751}
128: {'val_acc': 0.9872499704360962, 'test_acc': 0.9871000051498413}

精度グラフ

精度グラフ

損失グラフ

損失グラフ

結果まとめ

Batch Size 最終 Val Accuracy 最終 Val Loss 特徴
16 0.9852 0.1023 ステップ多く学習安定だが、最終損失高め
32 0.9868 0.1169 早く収束するが、損失のばらつき大
64 0.9868 0.1015 高速学習+安定感あり
128 0.9872 0.1073 最も高精度だがメモリ効率が低い

考察

  • Batch Size 16:小バッチはパラメータ更新が細かく、安定的に学習する反面、ステップ数が増えて学習時間が長くなり、最終損失もやや高め。
  • Batch Size 32:標準的な設定。学習が速く進むが、損失の振れ幅が大きいため微調整が必要。
  • Batch Size 64:学習速度と性能のバランスが良い。Val Accuracy と Val Loss の両方で安定した結果。
  • Batch Size 128:最も高い Val Accuracy を達成。ただし、大きなバッチはメモリ使用量が増加し、過学習リスクも若干高まる。

まとめ

バッチサイズは「学習時間」「メモリ使用量」「汎化性能」のトレードオフで最適値が変わります。
本実験では Batch Size 64 が最もバランスの良い結果となりましたが、データやモデル構造に応じて調整をおすすめします。
ぜひ本記事を参考に、プロジェクトに最適なバッチサイズを見つけてください!

このブログを検索

自己紹介

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

お問い合わせフォーム

名前

メール *

メッセージ *

プライバシーポリシー

QooQ