共计 2766 个字符,预计需要花费 7 分钟才能阅读完成。
多层感知机参数计算与反向传播机制解析
1. 多层感知机 (MLP) 基础结构
多层感知机是最基础的前馈神经网络结构,由输入层、隐藏层和输出层组成。以题目中的结构为例(输入层 33 节点,隐藏层 512 节点,输出层 10 节点):

- 参数总量计算:
- 输入层到隐藏层权重矩阵:33×512 = 16,896
- 隐藏层偏置向量:512×1 = 512
- 隐藏层到输出层权重矩阵:512×10 = 5,120
- 输出层偏置向量:10×1 = 10
- 总计:16,896 + 512 + 5,120 + 10 = 22,538 个可训练参数
数学表达式为:
Z^[1] = W^[1]X + b^[1]
A^[1] = σ(Z^[1])
Z^[2] = W^[2]A^[1] + b^[2]
A^[2] = softmax(Z^[2])
2. 反向传播机制详解
2.1 梯度计算原理
对于输出层(假设使用交叉熵损失和 softmax 激活):
- 输出层误差项:
dZ^[2] = A^[2] - Y - 隐藏层梯度:
dW^[2] = (1/m) * dZ^[2]A^[1]T db^[2] = (1/m) * sum(dZ^[2]) - 隐藏层误差传播:
dZ^[1] = W^[2]T * dZ^[2] ⊙ σ'(Z^[1]) - 输入层梯度:
dW^[1] = (1/m) * dZ^[1]XT db^[1] = (1/m) * sum(dZ^[1])
2.2 权重更新
采用梯度下降更新规则:
W^[l] = W^[l] - α * dW^[l]
b^[l] = b^[l] - α * db^[l]
其中 α 为学习率。
3. 过拟合解决方案
3.1 L2 正则化
在损失函数中加入权重惩罚项:
def compute_cost_with_regularization(A, Y, parameters, lambd):
m = Y.shape[1]
cross_entropy = compute_entropy(A, Y)
L2_cost = (lambd/(2*m)) * (np.sum(np.square(W1)) + np.sum(np.square(W2)))
return cross_entropy + L2_cost
3.2 Dropout
随机丢弃部分神经元:
def forward_prop_with_dropout(X, parameters, keep_prob=0.8):
W1, b1, W2, b2 = parameters
Z1 = np.dot(W1, X) + b1
A1 = relu(Z1)
D1 = np.random.rand(A1.shape[0], A1.shape[1])
D1 = (D1 < keep_prob).astype(int)
A1 = A1 * D1
A1 = A1 / keep_prob
Z2 = np.dot(W2, A1) + b2
A2 = softmax(Z2)
return A2, {"D1": D1}
3.3 早停法(Early Stopping)
best_val_loss = float('inf')
patience = 5
counter = 0
for epoch in range(epochs):
# 训练过程...
val_loss = compute_validation_loss()
if val_loss < best_val_loss:
best_val_loss = val_loss
counter = 0
# 保存最佳模型
else:
counter += 1
if counter >= patience:
print("Early stopping triggered")
break
4. 完整代码实现
import numpy as np
class SimpleMLP:
def __init__(self, input_size, hidden_size, output_size):
self.W1 = np.random.randn(hidden_size, input_size) * 0.01
self.b1 = np.zeros((hidden_size, 1))
self.W2 = np.random.randn(output_size, hidden_size) * 0.01
self.b2 = np.zeros((output_size, 1))
def relu(self, Z):
return np.maximum(0, Z)
def softmax(self, Z):
expZ = np.exp(Z - np.max(Z))
return expZ / expZ.sum(axis=0, keepdims=True)
def forward(self, X):
self.Z1 = np.dot(self.W1, X) + self.b1
self.A1 = self.relu(self.Z1)
self.Z2 = np.dot(self.W2, self.A1) + self.b2
self.A2 = self.softmax(self.Z2)
return self.A2
def compute_loss(self, Y):
m = Y.shape[1]
logprobs = np.multiply(np.log(self.A2), Y)
return -np.sum(logprobs) / m
def backward(self, X, Y):
m = X.shape[1]
# 输出层梯度
dZ2 = self.A2 - Y
dW2 = np.dot(dZ2, self.A1.T) / m
db2 = np.sum(dZ2, axis=1, keepdims=True) / m
# 隐藏层梯度
dA1 = np.dot(self.W2.T, dZ2)
dZ1 = dA1 * (self.Z1 > 0)
dW1 = np.dot(dZ1, X.T) / m
db1 = np.sum(dZ1, axis=1, keepdims=True) / m
return {"dW1": dW1, "db1": db1, "dW2": dW2, "db2": db2}
def update_parameters(self, grads, learning_rate):
self.W1 -= learning_rate * grads["dW1"]
self.b1 -= learning_rate * grads["db1"]
self.W2 -= learning_rate * grads["dW2"]
self.b2 -= learning_rate * grads["db2"]
5. 训练建议与避坑指南
- 学习率设置:推荐使用学习率衰减策略
learning_rate = initial_lr * (1 / (1 + decay_rate * epoch)) - 参数初始化:使用 He 初始化效果更好
W1 = np.random.randn(hidden_size, input_size) * np.sqrt(2/input_size) - 批量归一化:可加速训练过程
- 常见错误:
- 忘记对输入数据进行归一化
- 使用过大的学习率导致震荡
- 未正确实现梯度检查
- 权重矩阵维度不匹配
思考题
- 如果隐藏层使用 sigmoid 激活函数,反向传播的公式会有哪些变化?
- 当 batch size 设置为 1 时(随机梯度下降),参数更新会有什么特点?
- 如何设计实验比较三种过拟合方法的效果差异?
正文完
发表至: 未分类
近两天内
