用 Python 从零实现一个简单神经网络算法(含原理 + 代码 + 可视化讲解)
一、前言:为什么要自己实现神经网络?
很多人刚接触深度学习时,会直接用 TensorFlow、PyTorch 等框架。
但如果没有理解背后的数学原理,很容易出现“只会调库不会调脑”的情况。
👉 因此,从零实现一个简单的神经网络,是入门深度学习最重要的一步。
在本文中,我们将一步步手写一个可以学习 XOR(异或)问题 的神经网络。
不借助任何高级框架,只用 Python + NumPy,彻底理解神经网络的计算过程。
二、神经网络的核心思想
1. 神经元模型的启发
神经网络的灵感来源于人脑的神经元(Neuron)结构。
一个神经元会接收输入信号,通过加权求和后再经过激活函数产生输出:
y=f(w1x1+w2x2+⋯+b)
其中:
- xi:输入特征
- wi:权重(决定输入的重要性)
- b:偏置项(Bias,控制整体偏移)
- f:激活函数,用来增加非线性能力
🌟 激活函数相当于“非线性开关”,让网络能学习复杂关系。
2. 网络结构:三层神经网络
我们要构建一个最简单的网络:
输入层 (2个神经元) ↓ 隐藏层 (3个神经元) ↓ 输出层 (1个神经元) 输入是两个值(例如 XOR 的两个比特),输出是一个值(0 或 1)。
3. 前向传播 (Forward Propagation)
数据从输入层传向输出层,计算公式如下:
1️⃣ 隐藏层输入:
Z1=XW1+b1
2️⃣ 隐藏层输出(经过激活函数):
A1=f(Z1)
3️⃣ 输出层输入:
Z2=A1W2+b2
4️⃣ 输出层输出:
A2=f(Z2)
这里的 A2 就是最终预测结果。
4. 误差计算(Loss Function)
我们使用最常见的平方误差函数:
L=12(y−y^)2
其中:
- y:真实值
- y^:预测值
5. 反向传播 (Backpropagation)
核心目标:让误差越来越小。
我们通过梯度下降算法(Gradient Descent)调整权重。
梯度计算公式如下:
W=W+η∂L∂W
其中:
- η:学习率(learning rate)
- ∂L/∂W:误差对权重的导数(梯度)
三、Python 实现代码(详细注释)
环境:Python 3.x
依赖库:numpy
import numpy as np # 固定随机种子,保证每次运行结果一致 np.random.seed(42) # ========== 1. 数据集定义 ========== # XOR 问题的输入与输出 X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) y = np.array([[0], [1], [1], [0]]) # 目标输出(异或结果) # ========== 2. 定义激活函数 ========== def sigmoid(x): """Sigmoid 激活函数:将值压缩到 (0,1)""" return 1 / (1 + np.exp(-x)) def sigmoid_derivative(x): """Sigmoid 导数,用于反向传播""" return x * (1 - x) # ========== 3. 网络结构参数 ========== input_size = 2 # 输入层节点数 hidden_size = 3 # 隐藏层节点数 output_size = 1 # 输出层节点数 lr = 0.1 # 学习率 epochs = 10000 # 训练迭代次数 # ========== 4. 权重和偏置初始化 ========== W1 = np.random.uniform(-1, 1, (input_size, hidden_size)) b1 = np.zeros((1, hidden_size)) W2 = np.random.uniform(-1, 1, (hidden_size, output_size)) b2 = np.zeros((1, output_size)) # ========== 5. 开始训练 ========== for epoch in range(epochs): # ---- 前向传播 ---- hidden_input = np.dot(X, W1) + b1 hidden_output = sigmoid(hidden_input) final_input = np.dot(hidden_output, W2) + b2 final_output = sigmoid(final_input) # ---- 计算误差 ---- error = y - final_output # ---- 反向传播 ---- d_output = error * sigmoid_derivative(final_output) d_hidden = np.dot(d_output, W2.T) * sigmoid_derivative(hidden_output) # ---- 更新权重与偏置 ---- W2 += np.dot(hidden_output.T, d_output) * lr b2 += np.sum(d_output, axis=0, keepdims=True) * lr W1 += np.dot(X.T, d_hidden) * lr b1 += np.sum(d_hidden, axis=0, keepdims=True) * lr # 每 1000 次打印一次误差 if epoch % 1000 == 0: loss = np.mean(np.abs(error)) print(f"Epoch {epoch}, Loss: {loss:.4f}") # ========== 6. 输出结果 ========== print("\n训练完成后的预测输出:") print(final_output) 四、结果分析
输出结果示例:
Epoch 0, Loss: 0.51 Epoch 1000, Loss: 0.24 Epoch 2000, Loss: 0.12 Epoch 3000, Loss: 0.07 ... Epoch 9000, Loss: 0.03 训练完成后的预测输出: [[0.03] [0.97] [0.96] [0.04]] 预测效果如下表:
| 输入 | 期望输出 | 实际输出(约) |
|---|---|---|
| [0, 0] | 0 | 0.03 |
| [0, 1] | 1 | 0.97 |
| [1, 0] | 1 | 0.96 |
| [1, 1] | 0 | 0.04 |
模型已经非常成功地学习到了异或逻辑! 🎉
五、可视化:误差下降曲线
import matplotlib.pyplot as plt losses = [] for epoch in range(epochs): hidden_input = np.dot(X, W1) + b1 hidden_output = sigmoid(hidden_input) final_input = np.dot(hidden_output, W2) + b2 final_output = sigmoid(final_input) error = y - final_output losses.append(np.mean(np.abs(error))) d_output = error * sigmoid_derivative(final_output) d_hidden = np.dot(d_output, W2.T) * sigmoid_derivative(hidden_output) W2 += np.dot(hidden_output.T, d_output) * lr b2 += np.sum(d_output, axis=0, keepdims=True) * lr W1 += np.dot(X.T, d_hidden) * lr b1 += np.sum(d_hidden, axis=0, keepdims=True) * lr plt.plot(losses) plt.title("Loss 下降曲线") plt.xlabel("Epochs") plt.ylabel("Loss") plt.show() 输出图像显示误差从 0.5 逐步降到接近 0,说明模型在不断学习。
六、深入理解反向传播的数学逻辑
反向传播(Backpropagation)的关键是链式法则(Chain Rule)。
举例:
∂W2/∂L=∂A/2∂L⋅∂Z2/∂A2⋅∂W2/∂Z2
这其实就是在计算:
- 输出层误差如何影响权重;
- 隐藏层误差如何传播回去;
- 最终更新每一层的参数。
通过不断循环这个过程,网络就会“自我纠正”,让预测结果越来越接近真实值。
七、总结与扩展方向
✅ 本文我们手写了一个完整的神经网络,从:
- 原理推导
- 代码实现
- 训练过程
- 可视化结果
都进行了详细讲解。
📚 下一步建议:
- 使用 ReLU 替代 Sigmoid,提高收敛速度;
- 尝试多层网络,学习非线性更复杂的问题;
- 尝试分类任务(如 Iris 鸢尾花数据集);
- 对比纯 Python 与 TensorFlow 的实现性能差异。