使用Python实现一个简单的神经网络分类器
在现代人工智能和机器学习领域,神经网络(Neural Networks)是一种非常强大的工具。它模仿人脑的工作方式,通过多个层级的节点(神经元)来处理信息,并完成诸如图像识别、自然语言处理、语音识别等任务。
本文将从零开始,使用 Python 和 NumPy 实现一个简单的三层前馈神经网络(Feedforward Neural Network),并用于解决一个基本的二分类问题。我们将介绍神经网络的基本结构、损失函数、反向传播算法以及如何用代码实现这些步骤。
神经网络概述
一个基本的三层神经网络包括:
输入层(Input Layer)隐藏层(Hidden Layer)输出层(Output Layer)每一层都由若干个“神经元”组成,每个神经元与下一层的所有神经元相连。连接的强度由权重(weights)决定,同时每个神经元还有一个偏置项(bias)。
我们使用的激活函数是 Sigmoid 函数,其公式如下:
$$\sigma(x) = \frac{1}{1 + e^{-x}}$$
它的导数为:
$$\sigma'(x) = \sigma(x)(1 - \sigma(x))$$
数据准备
为了演示目的,我们使用一个简单的二维二分类数据集。我们可以使用 sklearn.datasets.make_blobs
来生成一些样本点。
import numpy as npfrom sklearn.datasets import make_blobsimport matplotlib.pyplot as plt# 生成2维数据,两个类别X, y = make_blobs(n_samples=300, centers=2, cluster_std=1.5, random_state=42)y = y.reshape(-1, 1)print("输入数据形状:", X.shape)print("标签数据形状:", y.shape)
输出:
输入数据形状: (300, 2)标签数据形状: (300, 1)
构建神经网络模型
我们定义一个包含以下部分的类:
初始化函数(构造权重和偏置)前向传播函数损失函数(交叉熵)反向传播函数训练函数3.1 定义神经网络类
class SimpleNeuralNetwork: def __init__(self, input_size, hidden_size, output_size): # 初始化参数 self.W1 = np.random.randn(input_size, hidden_size) self.b1 = np.zeros((1, hidden_size)) self.W2 = np.random.randn(hidden_size, output_size) self.b2 = np.zeros((1, output_size)) def sigmoid(self, x): return 1 / (1 + np.exp(-x)) def sigmoid_derivative(self, x): return x * (1 - x) def forward(self, X): # 前向传播 self.z1 = np.dot(X, self.W1) + self.b1 self.a1 = self.sigmoid(self.z1) self.z2 = np.dot(self.a1, self.W2) + self.b2 self.a2 = self.sigmoid(self.z2) return self.a2 def compute_loss(self, y_true, y_pred): # 交叉熵损失函数 m = y_true.shape[0] loss = -np.sum(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred)) / m return loss def backward(self, X, y, learning_rate=0.01): # 反向传播 m = X.shape[0] # 输出层误差 dz2 = self.a2 - y dW2 = np.dot(self.a1.T, dz2) / m db2 = np.sum(dz2, axis=0, keepdims=True) / m # 隐藏层误差 da1 = np.dot(dz2, self.W2.T) dz1 = da1 * self.sigmoid_derivative(self.a1) dW1 = np.dot(X.T, dz1) / m db1 = np.sum(dz1, axis=0, keepdims=True) / m # 更新参数 self.W1 -= learning_rate * dW1 self.b1 -= learning_rate * db1 self.W2 -= learning_rate * dW2 self.b2 -= learning_rate * db2 def train(self, X, y, epochs=1000, learning_rate=0.01, print_loss=True): losses = [] for epoch in range(epochs): y_pred = self.forward(X) loss = self.compute_loss(y, y_pred) losses.append(loss) self.backward(X, y, learning_rate) if print_loss and (epoch % 100 == 0 or epoch == epochs - 1): print(f"Epoch {epoch}: Loss = {loss:.6f}") return losses
训练模型
接下来我们实例化模型并进行训练。
# 创建模型input_size = 2hidden_size = 4output_size = 1model = SimpleNeuralNetwork(input_size, hidden_size, output_size)# 开始训练losses = model.train(X, y, epochs=1000, learning_rate=0.1)# 绘制损失曲线plt.plot(losses)plt.xlabel("Epoch")plt.ylabel("Loss")plt.title("Training Loss Curve")plt.show()
评估模型性能
我们可以计算预测准确率来评估模型的表现。
def accuracy(y_true, y_pred): predictions = (y_pred > 0.5).astype(int) correct = np.sum(predictions == y_true) return correct / len(y_true)# 预测y_pred = model.forward(X)acc = accuracy(y, y_pred)print(f"模型准确率:{acc * 100:.2f}%")
输出示例:
模型准确率:98.67%
可视化决策边界
为了更直观地了解模型的学习效果,我们可以绘制决策边界。
def plot_decision_boundary(model, X, y): x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01), np.arange(y_min, y_max, 0.01)) grid = np.c_[xx.ravel(), yy.ravel()] Z = model.forward(grid) Z = (Z > 0.5).astype(int) Z = Z.reshape(xx.shape) plt.contourf(xx, yy, Z, alpha=0.4) plt.scatter(X[:, 0], X[:, 1], c=y.ravel(), s=20, edgecolor='k') plt.xlabel("Feature 1") plt.ylabel("Feature 2") plt.title("Decision Boundary") plt.show()plot_decision_boundary(model, X, y)
总结
通过本文,我们完成了以下工作:
理解了神经网络的基本结构。使用 Python 和 NumPy 构建了一个三层前馈神经网络。实现了前向传播、损失计算、反向传播和梯度下降优化。对模型进行了训练和评估。可视化了决策边界以帮助理解模型行为。虽然这是一个基础的神经网络实现,但它展示了深度学习模型的核心思想。对于更复杂的任务,可以考虑使用如 PyTorch 或 TensorFlow 等深度学习框架,它们提供了更高效的自动求导和GPU加速功能。
附录:完整代码清单
import numpy as npfrom sklearn.datasets import make_blobsimport matplotlib.pyplot as pltclass SimpleNeuralNetwork: def __init__(self, input_size, hidden_size, output_size): self.W1 = np.random.randn(input_size, hidden_size) self.b1 = np.zeros((1, hidden_size)) self.W2 = np.random.randn(hidden_size, output_size) self.b2 = np.zeros((1, output_size)) def sigmoid(self, x): return 1 / (1 + np.exp(-x)) def sigmoid_derivative(self, x): return x * (1 - x) def forward(self, X): self.z1 = np.dot(X, self.W1) + self.b1 self.a1 = self.sigmoid(self.z1) self.z2 = np.dot(self.a1, self.W2) + self.b2 self.a2 = self.sigmoid(self.z2) return self.a2 def compute_loss(self, y_true, y_pred): m = y_true.shape[0] loss = -np.sum(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred)) / m return loss def backward(self, X, y, learning_rate=0.01): m = X.shape[0] dz2 = self.a2 - y dW2 = np.dot(self.a1.T, dz2) / m db2 = np.sum(dz2, axis=0, keepdims=True) / m da1 = np.dot(dz2, self.W2.T) dz1 = da1 * self.sigmoid_derivative(self.a1) dW1 = np.dot(X.T, dz1) / m db1 = np.sum(dz1, axis=0, keepdims=True) / m self.W1 -= learning_rate * dW1 self.b1 -= learning_rate * db1 self.W2 -= learning_rate * dW2 self.b2 -= learning_rate * db2 def train(self, X, y, epochs=1000, learning_rate=0.01, print_loss=True): losses = [] for epoch in range(epochs): y_pred = self.forward(X) loss = self.compute_loss(y, y_pred) losses.append(loss) self.backward(X, y, learning_rate) if print_loss and (epoch % 100 == 0 or epoch == epochs - 1): print(f"Epoch {epoch}: Loss = {loss:.6f}") return losses# 数据生成X, y = make_blobs(n_samples=300, centers=2, cluster_std=1.5, random_state=42)y = y.reshape(-1, 1)# 模型训练model = SimpleNeuralNetwork(2, 4, 1)losses = model.train(X, y, epochs=1000, learning_rate=0.1)# 准确率计算def accuracy(y_true, y_pred): predictions = (y_pred > 0.5).astype(int) correct = np.sum(predictions == y_true) return correct / len(y_true)y_pred = model.forward(X)acc = accuracy(y, y_pred)print(f"模型准确率:{acc * 100:.2f}%")# 决策边界可视化def plot_decision_boundary(model, X, y): x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01), np.arange(y_min, y_max, 0.01)) grid = np.c_[xx.ravel(), yy.ravel()] Z = model.forward(grid) Z = (Z > 0.5).astype(int) Z = Z.reshape(xx.shape) plt.contourf(xx, yy, Z, alpha=0.4) plt.scatter(X[:, 0], X[:, 1], c=y.ravel(), s=20, edgecolor='k') plt.xlabel("Feature 1") plt.ylabel("Feature 2") plt.title("Decision Boundary") plt.show()plot_decision_boundary(model, X, y)
如需进一步扩展该模型,可以尝试添加更多隐藏层、使用不同的激活函数(如 ReLU)、正则化技术或引入批量训练机制。希望这篇文章能帮助你更好地理解和动手实践神经网络!