基于 Python 实现 3 层 BP 神经网络鸢尾花分类 - 从原理到代码
本项目使用 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 神经网络的基本原理和应用。
原文地址: https://www.cveoy.top/t/topic/mq42 著作权归作者所有。请勿转载和采集!