多层感知机参数计算与反向传播机制解析:从基础原理到过拟合解决方案

1次阅读
没有评论

共计 2766 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

多层感知机参数计算与反向传播机制解析

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 激活):

  1. 输出层误差项:
    dZ^[2] = A^[2] - Y
  2. 隐藏层梯度:
    dW^[2] = (1/m) * dZ^[2]A^[1]T
    db^[2] = (1/m) * sum(dZ^[2])
  3. 隐藏层误差传播:
    dZ^[1] = W^[2]T * dZ^[2] ⊙ σ'(Z^[1])
  4. 输入层梯度:
    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)
  • 批量归一化:可加速训练过程
  • 常见错误
  • 忘记对输入数据进行归一化
  • 使用过大的学习率导致震荡
  • 未正确实现梯度检查
  • 权重矩阵维度不匹配

思考题

  1. 如果隐藏层使用 sigmoid 激活函数,反向传播的公式会有哪些变化?
  2. 当 batch size 设置为 1 时(随机梯度下降),参数更新会有什么特点?
  3. 如何设计实验比较三种过拟合方法的效果差异?
正文完
 0
评论(没有评论)