使用Python实现一个简单的神经网络
神经网络是深度学习的基础,广泛应用于图像识别、自然语言处理、语音识别等领域。在本文中,我们将使用 Python 实现一个简单的前馈神经网络(Feedforward Neural Network),并用它来解决一个基本的分类问题。我们将从头开始构建神经网络,包括定义网络结构、前向传播、损失计算、反向传播以及参数更新等步骤。
环境准备
在开始之前,请确保你已经安装了以下库:
NumPy:用于数值计算matplotlib:用于可视化训练过程(可选)你可以使用 pip 安装这些库:
pip install numpy matplotlib
1. 导入必要的库
首先,我们导入需要用到的库:
import numpy as npimport matplotlib.pyplot as plt
2. 构建数据集
为了演示方便,我们使用一个简单的二维二分类数据集。我们可以使用 sklearn
中的 make_blobs
函数生成一些带标签的点:
from sklearn.datasets import make_blobs# 生成数据X, y = make_blobs(n_samples=300, centers=2, cluster_std=1.5, random_state=42)y = y.reshape((y.shape[0], 1)) # 转换为列向量# 可视化数据plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm')plt.title("Generated Dataset")plt.show()
这段代码生成了两组二维点,并将它们绘制出来。我们的目标是训练一个神经网络来对这些点进行分类。
3. 定义神经网络模型
我们将构建一个具有单个隐藏层的神经网络。具体结构如下:
输入层:2个节点(对应两个特征)隐藏层:4个节点,使用ReLU激活函数输出层:1个节点,使用Sigmoid激活函数(因为这是一个二分类问题)激活函数及其导数
def sigmoid(z): return 1 / (1 + np.exp(-z))def sigmoid_derivative(z): return sigmoid(z) * (1 - sigmoid(z))def relu(z): return np.maximum(0, z)def relu_derivative(z): return (z > 0).astype(float)
4. 初始化参数
接下来,我们初始化网络的权重和偏置项:
def initialize_parameters(input_size, hidden_size, output_size): np.random.seed(42) W1 = np.random.randn(input_size, hidden_size) * 0.01 b1 = np.zeros((1, hidden_size)) W2 = np.random.randn(hidden_size, output_size) * 0.01 b2 = np.zeros((1, output_size)) parameters = { "W1": W1, "b1": b1, "W2": W2, "b2": b2 } return parameters
5. 前向传播
前向传播是指输入数据通过网络层层传递,最终得到输出预测值的过程:
def forward_propagation(X, parameters): Z1 = np.dot(X, parameters["W1"]) + parameters["b1"] A1 = relu(Z1) Z2 = np.dot(A1, parameters["W2"]) + parameters["b2"] A2 = sigmoid(Z2) cache = { "Z1": Z1, "A1": A1, "Z2": Z2, "A2": A2 } return A2, cache
6. 计算损失函数
我们使用交叉熵损失函数来衡量模型预测结果与真实标签之间的差异:
def compute_loss(y, y_hat): m = y.shape[0] loss = -(1/m) * np.sum(y * np.log(y_hat) + (1 - y) * np.log(1 - y_hat)) return loss
7. 反向传播
反向传播是根据损失函数的梯度调整网络参数的关键步骤:
def backward_propagation(X, y, cache, parameters): m = X.shape[0] W2 = parameters["W2"] A1 = cache["A1"] A2 = cache["A2"] dZ2 = A2 - y dW2 = (1/m) * np.dot(A1.T, dZ2) db2 = (1/m) * np.sum(dZ2, axis=0, keepdims=True) dZ1 = np.dot(dZ2, W2.T) * relu_derivative(cache["Z1"]) dW1 = (1/m) * np.dot(X.T, dZ1) db1 = (1/m) * np.sum(dZ1, axis=0, keepdims=True) gradients = { "dW1": dW1, "db1": db1, "dW2": dW2, "db2": db2 } return gradients
8. 更新参数
使用梯度下降法更新参数:
def update_parameters(parameters, gradients, learning_rate=0.01): parameters["W1"] -= learning_rate * gradients["dW1"] parameters["b1"] -= learning_rate * gradients["db1"] parameters["W2"] -= learning_rate * gradients["dW2"] parameters["b2"] -= learning_rate * gradients["db2"] return parameters
9. 整合训练过程
我们将以上所有步骤整合到一个完整的训练循环中:
def train(X, y, hidden_size=4, learning_rate=0.1, num_iterations=10000): input_size = X.shape[1] output_size = y.shape[1] parameters = initialize_parameters(input_size, hidden_size, output_size) losses = [] for i in range(num_iterations): y_hat, cache = forward_propagation(X, parameters) loss = compute_loss(y, y_hat) gradients = backward_propagation(X, y, cache, parameters) parameters = update_parameters(parameters, gradients, learning_rate) if i % 100 == 0: losses.append(loss) print(f"Iteration {i}, Loss: {loss:.6f}") plt.plot(losses) plt.xlabel("Iteration (per 100)") plt.ylabel("Loss") plt.title("Training Loss Curve") plt.show() return parameters
10. 模型训练与测试
现在,我们调用 train
函数来训练模型:
parameters = train(X, y, hidden_size=4, learning_rate=0.1, num_iterations=10000)
训练完成后,我们可以使用训练好的参数来进行预测:
def predict(X, parameters): y_hat, _ = forward_propagation(X, parameters) predictions = (y_hat > 0.5).astype(int) return predictionspredictions = predict(X, parameters)accuracy = np.mean(predictions == y)print(f"Accuracy: {accuracy * 100:.2f}%")
11. 总结
在本篇文章中,我们使用 Python 从零实现了一个人工神经网络,涵盖了以下关键步骤:
数据准备与可视化神经网络结构设计参数初始化前向传播与损失计算反向传播与参数更新模型训练与评估虽然这个神经网络比较简单,但它展示了深度学习的基本原理和流程。你可以在此基础上扩展,例如添加更多的隐藏层、使用不同的优化器、正则化技术或更复杂的激活函数等。
如果你有兴趣进一步深入,可以尝试使用 PyTorch 或 TensorFlow 来实现更复杂的神经网络模型,这些框架提供了自动求导、GPU加速等功能,能够显著提升开发效率。
完整代码汇总
import numpy as npimport matplotlib.pyplot as pltfrom sklearn.datasets import make_blobs# 生成数据X, y = make_blobs(n_samples=300, centers=2, cluster_std=1.5, random_state=42)y = y.reshape((y.shape[0], 1))# 激活函数def sigmoid(z): return 1 / (1 + np.exp(-z))def sigmoid_derivative(z): return sigmoid(z) * (1 - sigmoid(z))def relu(z): return np.maximum(0, z)def relu_derivative(z): return (z > 0).astype(float)# 初始化参数def initialize_parameters(input_size, hidden_size, output_size): np.random.seed(42) W1 = np.random.randn(input_size, hidden_size) * 0.01 b1 = np.zeros((1, hidden_size)) W2 = np.random.randn(hidden_size, output_size) * 0.01 b2 = np.zeros((1, output_size)) parameters = {"W1": W1, "b1": b1, "W2": W2, "b2": b2} return parameters# 前向传播def forward_propagation(X, parameters): Z1 = np.dot(X, parameters["W1"]) + parameters["b1"] A1 = relu(Z1) Z2 = np.dot(A1, parameters["W2"]) + parameters["b2"] A2 = sigmoid(Z2) cache = {"Z1": Z1, "A1": A1, "Z2": Z2, "A2": A2} return A2, cache# 损失函数def compute_loss(y, y_hat): m = y.shape[0] loss = -(1/m) * np.sum(y * np.log(y_hat) + (1 - y) * np.log(1 - y_hat)) return loss# 反向传播def backward_propagation(X, y, cache, parameters): m = X.shape[0] W2 = parameters["W2"] A1 = cache["A1"] A2 = cache["A2"] dZ2 = A2 - y dW2 = (1/m) * np.dot(A1.T, dZ2) db2 = (1/m) * np.sum(dZ2, axis=0, keepdims=True) dZ1 = np.dot(dZ2, W2.T) * relu_derivative(cache["Z1"]) dW1 = (1/m) * np.dot(X.T, dZ1) db1 = (1/m) * np.sum(dZ1, axis=0, keepdims=True) gradients = {"dW1": dW1, "db1": db1, "dW2": dW2, "db2": db2} return gradients# 参数更新def update_parameters(parameters, gradients, learning_rate=0.01): parameters["W1"] -= learning_rate * gradients["dW1"] parameters["b1"] -= learning_rate * gradients["db1"] parameters["W2"] -= learning_rate * gradients["dW2"] parameters["b2"] -= learning_rate * gradients["db2"] return parameters# 训练函数def train(X, y, hidden_size=4, learning_rate=0.1, num_iterations=10000): input_size = X.shape[1] output_size = y.shape[1] parameters = initialize_parameters(input_size, hidden_size, output_size) losses = [] for i in range(num_iterations): y_hat, cache = forward_propagation(X, parameters) loss = compute_loss(y, y_hat) gradients = backward_propagation(X, y, cache, parameters) parameters = update_parameters(parameters, gradients, learning_rate) if i % 100 == 0: losses.append(loss) print(f"Iteration {i}, Loss: {loss:.6f}") plt.plot(losses) plt.xlabel("Iteration (per 100)") plt.ylabel("Loss") plt.title("Training Loss Curve") plt.show() return parameters# 预测函数def predict(X, parameters): y_hat, _ = forward_propagation(X, parameters) predictions = (y_hat > 0.5).astype(int) return predictions# 开始训练parameters = train(X, y, hidden_size=4, learning_rate=0.1, num_iterations=10000)# 测试精度predictions = predict(X, parameters)accuracy = np.mean(predictions == y)print(f"Accuracy: {accuracy * 100:.2f}%")
如需进一步拓展,欢迎尝试:
添加更多隐藏层引入正则化(L2 或 Dropout)使用 Adam 优化器替代 SGD将其封装成类(面向对象编程)希望这篇文章对你理解神经网络的工作原理有所帮助!