跳转至

05 - 反向传播算法

反向传播原理

反向传播算法流程

图注:反向传播算法流程图,展示前向传播和反向传播的完整过程

重要性: ⭐⭐⭐⭐⭐ 实用度: ⭐⭐⭐⭐⭐ 学习时间: 4小时 必须掌握: 是


为什么学这一章?

反向传播是训练神经网络的核心算法。理解它能帮助你: - 真正理解神经网络是如何学习的 - 调试训练过程中的梯度问题 - 实现自定义的层和损失函数 - 理解自动微分的原理

学完这一章,你将能够: - ✅ 理解链式法则在神经网络中的应用 - ✅ 手动推导简单网络的反向传播 - ✅ 实现完整的反向传播算法 - ✅ 进行梯度检查验证正确性 - ✅ 理解自动微分的基本原理


📖 计算图与链式法则

计算图:前向传播vs反向传播

图注:计算图可视化,展示前向传播(数据流动)和反向传播(梯度流动)的对比

什么是计算图?

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    计算图:可视化计算过程                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  示例:计算 z = (x + y) × w                                          │
│                                                                     │
│       x ──┐                                                         │
│             ├──→ [+] ──→ a ──┐                                      │
│       y ──┘                  ├──→ [×] ──→ z                         │
│       w ─────────────────────┘                                      │
│                                                                     │
│  节点:变量或操作                                                     │
│  边:数据流动方向                                                     │
│                                                                     │
│  前向传播:从左到右计算                                                │
│  反向传播:从右到左计算梯度                                            │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

链式法则

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    链式法则 - 反向传播的核心                           │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  单变量链式法则:                                                     │
│  dz/dx = dz/dy · dy/dx                                              │
│                                                                     │
│  多变量链式法则:                                                     │
│  如果 z = f(x,y),x = g(t),y = h(t)                                 │
│  则 dz/dt = ∂z/∂x · dx/dt + ∂z/∂y · dy/dt                           │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  直观理解:                                                    │   │
│  │                                                              │   │
│  │  想象一条河流:                                                │   │
│  │  上游流量变化 = 中游流量变化 × 下游流量变化                     │   │
│  │                                                              │   │
│  │  梯度就是流量的变化率                                          │   │
│  │  反向传播就是逐层传递这个变化率                                  │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  示例:                                                              │
│  f(x) = (x + 1)²                                                    │
│  令 u = x + 1,则 f = u²                                            │
│  df/dx = df/du · du/dx = 2u · 1 = 2(x + 1)                          │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

🔧 反向传播详解

神经网络中的梯度流动

图注:神经网络中的梯度流动,蓝色箭头表示前向传播,橙色箭头表示反向传播(梯度流动)

简单示例

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    反向传播示例:z = x × y + w                       │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  计算图:                                                            │
│                                                                     │
│  x(2) ──┐              前向传播                                      │
│          ├──→ [×] ──→ a(6) ──┐      a = x × y = 2 × 3 = 6          │
│  y(3) ──┘                    ├──→ [+] ──→ z(10)  z = a + w = 6+4=10 │
│  w(4) ───────────────────────┘                                      │
│                                                                     │
│  ─────────────────────────────────────────────────────────────────  │
│                                                                     │
│  反向传播(假设 ∂L/∂z = 1):                                         │
│                                                                     │
│  1. ∂L/∂z = 1                                                       │
│                                                                     │
│  2. z = a + w                                                       │
│     ∂L/∂a = ∂L/∂z · ∂z/∂a = 1 × 1 = 1                               │
│     ∂L/∂w = ∂L/∂z · ∂z/∂w = 1 × 1 = 1                               │
│                                                                     │
│  3. a = x × y                                                       │
│     ∂L/∂x = ∂L/∂a · ∂a/∂x = 1 × y = 3                               │
│     ∂L/∂y = ∂L/∂a · ∂a/∂y = 1 × x = 2                               │
│                                                                     │
│  结果:                                                              │
│  ∂L/∂x = 3, ∂L/∂y = 2, ∂L/∂w = 1                                   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

神经网络中的反向传播

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    神经网络的反向传播                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  网络结构:输入 → 线性 → ReLU → 线性 → Softmax → 输出                 │
│                                                                     │
│  前向传播:                                                          │
│  z₁ = X·W₁ + b₁                                                     │
│  h = ReLU(z₁)                                                       │
│  z₂ = h·W₂ + b₂                                                     │
│  ŷ = Softmax(z₂)                                                    │
│  L = CrossEntropy(ŷ, y)                                             │
│                                                                     │
│  ─────────────────────────────────────────────────────────────────  │
│                                                                     │
│  反向传播(从后往前):                                                │
│                                                                     │
│  1. 输出层梯度(Softmax + CrossEntropy):                            │
│     ∂L/∂z₂ = ŷ - y    (简洁形式!)                                 │
│                                                                     │
│  2. 第二层参数梯度:                                                  │
│     ∂L/∂W₂ = hᵀ · ∂L/∂z₂                                            │
│     ∂L/∂b₂ = Σ ∂L/∂z₂                                               │
│                                                                     │
│  3. 隐藏层梯度:                                                      │
│     ∂L/∂h = ∂L/∂z₂ · W₂ᵀ                                            │
│     ∂L/∂z₁ = ∂L/∂h ⊙ ReLU'(z₁)    (逐点乘,ReLU导数)               │
│                                                                     │
│  4. 第一层参数梯度:                                                  │
│     ∂L/∂W₁ = Xᵀ · ∂L/∂z₁                                            │
│     ∂L/∂b₁ = Σ ∂L/∂z₁                                               │
│                                                                     │
│  关键:梯度从输出层向输入层逐层传播!                                  │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

🧮 手动推导示例

反向传播示例:z = x × y + w

图注:反向传播的具体示例,展示如何通过链式法则计算梯度

两层网络完整推导

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    两层网络反向传播完整推导                            │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  网络:                                                              │
│  输入 X (1×2) → W₁ (2×3) → ReLU → W₂ (3×2) → Softmax → 输出         │
│                                                                     │
│  给定:                                                              │
│  X = [1, 2]                                                         │
│  W₁ = [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]]                           │
│  W₂ = [[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]]                         │
│  y = [1, 0]  (类别0)                                              │
│                                                                     │
│  ─────────────────────────────────────────────────────────────────  │
│                                                                     │
│  前向传播:                                                          │
│                                                                     │
│  z₁ = X·W₁ = [1, 2] · [[0.1, 0.2, 0.3],                            │
│                       [0.4, 0.5, 0.6]]                              │
│      = [0.9, 1.2, 1.5]                                              │
│                                                                     │
│  h = ReLU(z₁) = [0.9, 1.2, 1.5]                                     │
│                                                                     │
│  z₂ = h·W₂ = [0.9, 1.2, 1.5] · [[0.1, 0.2],                        │
│                                 [0.3, 0.4],                         │
│                                 [0.5, 0.6]]                         │
│      = [1.20, 1.56]                                                 │
│                                                                     │
│  ŷ = Softmax(z₂) = [0.41, 0.59]                                     │
│                                                                     │
│  L = -log(0.41) = 0.89                                              │
│                                                                     │
│  ─────────────────────────────────────────────────────────────────  │
│                                                                     │
│  反向传播:                                                          │
│                                                                     │
│  1. ∂L/∂z₂ = ŷ - y = [0.41-1, 0.59-0] = [-0.59, 0.59]              │
│                                                                     │
│  2. ∂L/∂W₂ = hᵀ · ∂L/∂z₂                                           │
│            = [[0.9],   · [-0.59, 0.59]                              │
│               [1.2],                                                │
│               [1.5]]                                                │
│            = [[-0.53, 0.53],                                        │
│               [-0.71, 0.71],                                        │
│               [-0.89, 0.89]]                                        │
│                                                                     │
│  3. ∂L/∂h = ∂L/∂z₂ · W₂ᵀ                                           │
│           = [-0.59, 0.59] · [[0.1, 0.3, 0.5],                      │
│                               [0.2, 0.4, 0.6]]                      │
│           = [0.059, 0.059, 0.059]                                   │
│                                                                     │
│  4. ∂L/∂z₁ = ∂L/∂h ⊙ ReLU'(z₁)                                     │
│            = [0.059, 0.059, 0.059] ⊙ [1, 1, 1]                      │
│            = [0.059, 0.059, 0.059]   (z₁都>0)                     │
│                                                                     │
│  5. ∂L/∂W₁ = Xᵀ · ∂L/∂z₁                                           │
│            = [[1], · [0.059, 0.059, 0.059]                          │
│               [2]]                                                  │
│            = [[0.059, 0.059, 0.059],                                │
│               [0.118, 0.118, 0.118]]                                │
│                                                                     │
│  ✅ 完成!现在可以用这些梯度更新参数了!                                │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

✅ 梯度检查

数值梯度验证

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    梯度检查:验证反向传播正确性                         │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  原理:用数值梯度近似解析梯度,对比两者是否接近                         │
│                                                                     │
│  数值梯度公式(中心差分):                                            │
│  ∂f/∂x ≈ [f(x+ε) - f(x-ε)] / (2ε)                                   │
│                                                                     │
│  Python实现:                                                        │
│                                                                     │
│  def numerical_gradient(f, x, epsilon=1e-5):                        │
│      """                                                            │
│      计算函数f在点x处的数值梯度                                       │
│      f: 函数                                                         │
│      x: numpy数组,计算梯度的位置                                     │
│      """                                                            │
│      grad = np.zeros_like(x)                                        │
│      it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])│
│                                                                     │
│      while not it.finished:                                         │
│          idx = it.multi_index                                       │
│          old_val = x[idx]                                           │
│                                                                     │
│          # f(x + epsilon)                                           │
│          x[idx] = old_val + epsilon                                 │
│          fx_plus = f(x)                                             │
│                                                                     │
│          # f(x - epsilon)                                           │
│          x[idx] = old_val - epsilon                                 │
│          fx_minus = f(x)                                            │
│                                                                     │
│          # 中心差分                                                   │
│          grad[idx] = (fx_plus - fx_minus) / (2 * epsilon)           │
│                                                                     │
│          # 恢复原始值                                                 │
│          x[idx] = old_val                                           │
│          it.iternext()                                              │
│                                                                     │
│      return grad                                                    │
│                                                                     │
│  ─────────────────────────────────────────────────────────────────  │
│                                                                     │
│  使用示例:                                                          │
│                                                                     │
│  # 定义损失函数(关于W的函数)                                        │
│  def loss_fn(W):                                                    │
│      model.W1 = W                                                   │
│      y_pred = model.forward(X)                                      │
│      return model.compute_loss(y_pred, y)                           │
│                                                                     │
│  # 计算数值梯度                                                       │
│  num_grad = numerical_gradient(loss_fn, model.W1)                   │
│                                                                     │
│  # 计算解析梯度(反向传播)                                            │
│  y_pred = model.forward(X)                                          │
│  grads = model.backward(y)                                          │
│  ana_grad = grads['W1']                                             │
│                                                                     │
│  # 比较两者                                                           │
│  diff = np.linalg.norm(num_grad - ana_grad) /                       │
│         (np.linalg.norm(num_grad) + np.linalg.norm(ana_grad))       │
│                                                                     │
│  print(f"相对误差: {diff}")                                          │
│  # 如果 diff < 1e-7,说明反向传播实现正确!                           │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

🤖 自动微分简介

什么是自动微分?

Text Only
┌─────────────────────────────────────────────────────────────────────┐
│                    自动微分(Automatic Differentiation)             │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  自动微分 = 计算机自动计算梯度                                         │
│                                                                     │
│  三种计算导数的方法:                                                  │
│                                                                     │
│  1. 符号微分(Symbolic Diff)                                         │
│     • 用代数规则推导导数公式                                           │
│     • 优点:精确                                                      │
│     • 缺点:表达式膨胀,难以处理控制流                                  │
│                                                                     │
│  2. 数值微分(Numerical Diff)                                        │
│     • 用差分近似(f(x+h)-f(x))/h                                     │
│     • 优点:简单                                                      │
│     • 缺点:精度低,计算量大                                           │
│                                                                     │
│  3. 自动微分(Automatic Diff)⭐                                       │
│     • 基于链式法则,在计算图中反向传播                                   │
│     • 优点:精确、高效、通用                                           │
│     • 缺点:需要记录中间结果                                           │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  深度学习框架的自动微分:                                       │   │
│  │                                                              │   │
│  │  PyTorch: 动态计算图,反向传播时自动计算梯度                     │   │
│  │  TensorFlow: 静态/动态计算图,tf.GradientTape                  │   │
│  │  JAX: 函数变换,jit、grad、vmap                                │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

PyTorch自动微分示例

Python
import torch

# 创建需要梯度的张量
x = torch.tensor([2.0, 3.0], requires_grad=True)
w = torch.tensor([1.0, 2.0], requires_grad=True)
b = torch.tensor(1.0, requires_grad=True)

# 前向传播
y = torch.sum(x * w) + b  # y = 2*1 + 3*2 + 1 = 9

# 反向传播
y.backward()

# 查看梯度
print(f"x.grad = {x.grad}")  # tensor([1., 2.])
print(f"w.grad = {w.grad}")  # tensor([2., 3.])
print(f"b.grad = {b.grad}")  # tensor(1.)

# 验证:
# y = x₁w₁ + x₂w₂ + b
# ∂y/∂x₁ = w₁ = 1
# ∂y/∂x₂ = w₂ = 2
# ∂y/∂w₁ = x₁ = 2
# ∂y/∂w₂ = x₂ = 3
# ∂y/∂b = 1

💡 核心要点总结

反向传播关键步骤

  1. 前向传播:计算每一层的输出,保存中间结果
  2. 计算输出层梯度:根据损失函数计算
  3. 反向传播梯度:从后向前,用链式法则计算每层梯度
  4. 计算参数梯度:用上游梯度和本地梯度相乘
  5. 更新参数:用梯度下降更新权重

调试技巧

  • 梯度检查:用数值梯度验证解析梯度
  • 打印梯度:检查梯度大小和分布
  • 可视化:画出计算图帮助理解
  • 简化网络:先用小网络验证正确性

❓ 常见问题

Q1:为什么反向传播比前向传播慢?

A:反向传播需要: - 保存前向传播的中间结果(占用内存) - 计算并传播梯度(计算量类似前向) - 实际中两者时间相近

Q2:梯度消失怎么解决?

A: - 使用ReLU等激活函数 - 残差连接(ResNet) - 批归一化(BatchNorm) - 更好的初始化

Q3:梯度爆炸怎么解决?

A: - 梯度裁剪(Gradient Clipping) - 更小的学习率 - 权重正则化 - 批归一化

Q4:为什么要用链式法则?

A:神经网络是复合函数,链式法则是计算复合函数导数的唯一有效方法。


📝 自测问题

  1. 什么是链式法则?为什么在神经网络中需要它?
  2. 手动推导一个两层网络的反向传播过程。
  3. 为什么要进行梯度检查?
  4. 自动微分相比数值微分有什么优势?
  5. 如果反向传播实现错误,可能出现什么问题?

📚 扩展阅读

  1. 《Learning representations by back-propagating errors》 - Rumelhart et al. (1986) - 反向传播原始论文
  2. PyTorch Autograd文档 - 理解自动微分实现
  3. CS231n Lecture 4 - Backpropagation

🎯 下一步

恭喜完成第一阶段!现在你可以: 1. 完成 实践-手写神经网络 项目 2. 开始第二阶段 02-CNN 的学习

你已经掌握了深度学习的基础,继续加油!🎉