第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 layersW^[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) |
|---|---|
| Sigmoid | A * (1 - A) |
| ReLU | (Z > 0).astype(float) |
| Tanh | 1 - 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 / Glorot | W ~ N(0, 1/n_in) | Sigmoid, Tanh |
| He | W ~ N(0, 2/n_in) | ReLU |
推导直觉
我们希望每层的输出方差 ≈ 输入方差,防止信号在深层网络中放大或衰减。
对于 ReLU,大约一半的神经元被置为 0,所以方差会减半。He 初始化用 2/n_in 来补偿这个减半。
English Explanation
| Method | Formula | For Activation |
|---|---|---|
| Xavier | W ~ N(0, 1/n_in) | Sigmoid, Tanh |
| He | W ~ 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
- 手写 5 层网络:不参考代码,独立写出 5 层全连接网络(每层维度自定)的参数初始化、前向传播、反向传播。
- 初始化对比:对比全 0 初始化、标准正态、Xavier、He 四种初始化在 10 层网络上的梯度范数变化。
- 维度追踪:对网络 [10, 20, 15, 5, 3, 1],写出每一层 Z, A, dZ, dW, dA 的完整维度。
- 数值梯度检查:用有限差分法(
[f(w+ε) - f(w-ε)] / 2ε)验证你写的反向传播梯度是否正确。
- 深度与宽度:固定总参数量(如 1000),对比"深而窄"(如 [10,8,6,4,2,1])和"浅而宽"(如 [10,50,1])的网络在相同数据上的表现。