📋 このステップで学ぶこと
- バッチ正規化とは何か?なぜ必要か?
- 内部共変量シフトの問題とその解決
- バッチ正規化の計算手順(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なし
])
artnasekai
#artnasekai #学習メモ