BP神经网络数据分类实战:从基础原理到Python实现

1次阅读
没有评论

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

image.webp

为什么选择 BP 神经网络做分类?

BP(反向传播)神经网络是入门深度学习最经典的模型之一。它通过多层感知器的结构,能够学习复杂的非线性决策边界。对于分类任务,比如识别手写数字、判断肿瘤良性恶性等场景,BP 神经网络往往能达到比传统机器学习算法更好的效果。

BP 神经网络数据分类实战:从基础原理到 Python 实现

但初学者常会遇到两个头疼的问题:

  • 梯度消失 :深层网络中误差反向传播时,梯度越来越小,导致底层参数几乎不更新
  • 过拟合 :模型在训练集上表现很好,但遇到新数据就崩溃

用 Python 实现 BP 神经网络

1. 网络初始化

神经网络的骨架由输入层、隐藏层和输出层组成。我们需要随机初始化权重和偏置:

import numpy as np

class NeuralNetwork:
    def __init__(self, input_size, hidden_size, output_size):
        # 使用 He 初始化,适合 ReLU 激活函数
        self.W1 = np.random.randn(input_size, hidden_size) * np.sqrt(2./input_size)
        self.b1 = np.zeros((1, hidden_size))

        self.W2 = np.random.randn(hidden_size, output_size) * np.sqrt(2./hidden_size)
        self.b2 = np.zeros((1, output_size))

2. 前向传播实现

前向传播就是数据从输入层流向输出层的过程:

def forward(self, X):
    # 隐藏层计算(使用 ReLU 激活)self.z1 = np.dot(X, self.W1) + self.b1
    self.a1 = np.maximum(0, self.z1)  # ReLU

    # 输出层计算(使用 Softmax 激活)self.z2 = np.dot(self.a1, self.W2) + self.b2
    exp_scores = np.exp(self.z2)
    self.probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)

    return self.probs

3. 反向传播核心

反向传播通过链式法则计算梯度:

def backward(self, X, y, learning_rate):
    num_examples = X.shape[0]

    # 输出层误差
    delta3 = self.probs
    delta3[range(num_examples), y] -= 1
    delta3 /= num_examples

    # 隐藏层误差
    dW2 = np.dot(self.a1.T, delta3)
    db2 = np.sum(delta3, axis=0, keepdims=True)

    delta2 = np.dot(delta3, self.W2.T)
    delta2[self.a1 <= 0] = 0  # ReLU 的导数

    # 更新参数
    dW1 = np.dot(X.T, delta2)
    db1 = np.sum(delta2, axis=0)

    # 加入 L2 正则化
    dW2 += reg_lambda * self.W2
    dW1 += reg_lambda * self.W1

    # 参数更新
    self.W1 -= learning_rate * dW1
    self.b1 -= learning_rate * db1
    self.W2 -= learning_rate * dW2
    self.b2 -= learning_rate * db2

实战技巧:让网络更好训练

数据预处理

  • 标准化 :将特征缩放到均值为 0,方差为 1

    from sklearn.preprocessing import StandardScaler
    scaler = StandardScaler()
    X_train = scaler.fit_transform(X_train)
    X_test = scaler.transform(X_test)  # 注意用相同的 scaler

  • 类别编码 :对于多分类问题使用 one-hot 编码

    from keras.utils import to_categorical
    y_one_hot = to_categorical(y, num_classes=3)

学习率调整

学习率太大容易震荡,太小收敛慢:

# 学习率衰减策略
initial_learning_rate = 0.1
decay_rate = 0.95
epochs = 100

for epoch in range(epochs):
    learning_rate = initial_learning_rate * (decay_rate ** epoch)
    nn.backward(X_train, y_train, learning_rate)

防止过拟合

  1. L2 正则化 :在损失函数中加入权重惩罚项
  2. Dropout:随机让部分神经元失活
  3. 早停法 :验证集性能不再提升时停止训练

鸢尾花分类实战

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

# 加载数据
iris = load_iris()
X, y = iris.data, iris.target

# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# 创建网络
nn = NeuralNetwork(input_size=4, hidden_size=10, output_size=3)

# 训练 500 轮
for epoch in range(500):
    # 前向传播
    probs = nn.forward(X_train)

    # 反向传播
    nn.backward(X_train, y_train, learning_rate=0.01)

    # 每 50 轮打印一次损失
    if epoch % 50 == 0:
        loss = -np.log(probs[range(len(y_train)), y_train]).mean()
        print(f"Epoch {epoch}, loss: {loss:.4f}")

新手避坑指南

  1. 忘记数据标准化 :不同量纲的特征会导致梯度下降困难
  2. 初始化权重全为 0 :会导致所有神经元学习相同的特征
  3. 学习率设置不当 :建议先用 0.01 尝试,观察损失曲线
  4. 忽略梯度检查 :复杂网络实现时,先用数值梯度验证反向传播
  5. 过早停止训练 :监控验证集准确率,而不是只看训练损失

下一步探索方向

  1. 尝试不同的激活函数(Tanh、LeakyReLU 等)
  2. 增加网络深度,观察梯度变化
  3. 加入 Batch Normalization 层
  4. 用交叉验证选择最佳超参数

神经网络就像乐高积木,理解基础原理后,你可以自由组合各种模块。虽然现在有现成的深度学习框架,但亲手实现一次 BP 算法,会让你对神经网络的工作机制有更深刻的理解。

正文完
 0
评论(没有评论)