用 Python 从零实现一个简单神经网络算法(含原理 + 代码 + 可视化讲解)

一、前言:为什么要自己实现神经网络?

很多人刚接触深度学习时,会直接用 TensorFlowPyTorch 等框架。
但如果没有理解背后的数学原理,很容易出现“只会调库不会调脑”的情况。

👉 因此,从零实现一个简单的神经网络,是入门深度学习最重要的一步。

在本文中,我们将一步步手写一个可以学习 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]00.03
[0, 1]10.97
[1, 0]10.96
[1, 1]00.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​

这其实就是在计算:

  • 输出层误差如何影响权重;
  • 隐藏层误差如何传播回去;
  • 最终更新每一层的参数。

通过不断循环这个过程,网络就会“自我纠正”,让预测结果越来越接近真实值。


七、总结与扩展方向

✅ 本文我们手写了一个完整的神经网络,从:

  • 原理推导
  • 代码实现
  • 训练过程
  • 可视化结果

都进行了详细讲解。

📚 下一步建议:

  1. 使用 ReLU 替代 Sigmoid,提高收敛速度;
  2. 尝试多层网络,学习非线性更复杂的问题;
  3. 尝试分类任务(如 Iris 鸢尾花数据集);
  4. 对比纯 Python 与 TensorFlow 的实现性能差异。

Read more

立知-lychee-rerank-mm行业落地:中小企业图文匹配提效指南

立知-lychee-rerank-mm行业落地:中小企业图文匹配提效指南 1. 为什么中小企业需要多模态重排序工具 想象一下这样的场景:你的电商网站有上千个商品,用户搜索"白色连衣裙",系统找到了50个相关商品,但排在前面的却是红色上衣和黑色裤子。这种情况每天都在发生,不仅影响用户体验,更直接导致订单流失。 传统的关键词匹配就像是用筛子筛沙子,只能根据字面意思匹配,无法理解"白色连衣裙"背后的真实需求可能是"夏季轻薄、修身款式、适合约会"。这就是为什么中小企业需要立知-lychee-rerank-mm这样的多模态重排序工具。 这个工具的核心价值在于:它能同时理解文字和图片的含义,像人一样判断内容的相关性。用户搜索"猫咪玩球",它不仅看文字描述中是否有"猫"和"球",还会分析图片中是否真的有猫在玩球的场景。 对中小企业的三大价值: * 提升转化率:让最相关的商品/内容排在最前面,用户更容易找到想要的 * 降低人工成本:

By Ne0inhk
深入剖析:按下 F5 后,浏览器前端究竟发生了什么?

深入剖析:按下 F5 后,浏览器前端究竟发生了什么?

文章目录 * 概述 * 一、关键前提:三种导航方式的本质区别 * 二、核心概念:强缓存 vs 协商缓存 * 1. 强缓存(Strong Caching) * 2. 协商缓存(Revalidation Caching) * 三、F5 刷新全景流程图 * 四、F5 刷新的完整生命周期详解 * 阶段一:主文档(HTML)的缓存验证与获取 * 阶段二:HTML 解析与渲染流水线(Critical Rendering Path) * 阶段三:子资源(CSS/JS/IMG)的缓存处理 * 五、对比总结:F5 与其他操作的本质差异 * 六、给前端开发者的实践建议 * 七、结语 概述 在前端开发中,

By Ne0inhk
【Spring Boot开发实战手册】掌握Springboot开发技巧和窍门(十三)前端匹配界面、后端匹配WebSocket

【Spring Boot开发实战手册】掌握Springboot开发技巧和窍门(十三)前端匹配界面、后端匹配WebSocket

前言 在现代 Web 开发中,前端和后端的协作变得越来越重要,特别是在需要实时交互和数据更新的应用场景中。WebSocket 技术作为一种全双工通信协议,使得前端和后端之间的实时数据传输变得更加高效和稳定。本篇博客将会探讨如何设计和实现一个实时匹配系统,其中前端负责展示用户界面并与后端进行交互,而后端则通过 WebSocket 协议来处理数据通信。 前端 onMounted: 当组件被挂载的时候执行的函数 onUnmonted: 当组件被卸载的时候执行的函数 初步调试阶段,我们是将token传进user.id的 store/pk.js: import ModuleUser from'./user'exportdefault{state:{socket:null,//ws链接opponent_username:"",opponent_photo:"",status:"matching",//matching表示匹配界面,playing表示对战界面},getters:

By Ne0inhk
OpenClaw dashboard命令后,无法登录web控制面板(在systemd服务无法启动的一些虚拟机里会碰到)

OpenClaw dashboard命令后,无法登录web控制面板(在systemd服务无法启动的一些虚拟机里会碰到)

先上结论 执行OpenClaw dashboard命令后,无法登录web控制面板,是因为OpenClaw的gateway服务没有起来。原来小龙虾OpenClaw 的命令没有学明白,先弄清楚命令: openclaw onboard 是配置 openclaw dashboard是显示web控制面板登录信息 openclaw gateway --verbose 是启动网关 openclaw gateway start是启动网关服务 问题就是因为这台系统的systemd没有起作用,导致openclaw的gateway服务没有起来,所以控制面板无法登录。 OpenClaw status Overview ┌─────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────┐ │ Item │ Value │ ├─────────────────┼────────────────────────────────────

By Ne0inhk