共计 1193 个字符,预计需要花费 3 分钟才能阅读完成。
神经网络的数据流动可视化
我们先从一个三层的 BP 神经网络框架图开始理解(假设输入层、隐藏层、输出层节点数分别为 n、m、k):

输入 x ∈ Rⁿ → 隐藏层 W₁∈Rⁿˣᵐ → Sigmoid → 输出层 W₂∈Rᵐˣᵏ → Sigmoid → 预测值 ŷ
↑ ↑ ↑
δ₂=g'(z₂)∘(ŷ-y) δ₁=g'(z₁)∘(W₂ᵀδ₂)
矩阵维度变化规律:
- 前向传播时:
(batch_size, n) × (n, m) → (batch_size, m) - 反向传播时:
δ₂ ∈ Rᵏ会通过W₂ᵀ ∈ Rᵏˣᵐ反向传播到隐藏层
核心实现细节
1. Sigmoid 的数值稳定性处理
传统实现直接套公式会导致数值溢出:
def unsafe_sigmoid(x):
return 1 / (1 + np.exp(-x)) # 当 x <-100 时返回 0
改进方案添加边界判断:
def safe_sigmoid(x):
mask = x >= 0
positive = 1 / (1 + np.exp(-x[mask]))
negative = np.exp(x[~mask]) / (1 + np.exp(x[~mask]))
return np.concatenate([positive, negative])
2. 向量化梯度计算对比
循环版本(慢):
for i in range(batch_size):
grad_W += X[i].T.dot(delta[i]) # 每次处理单个样本
矩阵版本(快 10 倍):
grad_W = X.T.dot(delta) / batch_size # 一次性计算所有样本
3. 学习率衰减策略
余弦退火示例:
lr = base_lr * (1 + math.cos(epoch * math.pi / max_epoch)) / 2
避坑实践指南
权重初始化
- Xavier 初始化:
W = np.random.randn(n, m) * np.sqrt(2/(n+m)) - 适用于 Sigmoid/Tanh 的变种:
scale = np.sqrt(6/(n+m))
梯度检查
用数值梯度验证解析梯度:
def check_grad(W, f, eps=1e-5):
analytical_grad = compute_grad(W)
numerical_grad = (f(W+eps) - f(W-eps)) / (2*eps)
return np.allclose(analytical_grad, numerical_grad)
性能优化技巧
Numba 加速
from numba import jit
@jit(nopython=True)
def forward(x, W):
return x.dot(W) # 编译为机器码
内存映射大文件
X = np.memmap('data.bin', dtype='float32',
mode='r', shape=(1e6, 1000))
思考题延伸
当使用 ReLU 时:
- 反向传播路径中:
δ₁ = (W₂ᵀδ₂) * (z₁ > 0) - 需要调整初始化策略(He 初始化)
- 框架图中需增加对负梯度的截断处理
完整实现代码见:[GitHub 链接]
正文完
