BatchNormalizationとは?仕組み・メリット・Kerasでの使い方を画像とコードで徹底解説!

2025年7月11日金曜日

BatchNormalization CNN Google Colab Keras バッチ正規化

X f B! P L
アイキャッチ画像 BatchNormalizationとは?仕組み・メリット・Kerasでの使い方を画像とコードで徹底解説!

はじめに:BatchNormalizationとは?

ディープラーニングで高精度なモデルを構築したいと思ったことはありませんか?
実は、多くのモデルが「学習の不安定さ」や「勾配消失」といった問題に直面しています。
それらを解決するために誕生したのが、BatchNormalization(バッチ正規化)という技術です。

本記事では、BatchNormalizationの仕組み・効果・使い方・実験結果による検証まで、初学者でも理解しやすいよう丁寧に解説していきます。

実際のコードやグラフを通じて、BatchNormalizationの真価を体感してみましょう!

BatchNormalizationの効果とは?

BatchNormalization(バッチ正規化)には、機械学習モデルの性能を向上させる以下のようなメリットがあります。

  • 勾配消失の緩和:活性化関数の出力が極端な値になるのを防ぎます。
  • 学習の高速化:パラメータ調整がスムーズに進み、訓練時間が短縮されます。
  • 初期値への依存度低下:初期の重みが多少ズレていても、影響が小さくなります。
  • 軽い正則化効果:過学習を抑え、テスト精度の向上に貢献します。

このように、BatchNormalizationはディープラーニングの安定性と効率性を大きく改善してくれる重要な技術です。

実装方法:Kerasでの使い方

Kerasでは、layers.BatchNormalization() をモデルの中間層に追加するだけで簡単に実装できます。
特に、Conv2DやDense層の直後に挿入するのが一般的です。

以下は、BatchNormalizationを含むCNNモデルのサンプルコードです:

from tensorflow.keras import layers
model = keras.Sequential([
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
layers.BatchNormalization(), # ★ここに追加
layers.MaxPooling2D((2, 2)),
layers.Flatten(),
layers.Dense(64, activation='relu'),
layers.BatchNormalization(), # ★ここにも追加
layers.Dense(10, activation='softmax')
])

このように、わずかな変更でモデルの収束速度が大きく改善され、テスト精度も向上する可能性があります。

BatchNormalizationのしくみ

BatchNormalizationでは、各ミニバッチの出力に対して次の3つのステップを行います。

  1. 各特徴量の平均分散を計算
  2. 正規化:平均0、分散1のスケールに変換
  3. 学習可能なスケール(γ)シフト(β)パラメータを適用

これにより、内部共変量シフト(Internal Covariate Shift)が軽減され、ネットワークの深さによる性能劣化を抑えることができます。

BatchNormalizationのあり/なし比較

ここでは、MNIST手書き数字データセットを用いて、BatchNormalizationを「使ったモデル」と「使わないモデル」の性能を比較してみます。

比較条件

  • 使用データセット:MNIST(28x28の手書き数字画像)
  • エポック数:10
  • バッチサイズ:32
  • Optimizer:Adam

データ準備:MNIST手書き数字データセットの読み込みと前処理

import tensorflow as tf
from tensorflow import keras

# データ読み込み・前処理
(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[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]

MNISTは機械学習入門で定番のデータセットです。ここでは読み込みから正規化、形状変換までを一括処理しています。

モデル構築関数

今回は、2層構成のCNN(畳み込みニューラルネットワーク)をもとにBatchNormalizationあり・なしを切り替えることができるモデルを構築します。

BatchNormalizationあり:

Conv2D → BatchNormalization → MaxPooling → Conv2D → BatchNormalization → MaxPooling → Flatten → Dense → BatchNormalization → Dense

BatchNormalizationなし:

Conv2D → MaxPooling → Conv2D → MaxPooling → Flatten → Dense → Dense

from tensorflow.keras import layers

# モデル構築関数(引数でBatchNorm有無を切替)
def build_model(use_batchnorm=False):
    model = keras.Sequential()
    model.add(layers.Input(shape=(28, 28, 1)))
    model.add(layers.Conv2D(32, 3, activation='relu'))
    if use_batchnorm:
        model.add(layers.BatchNormalization())
    model.add(layers.MaxPooling2D())
    model.add(layers.Conv2D(64, 3, activation='relu'))
    if use_batchnorm:
        model.add(layers.BatchNormalization())
    model.add(layers.MaxPooling2D())
    model.add(layers.Flatten())
    model.add(layers.Dense(64, activation='relu'))
    if use_batchnorm:
        model.add(layers.BatchNormalization())
    model.add(layers.Dense(10, activation='softmax'))

    return model

各モデルの学習と評価手順

次に、構築した各CNNモデル(BatchNormalizationあり・なし)を訓練します。 最適化には Adam を用い、損失関数には SparseCategoricalCrossentropy を使用します。

# モデルの訓練
def train_model(use_batchnorm):
    model = build_model(use_batchnorm)
    model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
    history = model.fit(
        x_train, y_train,
        epochs=10,
        batch_size=32,
        validation_split=0.1,
        verbose=1
    )
    test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
    return history, test_acc

# 訓練実行
print(f"Training with BatchNorm")
history_bn, acc_bn = train_model(use_batchnorm=True)
print(f"Training without BatchNorm")
history_no_bn, acc_no_bn = train_model(use_batchnorm=False)

検証用データとして訓練データの10%を分割し、エポック数は10に統一しています。 訓練のたびにログを出力し、最後にテストデータで汎化性能を確認しています。

学習ログと各モデルの評価結果

各モデルの学習ログと最終結果です。

Training with BatchNorm
Epoch 1/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 15s 6ms/step - accuracy: 0.9372 - loss: 0.2156 - val_accuracy: 0.9867 - val_loss: 0.0472
Epoch 2/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 14s 4ms/step - accuracy: 0.9858 - loss: 0.0458 - val_accuracy: 0.9888 - val_loss: 0.0396
Epoch 3/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9906 - loss: 0.0288 - val_accuracy: 0.9892 - val_loss: 0.0443
Epoch 4/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 11s 4ms/step - accuracy: 0.9926 - loss: 0.0238 - val_accuracy: 0.9915 - val_loss: 0.0348
Epoch 5/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9946 - loss: 0.0173 - val_accuracy: 0.9905 - val_loss: 0.0365
Epoch 6/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9961 - loss: 0.0127 - val_accuracy: 0.9900 - val_loss: 0.0415
Epoch 7/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 6s 3ms/step - accuracy: 0.9950 - loss: 0.0129 - val_accuracy: 0.9905 - val_loss: 0.0342
Epoch 8/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9974 - loss: 0.0091 - val_accuracy: 0.9902 - val_loss: 0.0309
Epoch 9/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 10s 4ms/step - accuracy: 0.9974 - loss: 0.0071 - val_accuracy: 0.9907 - val_loss: 0.0431
Epoch 10/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 10s 4ms/step - accuracy: 0.9967 - loss: 0.0092 - val_accuracy: 0.9930 - val_loss: 0.0329
Training without BatchNorm
Epoch 1/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 9s 4ms/step - accuracy: 0.8971 - loss: 0.3367 - val_accuracy: 0.9847 - val_loss: 0.0572
Epoch 2/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 8s 3ms/step - accuracy: 0.9846 - loss: 0.0499 - val_accuracy: 0.9857 - val_loss: 0.0492
Epoch 3/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 6s 3ms/step - accuracy: 0.9892 - loss: 0.0333 - val_accuracy: 0.9887 - val_loss: 0.0408
Epoch 4/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9925 - loss: 0.0233 - val_accuracy: 0.9917 - val_loss: 0.0302
Epoch 5/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 6s 3ms/step - accuracy: 0.9952 - loss: 0.0162 - val_accuracy: 0.9912 - val_loss: 0.0403
Epoch 6/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 6s 3ms/step - accuracy: 0.9953 - loss: 0.0145 - val_accuracy: 0.9888 - val_loss: 0.0417
Epoch 7/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 10s 3ms/step - accuracy: 0.9963 - loss: 0.0105 - val_accuracy: 0.9905 - val_loss: 0.0425
Epoch 8/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 10s 3ms/step - accuracy: 0.9971 - loss: 0.0088 - val_accuracy: 0.9893 - val_loss: 0.0390
Epoch 9/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9979 - loss: 0.0066 - val_accuracy: 0.9885 - val_loss: 0.0556
Epoch 10/10
1688/1688 ━━━━━━━━━━━━━━━━━━━━ 10s 3ms/step - accuracy: 0.9979 - loss: 0.0065 - val_accuracy: 0.9897 - val_loss: 0.0479

学習曲線:精度と損失の推移グラフ

学習曲線の描画と比較結果出力を行います。

import matplotlib.pyplot as plt

# グラフ描画
def plot_history(hist1, hist2, label1='With BN', label2='Without BN'):
    plt.figure(figsize=(12,5))

    plt.subplot(1,2,1)
    plt.plot(hist1.history['val_accuracy'], label=f'{label1} Val Acc')
    plt.plot(hist2.history['val_accuracy'], label=f'{label2} Val Acc')
    plt.xlabel('Epoch')
    plt.ylabel('Validation Accuracy')
    plt.legend()
    plt.title('Validation Accuracy')

    plt.subplot(1,2,2)
    plt.plot(hist1.history['val_loss'], label=f'{label1} Val Loss')
    plt.plot(hist2.history['val_loss'], label=f'{label2} Val Loss')
    plt.xlabel('Epoch')
    plt.ylabel('Validation Loss')
    plt.legend()
    plt.title('Validation Loss')

    plt.tight_layout()
    plt.show()

# 比較結果出力
print(f"✅ テスト精度(BatchNormあり): {acc_bn:.4f}")
print(f"❌ テスト精度(BatchNormなし): {acc_no_bn:.4f}")

# 学習曲線プロット
plot_history(history_bn, history_no_bn)

比較結果出力

✅ テスト精度(BatchNormあり): 0.9911
❌ テスト精度(BatchNormなし): 0.9899

精度グラフ

精度グラフ

損失グラフ

損失グラフ

学習結果の比較(BatchNormalizationあり/なし)

10エポックの学習を比較したところ、BatchNormalizationを導入したモデルは、以下のような明確なメリットが見られました。

  • 学習の初期段階で精度が高く、収束が速い
  • バリデーション精度が全体的に高く、安定している
  • 過学習を抑える効果があり、テスト精度にも良好な影響

特に、学習終盤で「BNなしモデル」はバリデーションロスが上昇し、汎化性能の劣化が見られました。これは典型的な過学習の兆候です。

一方、BNありモデルは学習がスムーズかつ安定しており、高精度で実用性の高いモデルとなりました。

まとめ:BatchNormalizationは深層学習の安定化に不可欠

BatchNormalizationは、学習の安定性向上・学習速度の向上・テスト精度の改善といった多くの恩恵をもたらします。
現代のディープラーニングモデルでは、CNNや全結合層を問わず広く活用されています。

Kerasを使えば数行で導入できるため、まずは自分のモデルに組み込んで、その効果をグラフや数値で確認してみましょう。

より高性能で汎化能力のあるモデルを構築する第一歩として、BatchNormalizationは非常におすすめの技術です。

参考リンク

このブログを検索

自己紹介

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

お問い合わせフォーム

名前

メール *

メッセージ *

プライバシーポリシー

QooQ