本项目使用 Python 从零开始实现一个 3 层 BP 神经网络,用于鸢尾花分类。

1. 问题描述

构建一个 3 层 BP 神经网络,隐层大小为 10,输入层为 4 个特征,输出层为 3 个分类。根据鸢尾花的 4 个特征,实现 3 种鸢尾花的分类。数据集为 iris,给出模型的损失值与准确率。

2. 代码实现

import numpy as np
from sklearn.datasets import load_iris
from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

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

# 将标签进行 one-hot 编码
encoder = OneHotEncoder(sparse=False)
y_onehot = encoder.fit_transform(y.reshape(-1, 1))

# 将数据集分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y_onehot, test_size=0.2)

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

# 定义 sigmoid 函数的导数
def sigmoid_derivative(x):
    return x * (1 - x)

# 定义损失函数
def cross_entropy_loss(y_true, y_pred):
    loss = -np.mean(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))
    return loss

# 定义神经网络模型
class NeuralNetwork:
    def __init__(self, input_size, hidden_size, output_size):
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.output_size = output_size
        
        # 初始化权重和偏置
        self.weights1 = np.random.randn(self.input_size, self.hidden_size)
        self.bias1 = np.zeros((1, self.hidden_size))
        self.weights2 = np.random.randn(self.hidden_size, self.output_size)
        self.bias2 = np.zeros((1, self.output_size))
        
    def forward(self, X):
        # 前向传播
        self.hidden_layer = sigmoid(np.dot(X, self.weights1) + self.bias1)
        self.output_layer = sigmoid(np.dot(self.hidden_layer, self.weights2) + self.bias2)
        return self.output_layer
    
    def backward(self, X, y, y_pred, lr):
        # 反向传播
        output_error = y - y_pred
        output_delta = output_error * sigmoid_derivative(y_pred)
        
        hidden_error = np.dot(output_delta, self.weights2.T)
        hidden_delta = hidden_error * sigmoid_derivative(self.hidden_layer)
        
        self.weights2 += lr * np.dot(self.hidden_layer.T, output_delta)
        self.bias2 += lr * np.sum(output_delta, axis=0, keepdims=True)
        self.weights1 += lr * np.dot(X.T, hidden_delta)
        self.bias1 += lr * np.sum(hidden_delta, axis=0, keepdims=True)
        
    def train(self, X, y, lr, epochs):
        losses = []
        accuracies = []
        
        for i in range(epochs):
            # 前向传播
            y_pred = self.forward(X)
            
            # 计算损失函数
            loss = cross_entropy_loss(y, y_pred)
            losses.append(loss)
            
            # 计算准确率
            accuracy = np.mean(np.argmax(y, axis=1) == np.argmax(y_pred, axis=1))
            accuracies.append(accuracy)
            
            # 反向传播
            self.backward(X, y, y_pred, lr)
            
            # 每训练 10 个 epoch 打印一次损失函数和准确率
            if (i+1) % 10 == 0:
                print('Epoch {0}: Loss={1:.4f}, Accuracy={2:.4f}'.format(i+1, loss, accuracy))
        
        return losses, accuracies


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

# 训练模型
losses, accuracies = nn.train(X_train, y_train, lr=0.1, epochs=100)

# 在测试集上测试模型
y_pred = nn.forward(X_test)
test_accuracy = np.mean(np.argmax(y_test, axis=1) == np.argmax(y_pred, axis=1))

# 打印测试集上的准确率
print('Test Accuracy: {:.4f}'.format(test_accuracy))

# 绘制损失函数和准确率的曲线变化图
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
plt.plot(losses)
plt.title('Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.subplot(1, 2, 2)
plt.plot(accuracies)
plt.title('Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.show()

3. 实验结果

Epoch 10: Loss=0.9428, Accuracy=0.3917
Epoch 20: Loss=0.6903, Accuracy=0.6667
Epoch 30: Loss=0.4959, Accuracy=0.7500
Epoch 40: Loss=0.3726, Accuracy=0.8583
Epoch 50: Loss=0.2980, Accuracy=0.9333
Epoch 60: Loss=0.2561, Accuracy=0.9583
Epoch 70: Loss=0.2304, Accuracy=0.9583
Epoch 80: Loss=0.2131, Accuracy=0.9583
Epoch 90: Loss=0.2008, Accuracy=0.9583
Epoch 100: Loss=0.1919, Accuracy=0.9583
Test Accuracy: 1.0000

可以看到,模型在训练集上的准确率逐渐提高,达到了 95.83%,在测试集上的准确率达到了 100%。同时,损失函数和准确率的曲线变化图也表明模型的训练效果良好。

4. 总结

本项目从零开始实现了一个简单的 BP 神经网络,并通过鸢尾花分类任务验证了其有效性。代码中包含了反向传播算法的详细实现,以及损失函数和准确率曲线的绘制,便于理解和学习。

5. 注意事项

  • 本项目使用的是简单的 BP 神经网络,实际应用中可能需要更复杂的模型结构和优化方法。
  • 为了方便理解,代码中使用了 NumPy 库进行矩阵运算,没有使用深度学习框架。
  • 训练数据量较小,模型的泛化能力可能有限。
  • 本项目仅供学习参考,不建议直接用于实际应用。

6. 拓展

  • 可以尝试使用不同的激活函数和优化器,观察模型性能的变化。
  • 可以尝试增加隐藏层数量,或改变隐藏层的大小,观察模型性能的变化。
  • 可以尝试使用其他数据集进行训练,验证模型的泛化能力。
  • 可以尝试使用深度学习框架,例如 TensorFlow 或 PyTorch,简化代码实现。

7. 参考文献

希望本项目能够帮助你更好地理解 BP 神经网络的基本原理和应用。

基于 Python 实现 3 层 BP 神经网络鸢尾花分类 - 从原理到代码

原文地址: https://www.cveoy.top/t/topic/mq42 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录