SilverIce Toolbox
Back to course

Stage 3 / Chapter 11

第11章:深层神经网络 | Chapter 11: Deep Neural Networks

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

---

学习目标 | Learning Objectives

中文:

  • 掌握 L 层神经网络的通用前向传播实现
  • 理解反向传播的通用模式:dZ → dW, db → dA_prev
  • 掌握参数维度的系统化检查方法
  • 理解权重初始化对深层网络训练的重要性
  • 能手写任意深度的全连接网络前向+反向传播

English:

  • Master generic forward propagation for L-layer networks
  • Understand backprop pattern: dZ → dW, db → dA_prev
  • Master systematic parameter dimension checking
  • Understand weight initialization importance for deep networks
  • Implement forward + backward propagation for arbitrarily deep networks

---

11.1 深层网络的表示 | Deep Network Representation

中文解释

符号约定

符号含义维度
L网络总层数(不含输入层)
n^[l]第 l 层的神经元数量
W^[l]第 l 层的权重矩阵(n^[l], n^[l-1])
b^[l]第 l 层的偏置向量(n^[l], 1)
Z^[l]第 l 层的线性输出(n^[l], m)
A^[l]第 l 层的激活输出(n^[l], m)
A^[0]输入层 = X(n^[0], m)

一个 4 层网络的例子

输入层:   n^[0] = 5    (A^[0] = X)
隐藏层1:  n^[1] = 4    (ReLU)
隐藏层2:  n^[2] = 3    (ReLU)
隐藏层3:  n^[3] = 2    (ReLU)
输出层:   n^[4] = 1    (Sigmoid)

参数总数:

W1: (4, 5), b1: (4, 1)   → 20 + 4 = 24
W2: (3, 4), b2: (3, 1)   → 12 + 3 = 15
W3: (2, 3), b3: (2, 1)   → 6 + 2 = 8
W4: (1, 2), b4: (1, 1)   → 2 + 1 = 3
总计: 50 个参数

English Explanation

Notation:

  • L: total number of layers
  • W^[l]: (n^[l], n^[l-1])
  • b^[l]: (n^[l], 1)
  • A^[l]: (n^[l], m)

---

11.2 通用前向传播 | Generic Forward Propagation

中文解释

循环结构

python
A = X
caches = []
for l in range(1, L+1):
    Z = W[l] @ A + b[l]
    A = ReLU(Z) if l < L else Sigmoid(Z)
    caches.append((A_prev, W[l], b[l], Z))

关键洞察

前向传播可以用一个循环统一处理所有层:

  • 隐藏层(l < L):用 ReLU
  • 输出层(l = L):用 Sigmoid(或 Softmax)

每层的操作完全相同:线性变换 + 激活。

English Explanation

Generic Pattern:

For each layer l:
  Z^[l] = W^[l] · A^[l-1] + b^[l]
  A^[l] = g(Z^[l])

Hidden layers: ReLU. Output layer: Sigmoid/Softmax.

---

11.3 通用反向传播 | Generic Backpropagation

中文解释

通用模式

对于任意层 l:

输入: dA^[l] (从右边传过来的梯度)
输出: dW^[l], db^[l], dA^[l-1] (传给左边的梯度)

步骤:
1. dZ^[l] = dA^[l] * g'(Z^[l])
2. dW^[l] = (1/m) * dZ^[l] · A^[l-1].T
3. db^[l] = (1/m) * sum(dZ^[l], axis=1, keepdims=True)
4. dA^[l-1] = W^[l].T · dZ^[l]

激活函数导数

激活函数导数 g'(Z)
SigmoidA * (1 - A)
ReLU(Z > 0).astype(float)
Tanh1 - A²

反向传播流程

从输出层开始:
  dA[L] = -(Y/A - (1-Y)/(1-A))
  
for l = L, L-1, ..., 1:
  dZ[l] = dA[l] * g'(Z[l])
  dW[l] = (1/m) * dZ[l] @ A[l-1].T
  db[l] = (1/m) * sum(dZ[l])
  dA[l-1] = W[l].T @ dZ[l]

English Explanation

Generic Backprop Pattern:

dZ^[l] = dA^[l] ⊙ g'(Z^[l])
dW^[l] = (1/m) · dZ^[l] · A^[l-1].T
db^[l] = (1/m) · sum(dZ^[l])
dA^[l-1] = W^[l].T · dZ^[l]

---

11.4 权重初始化 | Weight Initialization

中文解释

为什么初始化重要?

深层网络中,如果初始权重太大:

  • Z 值很大 → Sigmoid/Tanh 饱和 → 梯度消失

如果初始权重太小:

  • Z 值接近 0 → 激活输出都相同 → 对称性破不掉 → 学习停滞

常用初始化方法

方法公式适用激活函数
Xavier / GlorotW ~ N(0, 1/n_in)Sigmoid, Tanh
HeW ~ N(0, 2/n_in)ReLU

推导直觉

我们希望每层的输出方差 ≈ 输入方差,防止信号在深层网络中放大或衰减。

对于 ReLU,大约一半的神经元被置为 0,所以方差会减半。He 初始化用 2/n_in 来补偿这个减半。

English Explanation

MethodFormulaFor Activation
XavierW ~ N(0, 1/n_in)Sigmoid, Tanh
HeW ~ N(0, 2/n_in)ReLU

Intuition: keep output variance ≈ input variance to prevent signal amplification or decay.

---

11.5 完整实现:L 层网络

代码案例

python
import numpy as np

np.random.seed(3)

# ========== 辅助函数 ==========
def relu(z):
    return np.maximum(0, z)

def relu_derivative(z):
    return (z > 0).astype(float)

def sigmoid(z):
    return 1 / (1 + np.exp(-np.clip(z, -500, 500)))

# ========== 1. 初始化参数 ==========
def initialize_parameters(layer_dims):
    """
    layer_dims: [n0, n1, n2, ..., nL]
    返回: parameters 字典
    """
    np.random.seed(3)
    parameters = {}
    L = len(layer_dims) - 1

    for l in range(1, L + 1):
        # He 初始化 (适用于 ReLU)
        parameters[f'W{l}'] = np.random.randn(
            layer_dims[l], layer_dims[l-1]
        ) * np.sqrt(2.0 / layer_dims[l-1])
        parameters[f'b{l}'] = np.zeros((layer_dims[l], 1))

    return parameters

# ========== 2. 前向传播 ==========
def forward_propagation(X, parameters):
    """
    返回: 最终输出 AL, 缓存列表 caches
    """
    caches = []
    A = X
    L = len(parameters) // 2

    for l in range(1, L + 1):
        W = parameters[f'W{l}']
        b = parameters[f'b{l}']
        A_prev = A

        Z = np.dot(W, A_prev) + b

        # 输出层用 Sigmoid,隐藏层用 ReLU
        if l == L:
            A = sigmoid(Z)
        else:
            A = relu(Z)

        caches.append((A_prev, W, b, Z))

    return A, caches

# ========== 3. 反向传播 ==========
def backward_propagation(AL, Y, caches):
    """
    返回: gradients 字典
    """
    gradients = {}
    L = len(caches)
    m = AL.shape[1]

    # 输出层梯度
    dAL = -(np.divide(Y, AL + 1e-8) - np.divide(1 - Y, 1 - AL + 1e-8))
    dA = dAL

    for l in reversed(range(1, L + 1)):
        A_prev, W, b, Z = caches[l-1]

        # 激活函数导数
        if l == L:
            dZ = dA * (AL * (1 - AL))  # Sigmoid
        else:
            dZ = dA * relu_derivative(Z)

        dW = (1/m) * np.dot(dZ, A_prev.T)
        db = (1/m) * np.sum(dZ, axis=1, keepdims=True)
        dA = np.dot(W.T, dZ)

        gradients[f'dW{l}'] = dW
        gradients[f'db{l}'] = db

    return gradients

# ========== 4. 测试 ==========
layer_dims = [5, 4, 3, 1]  # 3层网络 (2 hidden + 1 output)
params = initialize_parameters(layer_dims)

print("=" * 50)
print("L 层网络参数初始化")
print("=" * 50)
for l in range(1, len(layer_dims)):
    print(f"  W{l}: {params[f'W{l}'].shape}, b{l}: {params[f'b{l}'].shape}")

# 模拟数据
m = 2
X = np.random.randn(5, m)
Y = np.array([[1, 0]])

# 前向
AL, caches = forward_propagation(X, params)
print(f"\n前向传播完成: A{L} = {AL.shape}")

# 反向
grads = backward_propagation(AL, Y, caches)
print(f"\n反向传播完成:")
for l in range(1, len(layer_dims)):
    print(f"  dW{l}: {grads[f'dW{l}'].shape}, db{l}: {grads[f'db{l}'].shape}")

# 维度验证
print("\n维度验证:")
all_match = True
for l in range(1, len(layer_dims)):
    if params[f'W{l}'].shape != grads[f'dW{l}'].shape:
        print(f"  ✗ Layer {l}: W{l} {params[f'W{l}'].shape} != dW{l} {grads[f'dW{l}'].shape}")
        all_match = False
if all_match:
    print("  ✓ 所有梯度维度与参数维度匹配")

输出:

==================================================
L 层网络参数初始化
==================================================
  W1: (4, 5), b1: (4, 1)
  W2: (3, 4), b2: (3, 1)
  W3: (1, 3), b3: (1, 1)

前向传播完成: A3 = (1, 2)

反向传播完成:
  dW1: (4, 5), db1: (4, 1)
  dW2: (3, 4), db2: (3, 1)
  dW3: (1, 3), db3: (1, 1)

维度验证:
  ✓ 所有梯度维度与参数维度匹配

---

11.6 常见误区 | Common Pitfalls

1. 忘记除以 batch size m

dW = dZ @ A_prev.T 后必须除以 m,否则梯度大小随 batch size 变化。

2. 激活函数导数用错层

输出层用 Sigmoid 导数,隐藏层用 ReLU 导数。不要搞混。

3. 维度广播的隐性 bug

b(n, 1)Z(n, m)。NumPy 广播会自动把 b 复制 m 列。但如果 b(n,),广播行为会不同,导致静默错误。

---

本章总结 | Chapter Summary

中文:

  • 深层网络 = 多层线性变换 + 非线性激活的堆叠
  • 前向传播和反向传播都可以用循环统一实现任意深度
  • 反向传播通用模式:dZ = dA * g'(Z) → dW, db → dA_prev = W.T @ dZ
  • He 初始化(sqrt(2/n_in))是 ReLU 网络的标准初始化
  • 维度检查是调试的第一防线

English:

  • Deep network = stack of linear transforms + nonlinear activations
  • Forward and backward can both be looped for arbitrary depth
  • Backprop pattern: dZ = dA * g'(Z) → dW, db → dA_prev = W.T @ dZ
  • He initialization (sqrt(2/n_in)) is standard for ReLU networks
  • Dimension checking is the first defense against bugs

---

课后练习 | Homework

  1. 手写 5 层网络:不参考代码,独立写出 5 层全连接网络(每层维度自定)的参数初始化、前向传播、反向传播。
  1. 初始化对比:对比全 0 初始化、标准正态、Xavier、He 四种初始化在 10 层网络上的梯度范数变化。
  1. 维度追踪:对网络 [10, 20, 15, 5, 3, 1],写出每一层 Z, A, dZ, dW, dA 的完整维度。
  1. 数值梯度检查:用有限差分法([f(w+ε) - f(w-ε)] / 2ε)验证你写的反向传播梯度是否正确。
  1. 深度与宽度:固定总参数量(如 1000),对比"深而窄"(如 [10,8,6,4,2,1])和"浅而宽"(如 [10,50,1])的网络在相同数据上的表现。