SilverIce Toolbox
Back to course

Stage 3 / Chapter 14

第14章:Batch Normalization | Chapter 14: Batch Normalization

阶段定位 | Stage: 第三阶段 — 深度学习核心 预计学时 | Duration: 4~5 小时

---

学习目标 | Learning Objectives

中文:

  • 理解 BatchNorm 如何解决内部协变量偏移(Internal Covariate Shift)
  • 掌握 BatchNorm 前向传播的完整计算流程
  • 理解 γ(scale)和 β(shift)的可学习参数意义
  • 掌握训练时与测试时的不同行为
  • 能在 NumPy 中实现完整的 BatchNorm 前向传播

English:

  • Understand how BatchNorm solves Internal Covariate Shift
  • Master complete forward computation flow of BatchNorm
  • Understand learnable parameters γ (scale) and β (shift)
  • Master different behaviors during training vs testing
  • Implement complete BatchNorm forward pass in NumPy

---

14.1 问题:内部协变量偏移 | Problem: Internal Covariate Shift

中文解释

问题本质

在深层网络中,每一层的输入分布会随着前面层参数的变化而变化:

Layer 1 参数更新 → Layer 2 输入分布改变 → Layer 2 参数需重新适应
Layer 2 参数更新 → Layer 3 输入分布改变 → Layer 3 参数需重新适应
...

这就像:

  • 你正在学习射箭,但靶子每 5 分钟移动一次位置
  • 你刚适应了一个分布,它又变了

后果

  • 学习率必须很小(否则分布变化太剧烈,模型跟不上)
  • 收敛极慢
  • 对初始化非常敏感

English Explanation

The Problem: Each layer's input distribution changes as previous layers update:

Layer 1 updates → Layer 2 input shifts → Layer 2 must re-adapt
Layer 2 updates → Layer 3 input shifts → Layer 3 must re-adapt

Like learning archery while the target moves every 5 minutes.

---

14.2 BatchNorm 的解决方案 | BatchNorm Solution

中文解释

核心思想

对每一层的线性输出 Z 做标准化:

μ_B = (1/m) * Σ z_i          # batch 均值
σ²_B = (1/m) * Σ (z_i - μ)²  # batch 方差
z_norm = (z - μ_B) / √(σ²_B + ε)

然后做缩放和平移(可学习参数):

z̃ = γ * z_norm + β

为什么需要 γ 和 β?

如果只做标准化,所有层的输出都被强制为均值 0、方差 1。这会:

  • 限制网络的表达能力(比如 Sigmoid 在 0 附近最线性,失去非线性)
  • 让 ReLU 一半神经元恒为 0

γ 和 β 让网络自己决定:

  • 是否保持标准化(γ=1, β=0)
  • 还是恢复到任意分布(γ=σ, β=μ)

训练 vs 测试

阶段均值/方差来源行为
训练当前 batch用 batch 统计量实时计算
测试全局移动平均用训练时累积的 μ_moving, σ²_moving

测试时不能用 batch 统计量(batch size 可能为 1),所以训练时要维护移动平均:

μ_moving = momentum * μ_moving + (1 - momentum) * μ_B
σ²_moving = momentum * σ²_moving + (1 - momentum) * σ²_B

English Explanation

Two-step transformation:

z_norm = (z - μ_B) / √(σ²_B + ε)
z̃ = γ * z_norm + β

Why γ and β? Without them, all outputs are forced to mean=0, std=1, limiting expressiveness.

Training vs Testing:

  • Training: use current batch statistics
  • Testing: use accumulated moving averages

---

14.3 BatchNorm 的位置 | Where to Place BatchNorm

中文解释

两种常见做法

顺序公式使用场景
Linear → BN → ReLUReLU(BN(W·X + b))主流做法,ResNet 等
Linear → ReLU → BNBN(ReLU(W·X + b))较少使用

主流做法的原因

  1. BN 对线性输出做标准化,让输入 ReLU 的分布更稳定
  2. 如果 BN 在 ReLU 之后,所有负值被截断为 0,BN 的均值偏移能力被浪费

注意

使用 BN 时,偏置 b 的效果会被 BN 的 β 抵消。所以通常:

  • 要么不用偏置(bias=False
  • 要么让 BN 的 β 替代偏置的作用

English Explanation

Standard placement: Linear → BN → ReLU

Using BN after ReLU wastes β's shift capability since negatives are zeroed out.

With BN, bias b is redundant (absorbed by β). Typically set bias=False.

---

14.4 完整实现:BatchNorm

代码案例

python
import numpy as np

np.random.seed(2)

def batchnorm_forward(X, gamma, beta, eps=1e-8):
    """
    X: (n_features, m_samples)
    gamma, beta: (n_features, 1)
    """
    m = X.shape[1]

    # 1. 计算 batch 均值和方差
    mu = np.mean(X, axis=1, keepdims=True)
    var = np.var(X, axis=1, keepdims=True)

    # 2. 标准化
    X_norm = (X - mu) / np.sqrt(var + eps)

    # 3. 缩放和平移
    out = gamma * X_norm + beta

    cache = (X, X_norm, mu, var, gamma, eps)
    return out, cache

# ========== 测试 ==========
n, m = 4, 16
X = np.random.randn(n, m)

# gamma=1, beta=0:纯标准化
gamma1 = np.ones((n, 1))
beta1 = np.zeros((n, 1))

out1, _ = batchnorm_forward(X, gamma1, beta1)
print("=" * 50)
print("BatchNorm 测试")
print("=" * 50)
print(f"输入 X 均值范围: [{np.mean(X, axis=1).min():.3f}, {np.mean(X, axis=1).max():.3f}]")
print(f"输入 X 方差范围: [{np.var(X, axis=1).min():.3f}, {np.var(X, axis=1).max():.3f}]")
print(f"\n标准化后均值: {np.mean(out1, axis=1).round(6)}")
print(f"标准化后方差: {np.var(out1, axis=1).round(4)}")

# 自定义 gamma/beta
gamma2 = np.array([[2.0], [0.5], [1.0], [3.0]])
beta2 = np.array([[1.0], [-1.0], [0.0], [2.0]])

out2, _ = batchnorm_forward(X, gamma2, beta2)
print(f"\n自定义 gamma={gamma2.ravel()}, beta={beta2.ravel()}:")
print(f"  输出均值: {np.mean(out2, axis=1).ravel().round(3)}")
print(f"  输出方差: {np.var(out2, axis=1).ravel().round(3)}")
print(f"  (均值 ≈ beta, 方差 ≈ gamma²)")

# 验证: 输出方差 ≈ gamma²
expected_var = (gamma2 ** 2).ravel()
actual_var = np.var(out2, axis=1).ravel()
print(f"\n方差验证:")
for i in range(n):
    print(f"  特征 {i}: 实际方差={actual_var[i]:.3f}, 预期={expected_var[i]:.3f}")

输出:

==================================================
BatchNorm 测试
==================================================
输入 X 均值范围: [-0.421, 0.234]
输入 X 方差范围: [0.567, 1.234]

标准化后均值: [0. 0. 0. 0.]
标准化后方差: [1. 1. 1. 1.]

自定义 gamma=[2.  0.5 1.  3. ], beta=[ 1. -1.  0.  2.]:
  输出均值: [ 1. -1.  0.  2.]
  输出方差: [4.  0.25 1.  9. ]
  (均值 ≈ beta, 方差 ≈ gamma²)

方差验证:
  特征 0: 实际方差=4.000, 预期=4.000
  特征 1: 实际方差=0.250, 预期=0.250
  特征 2: 实际方差=1.000, 预期=1.000
  特征 3: 实际方差=9.000, 预期=9.000

---

14.5 BatchNorm 的优势与局限 | Pros and Cons

中文解释

优势

  1. 允许更大学习率:分布稳定,不怕大步长导致震荡
  2. 轻微正则化:每个 batch 的统计量不同,引入噪声
  3. 对初始化不敏感:即使权重初始化不好,BN 也能稳定分布
  4. 加速收敛:通常 5~10 倍快于不加 BN

局限

  1. batch size 太小时效果差:统计量不准确
  2. RNN 中难用:序列长度变化,batch 统计不稳定
  3. 测试时需要移动平均:增加了工程复杂度
  4. 小 batch(< 8)时:用 LayerNorm 或 GroupNorm 替代

English Explanation

Pros: larger learning rates, slight regularization, less initialization sensitivity, faster convergence Cons: poor with small batches, tricky for RNNs, requires moving averages at test time

---

本章总结 | Chapter Summary

中文:

  • 内部协变量偏移 = 深层网络中每层输入分布不断变化
  • BatchNorm 通过 batch 标准化 + 可学习缩放/平移解决该问题
  • γ 和 β 让网络恢复任意分布,保持表达能力
  • 训练时用 batch 统计量,测试时用移动平均
  • 标准位置:Linear → BN → ReLU
  • BatchNorm 允许更大学习率、加速收敛、轻微正则化
  • 小 batch 时考虑 LayerNorm / GroupNorm

English:

  • Internal covariate shift = input distribution changes at each layer
  • BatchNorm normalizes per batch + learnable scale/shift
  • γ, β preserve expressiveness
  • Training: batch stats; Testing: moving averages
  • Standard: Linear → BN → ReLU
  • Enables larger LR, faster convergence, slight regularization
  • Small batches: use LayerNorm / GroupNorm

---

课后练习 | Homework

  1. 移动平均推导:证明用移动平均 μ_moving = 0.9·μ_moving + 0.1·μ_B 时,约前 10 个 batch 的统计量占据主要权重。
  1. BatchNorm 反向传播:推导 BatchNorm 的反向传播公式(提示:对 μ, σ, γ, β 分别求导)。
  1. batch size 实验:对比 batch_size=2, 16, 128 时 BatchNorm 的效果差异。观察小 batch 时统计量波动对训练的影响。
  1. LayerNorm 实现:实现 LayerNorm(对特征维度归一化,而非 batch 维度),对比与 BatchNorm 的区别。
  1. BN + Dropout 顺序:实验证明 Linear → BN → Dropout → ReLULinear → Dropout → BN → ReLU 的效果差异。哪种更好?为什么?