STEP 13:バッチ正規化

⚡ STEP 13: バッチ正規化(Batch Normalization)

学習を劇的に高速化・安定化させる強力なテクニックを習得しよう

📋 このステップで学ぶこと

  • バッチ正規化とは何か?なぜ必要か?
  • 内部共変量シフトの問題とその解決
  • バッチ正規化の計算手順(4ステップ)
  • 訓練時と推論時の違い
  • Kerasでの実装方法と配置場所
  • バッチ正規化の5つの効果
  • 実践的な使い方とパターン

🎯 1. バッチ正規化とは?

1-1. 基本的な定義

バッチ正規化(Batch Normalization)は、2015年にGoogleの研究者が発表した技術で、ニューラルネットワークの各層の出力を正規化することで、学習を高速化・安定化させます。

💡 バッチ正規化を一言で言うと

各層の出力を「平均0、標準偏差1」に揃えるテクニックです。

これにより、次の層への入力が常に安定し、学習がスムーズになります。

1-2. 身近な例で理解する

📚 テストの点数調整の例

問題:数学と英語のテスト、平均点が大きく違う場合

数学:平均30点、標準偏差10点(難しい)
英語:平均80点、標準偏差5点(簡単)

太郎くんの点数:数学40点、英語85点
→ このままでは「どちらが得意か」比較しにくい!

解決策:正規化する

数学の標準化スコア = (40 – 30) / 10 = 1.0
英語の標準化スコア = (85 – 80) / 5 = 1.0

→ 両方とも平均から1標準偏差分上!同じくらい得意!

バッチ正規化も同じアイデアです。
各層の出力を「平均0、標準偏差1」に揃えることで、
次の層が安定した入力を受け取れるようにします。

1-3. バッチ正規化の効果(先に結論)

✅ バッチ正規化の5つの効果
  • 学習の高速化:2〜10倍速くなることも!
  • 学習の安定化:より大きい学習率が使える
  • 過学習の抑制:正則化の効果もある
  • 勾配消失の緩和:深いネットワークでも学習しやすい
  • 初期値への依存が減る:重みの初期化の影響が小さくなる

⚠️ 2. 内部共変量シフトの問題

2-1. 内部共変量シフトとは?

バッチ正規化が解決する主な問題は、内部共変量シフト(Internal Covariate Shift)です。
難しい名前ですが、簡単に言うと「各層への入力分布が学習中に変わってしまう問題」です。

🏫 転校生の例え

隠れ層2が転校生だとします:

月曜日:「今日から新しいクラスで勉強するよ!」
→ 先生(隠れ層1)の教え方に慣れる

火曜日:「えっ、先生の教え方が変わった!?」
→ また1から適応しなければ…

水曜日:「また変わった!!」
→ 混乱して学習が進まない…

これが内部共変量シフトです。
前の層の出力分布が変わると、次の層は常に適応し続けなければならず、学習が遅くなります。

2-2. なぜ内部共変量シフトが起きるのか?

以下の図は横スクロールできます。

【内部共変量シフトの発生メカニズム】 ニューラルネットワークの構造: 入力 → 隠れ層1 → 隠れ層2 → 出力 【学習の流れ】 エポック1: ・隠れ層1の重み = w₁(初期値) ・隠れ層1の出力分布 = 平均5、標準偏差2 ・隠れ層2は「この分布」に最適化しようとする エポック2: ・隠れ層1の重みが更新 → w₁’ ・隠れ層1の出力分布 = 平均8、標準偏差4 ← 変わった! ・隠れ層2:「えっ、入力が全然違う…」 エポック3: ・隠れ層1の重みがさらに更新 → w₁” ・隠れ層1の出力分布 = 平均3、標準偏差1 ← また変わった! ・隠れ層2:「もう何に最適化すればいいか分からない…」 → 隠れ層2は常に「動く的」を追いかけることになる → 学習が遅く、不安定になる

2-3. 視覚的なイメージ

【内部共変量シフトのイメージ】 ■ バッチ正規化なしの場合: 分布が変わる! また変わる! ↓ ↓ エポック1: [分布A] → 隠れ層2 → … エポック2: [分布B] → 隠れ層2 → …(混乱) エポック3: [分布C] → 隠れ層2 → …(さらに混乱) ↑ 隠れ層1の出力 ■ バッチ正規化ありの場合: 常に同じ分布! ↓ エポック1: [平均0, 標準偏差1] → 隠れ層2 → … エポック2: [平均0, 標準偏差1] → 隠れ層2 → …(安定) エポック3: [平均0, 標準偏差1] → 隠れ層2 → …(安定) ↑ バッチ正規化で揃える → 隠れ層2は安定した入力で学習できる!
⚠️ 内部共変量シフトの悪影響
  • 学習が遅い:各層が常に変化する入力に適応しなければならない
  • 学習が不安定:学習率を大きくすると発散しやすい
  • 勾配消失:深い層では勾配が消えやすい
  • 初期値に敏感:悪い初期値だと学習が進まない

🧮 3. バッチ正規化の計算手順

3-1. 計算の4ステップ

バッチ正規化は、以下の4ステップで実行されます。

📐 バッチ正規化の4ステップ

ミニバッチのデータ: x₁, x₂, …, xₘ(m個のサンプル)

ステップ1: ミニバッチの平均を計算
μ_B = (1/m) × Σ xᵢ

ステップ2: ミニバッチの分散を計算
σ²_B = (1/m) × Σ (xᵢ – μ_B)²

ステップ3: 正規化(平均0、標準偏差1にする)
x̂ᵢ = (xᵢ – μ_B) / √(σ²_B + ε)
ε = 0除算を防ぐ小さな値(例:1e-5)

ステップ4: スケールとシフト(γとβで調整)
yᵢ = γ × x̂ᵢ + β
γ, β = 学習可能なパラメータ

3-2. 具体例で理解する

【具体例】ミニバッチサイズ = 4の場合 入力データ: x₁=2, x₂=4, x₃=6, x₄=8 ■ ステップ1: 平均を計算 μ_B = (2 + 4 + 6 + 8) / 4 = 20 / 4 = 5 ■ ステップ2: 分散を計算 σ²_B = [(2-5)² + (4-5)² + (6-5)² + (8-5)²] / 4 = [9 + 1 + 1 + 9] / 4 = 20 / 4 = 5 ■ ステップ3: 正規化(ε = 0.00001) x̂₁ = (2 – 5) / √(5 + 0.00001) ≈ -3 / 2.236 ≈ -1.34 x̂₂ = (4 – 5) / √5 ≈ -1 / 2.236 ≈ -0.45 x̂₃ = (6 – 5) / √5 ≈ 1 / 2.236 ≈ 0.45 x̂₄ = (8 – 5) / √5 ≈ 3 / 2.236 ≈ 1.34 → 正規化後: 平均≈0、標準偏差≈1 になった! ■ ステップ4: スケールとシフト(γ=1.5, β=0.5の場合) y₁ = 1.5 × (-1.34) + 0.5 ≈ -1.51 y₂ = 1.5 × (-0.45) + 0.5 ≈ -0.18 y₃ = 1.5 × 0.45 + 0.5 ≈ 1.18 y₄ = 1.5 × 1.34 + 0.5 ≈ 2.51 → γとβで最終的な分布を調整

3-3. なぜステップ4(γとβ)が必要?

🤔 疑問:正規化したのに、またスケール・シフトする?

理由:正規化しすぎると、ネットワークの表現力が制限される可能性があるためです。

【なぜγとβが必要か?】 ■ 問題:sigmoid関数の場合 正規化後の値は約-3〜3の範囲に集中 ↓ sigmoid(-3) ≈ 0.05 sigmoid(-1) ≈ 0.27 sigmoid(0) ≈ 0.50 sigmoid(1) ≈ 0.73 sigmoid(3) ≈ 0.95 ↓ この範囲はsigmoidの「ほぼ線形な部分」 ↓ 非線形性が失われて、ネットワークの表現力が下がる! ■ 解決:γとβを学習させる γ = 2, β = 3 に学習すると… y = 2 × x̂ + 3 ↓ 値の範囲が広がり、非線形な部分も使えるようになる ■ さらに重要なポイント γ = σ_B(元の標準偏差) β = μ_B(元の平均) に学習すれば… ↓ 正規化を「完全に元に戻す」ことも可能! ↓ ネットワークが自分で「正規化が必要かどうか」を判断できる

3-4. 訓練時と推論時の違い

項目 訓練時(Training) 推論時(Inference)
平均・分散 ミニバッチごとに計算 訓練時の移動平均を使用(固定値)
なぜ違う? バッチ内の統計量で十分 1サンプルではバッチ統計量が計算できない
γ, β 学習して更新 固定値を使用
✅ 推論時の動作

推論時(テスト時)は、訓練時に記録した平均・分散の移動平均を使います。

理由:推論時は1サンプルずつ処理することが多く、ミニバッチの統計量が計算できないため。

安心ポイント:Kerasが自動で処理してくれるので、特別な実装は不要です!

💻 4. Kerasでの実装方法

4-1. 基本的な使い方

📝 コードの解説

BatchNormalization()

バッチ正規化レイヤーを追加します。
これだけで、その前の層の出力を正規化してくれます。

from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, BatchNormalization, Activation # モデル構築 model = Sequential([ Dense(128, input_shape=(784,)), # 線形変換 BatchNormalization(), # 正規化 Activation(‘relu’), # 活性化 Dense(64), # 線形変換 BatchNormalization(), # 正規化 Activation(‘relu’), # 活性化 Dense(10, activation=’softmax’) # 出力層(BNは追加しない) ]) model.compile( optimizer=’adam’, loss=’categorical_crossentropy’, metrics=[‘accuracy’] )

4-2. 配置場所:活性化関数の前 vs 後

バッチ正規化は、活性化関数の前に置くか、に置くか、議論があります。

📊 2つの配置パターン

パターンA:活性化関数の前(推奨)

Dense(128) # 線形変換 BatchNormalization() # 正規化 Activation(‘relu’) # 活性化

パターンB:活性化関数の後

Dense(128, activation=’relu’) # 線形変換 + 活性化 BatchNormalization() # 正規化
項目 活性化関数の前(パターンA) 活性化関数の後(パターンB)
論文の推奨 ✅ 推奨
実装の簡単さ やや複雑(3行必要) ✅ 簡単(2行で済む)
効果 ほぼ同じ ほぼ同じ
結論 どちらでも効果はほぼ同じ!好きな方を使ってOK

4-3. 完成コード(推奨パターン)

from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, BatchNormalization, Activation, Flatten from tensorflow.keras.datasets import mnist from tensorflow.keras.utils import to_categorical # データ読み込み (X_train, y_train), (X_test, y_test) = mnist.load_data() X_train = X_train / 255.0 X_test = X_test / 255.0 y_train = to_categorical(y_train) y_test = to_categorical(y_test) # モデル構築(バッチ正規化あり) model = Sequential([ Flatten(input_shape=(28, 28)), Dense(256), BatchNormalization(), Activation(‘relu’), Dense(128), BatchNormalization(), Activation(‘relu’), Dense(64), BatchNormalization(), Activation(‘relu’), Dense(10, activation=’softmax’) # 出力層にはBNを追加しない ]) model.compile( optimizer=’adam’, loss=’categorical_crossentropy’, metrics=[‘accuracy’] ) # 学習 history = model.fit( X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=128 )

📊 5. バッチ正規化の効果を確認

5-1. バッチ正規化あり vs なし の比較

📝 コードの解説

2つのモデル(バッチ正規化あり/なし)を作成し、同じデータで学習して比較します。

import tensorflow as tf from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Flatten, BatchNormalization, Activation from tensorflow.keras.datasets import mnist from tensorflow.keras.utils import to_categorical import matplotlib.pyplot as plt # データ読み込み (X_train, y_train), (X_test, y_test) = mnist.load_data() X_train = X_train / 255.0 X_test = X_test / 255.0 y_train = to_categorical(y_train) y_test = to_categorical(y_test) # モデル1:バッチ正規化なし model_without_bn = Sequential([ Flatten(input_shape=(28, 28)), Dense(256, activation=’relu’), Dense(128, activation=’relu’), Dense(64, activation=’relu’), Dense(10, activation=’softmax’) ]) model_without_bn.compile(optimizer=’adam’, loss=’categorical_crossentropy’, metrics=[‘accuracy’]) # モデル2:バッチ正規化あり model_with_bn = Sequential([ Flatten(input_shape=(28, 28)), Dense(256), BatchNormalization(), Activation(‘relu’), Dense(128), BatchNormalization(), Activation(‘relu’), Dense(64), BatchNormalization(), Activation(‘relu’), Dense(10, activation=’softmax’) ]) model_with_bn.compile(optimizer=’adam’, loss=’categorical_crossentropy’, metrics=[‘accuracy’]) # 学習 print(“=== バッチ正規化なしで学習 ===”) history_without = model_without_bn.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=20, batch_size=128, verbose=0) print(“=== バッチ正規化ありで学習 ===”) history_with = model_with_bn.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=20, batch_size=128, verbose=0) # 結果を表示 print(f”\nバッチ正規化なし – テスト精度: {history_without.history[‘val_accuracy’][-1]:.4f}”) print(f”バッチ正規化あり – テスト精度: {history_with.history[‘val_accuracy’][-1]:.4f}”)
実行結果(例):
=== バッチ正規化なしで学習 ===
=== バッチ正規化ありで学習 ===

バッチ正規化なし - テスト精度: 0.9754
バッチ正規化あり - テスト精度: 0.9812

→ バッチ正規化により、精度が約0.6%向上!
→ 損失の減少も速い(学習が高速化)
✅ 実験から分かること
  • 収束が速い:同じエポック数で、より低い損失に到達
  • 精度が向上:テスト精度が約0.6%向上
  • 学習が安定:損失のグラフが滑らか

🎯 6. 実践的な使い方

6-1. バッチ正規化の配置ガイド

📌 配置のルール
  • すべての隠れ層の後にBatchNormalizationを追加
  • 出力層には追加しない(出力の分布を変えたくないため)
  • Dropoutと併用する場合:BatchNormalization → Dropout の順

6-2. パターン別の実装例

📝 パターン1:シンプルな全結合ネットワーク
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, BatchNormalization, Activation model = Sequential([ Dense(256, input_shape=(784,)), BatchNormalization(), Activation(‘relu’), Dense(128), BatchNormalization(), Activation(‘relu’), Dense(10, activation=’softmax’) # 出力層にはBNなし ])
📝 パターン2:Dropoutと併用

Dropoutと併用する場合は、BN → Dropoutの順番が推奨されます。

from tensorflow.keras.layers import Dropout model = Sequential([ Dense(256, input_shape=(784,)), BatchNormalization(), Activation(‘relu’), Dropout(0.3), # BN → Dropout の順 Dense(128), BatchNormalization(), Activation(‘relu’), Dropout(0.3), Dense(10, activation=’softmax’) ])
📝 パターン3:CNNでの使用

畳み込み層でも同じようにBatchNormalizationを追加できます。

from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten model = Sequential([ Conv2D(32, (3, 3), input_shape=(28, 28, 1)), BatchNormalization(), Activation(‘relu’), MaxPooling2D((2, 2)), Conv2D(64, (3, 3)), BatchNormalization(), Activation(‘relu’), MaxPooling2D((2, 2)), Flatten(), Dense(128), BatchNormalization(), Activation(‘relu’), Dense(10, activation=’softmax’) ])

6-3. バッチ正規化を使うべき場面

場面 推奨度 理由
深いネットワーク(5層以上) ★★★★★ 強く推奨 勾配消失を緩和、学習が安定
CNN(画像認識) ★★★★★ 強く推奨 画像認識で特に効果的
学習が不安定な場合 ★★★★★ 強く推奨 損失が振動する場合に効果
浅いネットワーク(2-3層) ★★☆☆☆ 効果は限定的 シンプルなネットワークでは不要なことも
RNN/LSTM ★★★☆☆ ケースバイケース Layer Normalizationの方が良い場合も

6-4. 注意点

⚠️ バッチ正規化の注意点
  • バッチサイズが小さいと不安定:32以上推奨、8以下は避ける
    理由:サンプル数が少ないと、ミニバッチの統計量が不安定になる
  • 計算量が増える:レイヤーが増えるため、やや遅くなる(通常は問題にならない)
  • RNN/LSTMでは慎重に:時系列データではLayer Normalizationの方が良い場合も

⚡ 7. バッチ正規化の5つの効果

✅ 効果1:学習の高速化

内部共変量シフトを抑制することで、学習が2〜10倍速くなります。
各層が安定した入力を受け取れるため、効率的に学習できます。

✅ 効果2:より大きい学習率が使える

正規化により学習が安定するため、通常より大きい学習率を使えます。
→ さらに学習が高速化!

✅ 効果3:初期値への依存が減る

正規化により、重みの初期値の影響が小さくなります。
→ 初期化の失敗による学習の失敗が減る

✅ 効果4:正則化の効果(過学習抑制)

ミニバッチごとに正規化するため、ノイズが加わり、過学習を抑制する効果があります。
→ Dropoutとの併用でさらに効果的

✅ 効果5:勾配消失の緩和

各層の出力が適切な範囲に保たれるため、勾配消失が起こりにくくなります。
→ 深いネットワークでも学習可能

📝 STEP 13 のまとめ

✅ このステップで学んだこと
  • バッチ正規化は、各層の出力を平均0、標準偏差1に正規化する技術
  • 内部共変量シフト(各層への入力分布が変化する問題)を解決
  • 計算は4ステップ:平均計算 → 分散計算 → 正規化 → スケール・シフト
  • γとβは学習可能なパラメータで、ネットワークが最適な分布を学習
  • KerasではBatchNormalization()を追加するだけ
  • 活性化関数の前に配置するのが推奨(後でも効果はほぼ同じ)
  • 深いネットワーク、CNNで特に効果的
💡 覚えておくべき実装パターン
from tensorflow.keras.layers import Dense, BatchNormalization, Activation # 推奨パターン Dense(128) # 線形変換 BatchNormalization() # 正規化 Activation(‘relu’) # 活性化 # 出力層にはBatchNormalizationを追加しない Dense(10, activation=’softmax’)
🚀 次のステップへ

バッチ正規化を習得したので、次のSTEP 14ではドロップアウト(Dropout)を学びます。

ドロップアウトは過学習を防ぐ強力な正則化手法です。
バッチ正規化と組み合わせることで、さらに効果的なモデルを構築できます!

📝 練習問題

問題1 やさしい

バッチ正規化の主な効果

バッチ正規化の主な効果として、正しくないものを選んでください。

  • A. 学習の高速化
  • B. 学習の安定化
  • C. メモリ使用量の削減
  • D. 過学習の抑制
正解:C

バッチ正規化はメモリを削減しない

バッチ正規化はメモリ使用量を削減する効果はありません
むしろ、追加のパラメータ(γ、β)と統計量(平均、分散)を保存するため、メモリ使用量はやや増えます

【バッチ正規化の正しい効果】 ✅ A. 学習の高速化 → 内部共変量シフトを抑制し、2〜10倍速くなる ✅ B. 学習の安定化 → より大きい学習率が使える ✅ D. 過学習の抑制 → ミニバッチごとにノイズが加わり、正則化効果がある ❌ C. メモリ使用量の削減 → これは間違い。むしろ少し増える
問題2 やさしい

バッチ正規化の配置場所

バッチ正規化を配置する場所として、最も一般的なのはどれですか?

  • A. 入力層の直後
  • B. 各隠れ層の後(活性化関数の前)
  • C. 出力層の直前
  • D. Dropoutの前
正解:B

配置場所の説明

バッチ正規化は、各隠れ層の後(活性化関数の前)に配置するのが最も一般的です。

【推奨パターン】 Dense(128) # 隠れ層1 BatchNormalization() # ← ここ(活性化関数の前) Activation(‘relu’) Dense(64) # 隠れ層2 BatchNormalization() # ← ここ Activation(‘relu’) Dense(10, activation=’softmax’) # 出力層(BNなし)

他の選択肢の解説:

Aが間違い:入力層の直後にBNを置くこともできますが、一般的ではありません。
Cが間違い:出力層には追加しません(出力の分布を変えたくないため)。
Dが間違い:Dropoutと併用する場合は、BN → Dropout の順番です。

問題3 ふつう

内部共変量シフト

内部共変量シフト(Internal Covariate Shift)について、正しい説明を選んでください。

  • A. 入力データの分布が変化すること
  • B. 学習中に各層の入力分布が変化すること
  • C. 学習率が大きすぎること
  • D. 過学習によりテストデータで精度が下がること
正解:B

内部共変量シフトとは

内部共変量シフトは、学習中に各層の入力分布が変化することです。

【内部共変量シフトの問題】 エポック1: ・隠れ層1の出力分布 = 平均5、標準偏差2 ・隠れ層2はこの分布に最適化しようとする エポック2: ・隠れ層1の重みが更新される ・隠れ層1の出力分布 = 平均8、標準偏差4 ← 変わった! ・隠れ層2:「入力が全然違う…」 → 各層が常に変化する入力に適応しなければならない → 学習が遅く、不安定になる 【バッチ正規化による解決】 各層の出力を常に平均0、標準偏差1に正規化 → 次の層への入力分布が安定 → 学習が速く、安定する
問題4 むずかしい

バッチ正規化の実装

以下のコードのうち、バッチ正規化を正しく実装しているものを選んでください。

【選択肢A】 model = Sequential([ Dense(128, activation=’relu’), BatchNormalization(), Dense(64, activation=’relu’), Dense(10, activation=’softmax’) ])
【選択肢B】 model = Sequential([ Dense(128), BatchNormalization(), Activation(‘relu’), Dense(64), BatchNormalization(), Activation(‘relu’), Dense(10, activation=’softmax’) ])
【選択肢C】 model = Sequential([ BatchNormalization(), Dense(128, activation=’relu’), BatchNormalization(), Dense(64, activation=’relu’), BatchNormalization(), Dense(10, activation=’softmax’) ])
  • A. 選択肢Aが正しい
  • B. 選択肢Bが正しい
  • C. 選択肢Cが正しい
  • D. すべて正しい
正解:B

各選択肢の解説

選択肢Aの問題点:

  • 活性化関数の「後」にバッチ正規化を配置している
  • 2つ目のDense層にバッチ正規化がない
  • 動作はするが、推奨される配置ではない

選択肢Bが正しい理由:

  • Dense → BatchNormalization → Activation の順(推奨)
  • すべての隠れ層にバッチ正規化を配置
  • 出力層には配置しない(正しい)

選択肢Cの問題点:

  • 入力層の直後にバッチ正規化(一般的ではない)
  • 出力層の前にバッチ正規化(避けるべき)
【推奨される実装パターン(選択肢B)】 model = Sequential([ Dense(128), # 線形変換 BatchNormalization(), # 正規化 Activation(‘relu’), # 活性化 Dense(64), BatchNormalization(), Activation(‘relu’), Dense(10, activation=’softmax’) # 出力層にはBNなし ])
📝

学習メモ

ディープラーニング基礎 - Step 13

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE