共计 2147 个字符,预计需要花费 6 分钟才能阅读完成。
一、理解多层感知机的参数计算
以一个输入层 33 节点、隐层 512 节点、输出层 10 节点的网络为例,参数包含两部分:

- 权重参数:
- 输入层到隐层:$W_1 \in \mathbb{R}^{33×512}$,共 33×512=16,896 个参数
-
隐层到输出层:$W_2 \in \mathbb{R}^{512×10}$,共 512×10=5,120 个参数
-
偏置参数:
- 隐层偏置:$b_1 \in \mathbb{R}^{512}$
- 输出层偏置:$b_2 \in \mathbb{R}^{10}$
总参数量 = 16,896 + 512 + 5,120 + 10 = 22,538 个可训练参数
import numpy as np
# 参数初始化实现
input_dim, hidden_dim, output_dim = 33, 512, 10
W1 = np.random.randn(input_dim, hidden_dim) * 0.01
b1 = np.zeros(hidden_dim)
W2 = np.random.randn(hidden_dim, output_dim) * 0.01
b2 = np.zeros(output_dim)
二、反向传播的梯度计算与权重更新
梯度计算步骤(以 SGD 为例):
-
前向传播计算各层输出:
$$z_1 = W_1^Tx + b_1$$
$$a_1 = \sigma(z_1)$$
$$z_2 = W_2^Ta_1 + b_2$$
$$\hat{y} = \text{softmax}(z_2)$$ -
计算输出层梯度:
$$\frac{\partial L}{\partial z_2} = \hat{y} – y$$ -
反向传播隐层梯度:
$$\frac{\partial L}{\partial W_2} = a_1^T \frac{\partial L}{\partial z_2}$$
$$\frac{\partial L}{\partial z_1} = W_2 \frac{\partial L}{\partial z_2} \odot \sigma'(z_1)$$ -
计算输入层梯度:
$$\frac{\partial L}{\partial W_1} = x^T \frac{\partial L}{\partial z_1}$$
权重更新实现:
# 简化版反向传播实现
learning_rate = 0.01
def backward(x, y, cache):
W1, b1, W2, b2, a1, z2 = cache
m = x.shape[0]
# 输出层梯度
dz2 = cache['probs'] - y
dW2 = np.dot(a1.T, dz2) / m
db2 = np.sum(dz2, axis=0) / m
# 隐层梯度
dz1 = np.dot(dz2, W2.T) * (a1 * (1 - a1)) # 假设使用 sigmoid 激活
dW1 = np.dot(x.T, dz1) / m
db1 = np.sum(dz1, axis=0) / m
# 参数更新
W1 -= learning_rate * dW1
b1 -= learning_rate * db1
W2 -= learning_rate * dW2
b2 -= learning_rate * db2
三、过拟合的三大应对策略
1. Dropout 方法
- 训练时随机丢弃部分神经元(通常丢弃率 p =0.5)
- 测试时使用全部神经元但乘以保留概率(1-p)
# Dropout 实现示例
keep_prob = 0.5
mask = (np.random.rand(*a1.shape) < keep_prob) / keep_prob
a1_drop = a1 * mask
2. L2 正则化
- 在损失函数中加入权重平方和项:
$$L_{new} = L + \frac{\lambda}{2}(|W_1|^2 + |W_2|^2)$$
l2_lambda = 0.01
l2_loss = 0.5 * l2_lambda * (np.sum(W1**2) + np.sum(W2**2))
3. 早停法(Early Stopping)
- 在验证集性能不再提升时终止训练
- 需要监控验证集准确率曲线
四、实战避坑指南
参数初始化注意事项
- 使用 Xavier 初始化:$W \sim N(0, \sqrt{\frac{2}{n_{in}+n_{out}}})$
- ReLU 网络建议使用 He 初始化:$W \sim N(0, \sqrt{\frac{2}{n_{in}}})$
学习率设置经验
- 初始学习率可尝试 0.1~0.001
- 使用学习率衰减策略:
lr = initial_lr * (1 + decay_rate * epoch)**(-0.5)
梯度问题应对方案
- 梯度消失:改用 ReLU/LeakyReLU,合理初始化
- 梯度爆炸:梯度裁剪(gradient clipping)
max_grad_norm = 5.0 total_norm = np.sum([np.linalg.norm(g) for g in grads]) clip_coef = max_grad_norm / (total_norm + 1e-6) grads = [g * clip_coef if clip_coef < 1 else g for g in grads]
思考题
如果隐层使用 ReLU 激活函数,反向传播时梯度计算需要修改为:
$$\frac{\partial L}{\partial z_1} = W_2 \frac{\partial L}{\partial z_2} \odot \mathbb{I}(z_1 > 0)$$
其中 $\mathbb{I}(·)$ 是指示函数,当输入 >0 时输出 1,否则输出 0。
