BP神经网络实战:从零实现鸢尾花分类的简明指南

1次阅读
没有评论

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

image.webp

背景与痛点

鸢尾花数据集是机器学习领域的经典案例,包含 150 个样本,每个样本有 4 个特征(花萼长度、花萼宽度、花瓣长度、花瓣宽度)和 3 个分类标签(山鸢尾、变色鸢尾、维吉尼亚鸢尾)。这个数据集非常适合初学者练习分类任务,因为:

BP 神经网络实战:从零实现鸢尾花分类的简明指南

  • 数据量适中,训练速度快
  • 特征维度低,便于可视化理解
  • 分类边界非线性,能体现神经网络的威力

初学者在实现 BP 神经网络时,常会遇到以下问题:

  1. 梯度消失 :深层网络在反向传播时梯度逐渐变小,导致训练停滞
  2. 过拟合 :模型在训练集表现很好,但测试集效果差
  3. 参数难调 :学习率、隐藏层节点数等超参数选择困难

技术实现

网络结构设计

  1. 输入层 :4 个节点(对应 4 个特征)
  2. 隐藏层 :经验法则是取输入节点数和输出节点数的平均值,这里选择 5 个节点
  3. 输出层 :3 个节点(对应 3 个分类),使用独热编码表示

激活函数选择

使用 Sigmoid 函数,因为它:

  • 输出范围 (0,1),适合概率预测
  • 导数容易计算:σ'(x) = σ(x)(1-σ(x))
  • 数学表达式:σ(x) = 1/(1+e^(-x))

反向传播过程

  1. 计算输出层误差:δ^L = (y – a^L) ⊙ σ'(z^L)
  2. 反向传播误差:δ^l = (W^l)^T δ^{l+1} ⊙ σ'(z^l)
  3. 权重更新:ΔW = η * δ^{l+1} (a^l)^T

代码示例

import numpy as np
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler

# 数据加载和预处理
iris = load_iris()
X = iris.data
y = iris.target

# 标准化特征
scaler = StandardScaler()
X = scaler.fit_transform(X)

# 将标签转为独热编码
def to_one_hot(y):
    one_hot = np.zeros((len(y), 3))
    one_hot[np.arange(len(y)), y] = 1
    return one_hot

y_one_hot = to_one_hot(y)

# 定义神经网络结构
input_size = 4
hidden_size = 5
output_size = 3

# 初始化权重
W1 = np.random.randn(input_size, hidden_size) * 0.01
W2 = np.random.randn(hidden_size, output_size) * 0.01

# 定义 sigmoid 激活函数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def sigmoid_derivative(x):
    return x * (1 - x)

# 训练参数
learning_rate = 0.1
epochs = 1000

# 存储损失值
losses = []

# 训练循环
for epoch in range(epochs):
    # 前向传播
    hidden_layer = sigmoid(np.dot(X, W1))
    output_layer = sigmoid(np.dot(hidden_layer, W2))

    # 计算损失(均方误差)loss = np.mean(0.5 * (y_one_hot - output_layer) ** 2)
    losses.append(loss)

    # 反向传播
    output_error = y_one_hot - output_layer
    output_delta = output_error * sigmoid_derivative(output_layer)

    hidden_error = output_delta.dot(W2.T)
    hidden_delta = hidden_error * sigmoid_derivative(hidden_layer)

    # 更新权重
    W2 += learning_rate * hidden_layer.T.dot(output_delta)
    W1 += learning_rate * X.T.dot(hidden_delta)

优化实践

学习率对比

  1. 学习率 =0.1:收敛快但可能震荡
  2. 学习率 =0.01:收敛稳定但速度慢
  3. 学习率 =0.001:可能无法在合理步数内收敛

L2 正则化实现

在损失函数中加入权重惩罚项:

l2_lambda = 0.01
loss = np.mean(0.5 * (y_one_hot - output_layer) ** 2) + 
       l2_lambda * (np.sum(W1**2) + np.sum(W2**2))

模型评估

from sklearn.metrics import accuracy_score, confusion_matrix

# 预测函数
def predict(X):
    hidden_layer = sigmoid(np.dot(X, W1))
    output_layer = sigmoid(np.dot(hidden_layer, W2))
    return np.argmax(output_layer, axis=1)

# 计算准确率
y_pred = predict(X)
accuracy = accuracy_score(y, y_pred)
print(f"Accuracy: {accuracy:.2f}")

# 混淆矩阵
cm = confusion_matrix(y, y_pred)
print("Confusion Matrix:")
print(cm)

避坑指南

  1. 特征缩放 :务必对输入特征做标准化 / 归一化,否则不同尺度的特征会影响收敛
  2. 隐藏层节点数 :可以从输入输出节点数的几何平均值开始尝试
  3. 训练终止条件 :可以设置早停机制,当验证集损失连续几轮不下降时停止

延伸思考

  1. 激活函数改进 :尝试 ReLU 函数,可能解决梯度消失问题
  2. 可视化权重 :用热力图展示隐藏层权重,理解网络学习到的特征
  3. 批归一化 :在隐藏层后加入 BN 层,加速训练过程

通过这个简单的实现,我们完成了鸢尾花分类任务。虽然代码不到 100 行,但涵盖了 BP 神经网络的核心概念。建议读者可以尝试调整网络结构、更换激活函数、添加正则化等改进措施,观察模型表现的变化。

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