共计 1330 个字符,预计需要花费 4 分钟才能阅读完成。
神经网络结构与前向传播
我们以一个单隐藏层的神经网络为例,结构如下:

- 输入层:2 个节点(特征维度)
- 隐藏层:3 个节点(使用 sigmoid 激活)
- 输出层:1 个节点(二分类任务)
数学表达:
-
输入层到隐藏层计算:
$$ z_1 = W_1X + b_1 $$
$$ a_1 = \sigma(z_1) $$ -
隐藏层到输出层计算:
$$ z_2 = W_2a_1 + b_2 $$
$$ \hat{y} = \sigma(z_2) $$
其中 $\sigma(x)=\frac{1}{1+e^{-x}}$,$W_1$ 是 3×2 矩阵,$W_2$ 是 1×3 矩阵。
反向传播推导
使用均方误差损失函数:
$$ L = \frac{1}{2}(y-\hat{y})^2 $$
输出层梯度
-
损失对输出的梯度:
$$ \frac{\partial L}{\partial \hat{y}} = \hat{y} – y $$ -
经过 sigmoid 激活的梯度:
$$ \frac{\partial \hat{y}}{\partial z_2} = \hat{y}(1-\hat{y}) $$ -
链式法则合并:
$$ \delta_2 = \frac{\partial L}{\partial z_2} = (\hat{y}-y)\hat{y}(1-\hat{y}) $$
隐藏层梯度
-
输出层权重梯度:
$$ \frac{\partial z_2}{\partial W_2} = a_1 $$
$$ \frac{\partial L}{\partial W_2} = \delta_2 a_1^T $$ -
继续反向传播:
$$ \delta_1 = W_2^T \delta_2 \odot a_1 \odot (1-a_1) $$ -
输入层权重梯度:
$$ \frac{\partial L}{\partial W_1} = \delta_1 X^T $$
Python 实现
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def forward(X, W1, b1, W2, b2):
z1 = np.dot(W1, X) + b1 # 3x1
a1 = sigmoid(z1) # 3x1
z2 = np.dot(W2, a1) + b2 # 1x1
y_hat = sigmoid(z2) # 1x1
return a1, y_hat
def backward(X, y, a1, y_hat, W2):
delta2 = (y_hat - y) * y_hat * (1 - y_hat) # 1x1
dW2 = delta2 * a1.T # 1x3
delta1 = np.dot(W2.T, delta2) * a1 * (1 - a1) # 3x1
dW1 = np.dot(delta1, X.T) # 3x2
return dW1, dW2
避坑指南
- 学习率选择:过大学习率会导致梯度爆炸(建议从 0.01 开始尝试)
- 数据标准化 :输入特征应归一化到[0,1] 或标准化(均值 0 方差 1)
- 隐藏层节点:通常取输入特征的 1~2 倍,可通过交叉验证调整
思考题
- 如何用 ReLU 替代 sigmoid?提示:需要修改激活函数和对应的梯度计算
- 批量训练时如何调整代码?提示:注意矩阵维度变化(X 变为 n×2)
- L2 正则化应该加在哪里?提示:在损失函数和梯度计算中都需要添加
实践心得
通过这个案例,我深刻理解了反向传播的链式法则本质。最初容易犯的维度错误,通过打印矩阵 shape 可以快速定位。建议初学者先用小学习率确保收敛,再逐步调整参数。
