957 字
5 分钟
神经网络反向传播
神经网络反向传播
1. 为什么需要反向传播?
类比:考试考砸了,你要找出是哪道题出了问题,再追溯是哪个知识点没掌握好。反向传播就是从”最终损失”出发,逐层追溯每个参数对损失的”责任大小”(梯度)。
前向传播计算预测值,反向传播计算梯度,两者配合完成一次参数更新。
2. 核心工具:链式法则1
若 是 的函数, 是 的函数,则:
多层网络中,梯度从输出层向输入层逐层相乘传递,这就是”反向传播”名字的由来。
3. 单层推导示例
以一个两层网络(隐藏层 ReLU + 输出层 Sigmoid + 二元交叉熵损失)为例:
前向:
反向(从输出层往回推):
表示逐元素相乘(Hadamard 积2); 若 ,否则为 。
4. 完整代码实现
import micropipawait micropip.install("numpy")import numpy as np
# ── 激活函数 ──────────────────────────────────────────def sigmoid(z): return 1 / (1 + np.exp(-z))
def relu(z): return np.maximum(0, z)
def relu_backward(dA, Z): # ReLU 导数:Z>0 处为1,否则为0 dZ = dA.copy() dZ[Z <= 0] = 0 return dZ
# ── 前向传播 ──────────────────────────────────────────def forward(X, W1, b1, W2, b2): Z1 = X @ W1.T + b1 A1 = relu(Z1) Z2 = A1 @ W2.T + b2 A2 = sigmoid(Z2) cache = (Z1, A1, Z2, A2) return A2, cache
# ── 反向传播 ──────────────────────────────────────────def backward(X, y, W2, cache): m = X.shape[0] Z1, A1, Z2, A2 = cache
# 输出层梯度(Sigmoid + 交叉熵的组合导数化简为 ŷ - y) dZ2 = A2 - y # (m, 1) dW2 = (dZ2.T @ A1) / m # (1, n_h) db2 = np.mean(dZ2, axis=0, keepdims=True) # (1, 1)
# 隐藏层梯度(链式法则 + ReLU 导数) dA1 = dZ2 @ W2 # (m, n_h) dZ1 = relu_backward(dA1, Z1) # (m, n_h) dW1 = (dZ1.T @ X) / m # (n_h, n_x) db1 = np.mean(dZ1, axis=0, keepdims=True) # (1, n_h)
return dW1, db1, dW2, db2
# ── 训练循环 ──────────────────────────────────────────np.random.seed(42)X = np.random.randn(100, 3) # 100样本,3特征y = (X[:, 0] + X[:, 1] > 0).astype(float).reshape(-1, 1) # 简单二分类标签
# 初始化参数(小随机数,避免对称性问题[^3])W1 = np.random.randn(4, 3) * 0.01b1 = np.zeros((1, 4))W2 = np.random.randn(1, 4) * 0.01b2 = np.zeros((1, 1))
lr = 0.1for epoch in range(1000): # 前向 A2, cache = forward(X, W1, b1, W2, b2)
# 损失(二元交叉熵) loss = -np.mean(y * np.log(A2 + 1e-9) + (1 - y) * np.log(1 - A2 + 1e-9))
# 反向 dW1, db1, dW2, db2 = backward(X, y, W2, cache)
# 参数更新 W1 -= lr * dW1 b1 -= lr * db1 W2 -= lr * dW2 b2 -= lr * db2
if epoch % 200 == 0: print(f"Epoch {epoch:4d} | Loss: {loss:.4f}")5. 反向传播的本质
现代深度学习框架(PyTorch、TensorFlow)通过自动微分3自动完成反向传播,无需手动推导梯度。