Python神经网络编程(一):预测器、分类器与神经网络基础概念
本文是《Python神经网络编程》系列博客的第1篇,基于真实服务器实操输出,涵盖实验1-2的所有内容。
服务器环境:Ubuntu 24.04 / Python 3.12.3 / NumPy 2.5.1 / Matplotlib 3.11.0
服务器:华为云 ecs-1f62-0001 (120.46.93.164)
目录
- 你将学到什么
- 实验1:预测器与分类器
- 实验2:多分类器与神经网络
- 总结
- 下一篇预告
你将学到什么
在本篇博客中,你将通过从零开始的数学推导和Python代码实操,理解神经网络的核心概念:
- 预测器(Predictor):线性回归如何工作
- 分类器(Classifier):从回归到分类的跨越
- 线性分类器的局限性:为什么XOR问题无法用一条直线解决
- 激活函数(Activation Function):给神经网络引入非线性
- 神经网络的结构:从单层到多层,从线性到非线性
实验1:预测器与分类器
1.1 人工智能的概念
人工智能(Artificial Intelligence, AI)的本质是让机器能够模拟人类的智能行为,包括学习、推理、感知和决策。
神经网络是人工智能的一个重要分支,它受到生物神经网络的启发:
生物神经网络 人工神经网络 ┌──────────┐ ┌──────────┐ │ 神经元 │ │ 节点 │ │ (Neuron) │ ←类比→ │ (Node) │ └──────────┘ └──────────┘ │ │ ▼ ▼ 树突接收信号 加权求和 + 激活函数 轴突传递信号 输出到下一层1.2 预测机(Predictor)
预测器是一个简单的数学模型,用于根据输入预测输出。
核心公式
y = w × x + b其中:
x:输入(特征)y:输出(预测值)w:权重(weight),表示输入对输出的影响程度b:偏置(bias),表示当输入为0时的输出
Python实现:简单线性预测器
importnumpyasnp# 简单线性预测器defpredict(x,w,b):"""简单的线性预测器"""returnw*x+b# 示例:根据学习时间预测考试分数# 训练数据:(学习时间, 考试分数)training_data=[[1.0,35.0],[2.0,48.0],[3.0,62.0],[4.0,75.0],[5.0,85.0],[6.0,92.0]]# 使用最小二乘法计算权重w和偏置b# 公式:w = Σ((x_i - x_mean)(y_i - y_mean)) / Σ((x_i - x_mean)²)# b = y_mean - w * x_meanx=np.array([d[0]fordintraining_data])y=np.array([d[1]fordintraining_data])x_mean=np.mean(x)y_mean=np.mean(y)w=np.sum((x-x_mean)*(y-y_mean))/np.sum((x-x_mean)**2)b=y_mean-w*x_meanprint(f"训练数据:{training_data}")print(f"计算得到: w ={w:.4f}, b ={b:.4f}")print(f"预测函数: y ={w:.4f}* x +{b:.4f}")# 预测fortest_xin[3.5,7,8]:pred_y=predict(test_x,w,b)print(f" 学习{test_x}小时 -> 预测分数:{pred_y:.1f}")服务器真实输出:
训练数据: [[1.0, 35.0], [2.0, 48.0], [3.0, 62.0], [4.0, 75.0], [5.0, 85.0], [6.0, 92.0]] 计算得到: w = 11.6857, b = 25.2667 预测函数: y = 11.6857 * x + 25.2667 学习 3.5 小时 -> 预测分数: 66.2 学习 7 小时 -> 预测分数: 107.1 学习 8 小时 -> 预测分数: 118.8最小二乘法推导
目标:找到一条直线y = wx + b,使得所有样本点到直线的垂直距离平方和最小。
误差函数(Loss Function):
E = Σ(y_i - (w × x_i + b))²求解:对w和b求偏导,令偏导为0:
∂E/∂w = -2 × Σ(y_i - w×x_i - b) × x_i = 0 ∂E/∂b = -2 × Σ(y_i - w×x_i - b) = 0解方程组得到:
w = Σ((x_i - x_mean)(y_i - y_mean)) / Σ((x_i - x_mean)²) b = y_mean - w × x_mean1.3 分类机(Classifier)
分类器将输入映射到离散的类别标签,而不是连续值。
从预测到分类
预测器的输出是连续值(如分数 66.2),而分类器的输出是类别(如"及格"/“不及格”)。
方法:设置一个阈值(threshold),将连续输出转换为类别。
# 简单分类器defclassify(score,threshold=60):"""根据分数判断是否及格"""return"及格"ifscore>=thresholdelse"不及格"# 测试forhoursin[1,2,3,4,5,6]:score=predict(hours,w,b)label=classify(score)print(f" 学习{hours}小时, 分数{score:.0f}->{label}")服务器真实输出:
学习 1 小时, 分数 35 -> 不及格 学习 2 小时, 分数 48 -> 不及格 学习 3 小时, 分数 62 -> 及格 学习 4 小时, 分数 75 -> 及格 学习 5 小时, 分数 85 -> 及格 学习 6 小时, 分数 92 -> 及格实验2:多分类器与神经网络
2.1 线性分类器的局限
线性分类器只能用一个**超平面(在2D中是直线)**来划分两类数据。
XOR问题:线性不可分
XOR(异或)是一个经典的线性不可分问题:
| 输入A | 输入B | XOR输出 |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
在2D平面上,XOR的输出分布如下:
B=1 │ 1 0 │ B=0───┼───B=1 │ │ 0 1 B=0 A=0 A=1无法用一条直线将"1"和"0"分开!这就是线性分类器的局限性。
可视化:线性分类器的局限
(图1:线性分类器无法用一条直线将XOR的两类分开)
2.2 激活函数的意义
激活函数(Activation Function)是神经网络的灵魂,它引入了非线性,使得神经网络可以拟合任意复杂的函数。
常见激活函数
| 激活函数 | 公式 | 输出范围 | 特点 |
|---|---|---|---|
| Step | 0 if x<0 else 1 | {0, 1} | 最早使用,不可导 |
| Sigmoid | 1 / (1 + e^(-x)) | (0, 1) | 平滑,可导,梯度消失 |
| Tanh | (e^x - e^(-x)) / (e^x + e^(-x)) | (-1, 1) | 零中心,梯度消失 |
| ReLU | max(0, x) | [0, +∞) | 计算简单,缓解梯度消失 |
Python实现:激活函数对比
importnumpyasnpimportmatplotlib.pyplotaspltdefsigmoid(x):return1/(1+np.exp(-x))deftanh(x):returnnp.tanh(x)defrelu(x):returnnp.maximum(0,x)defstep(x):returnnp.where(x>=0,1,0)# 测试各激活函数x_values=[-2,-1,0,1,2]print(f"{'x':>4}|{'Sigmoid':>12}|{'Tanh':>12}|{'ReLU':>12}|{'Step':>10}")print("-"*60)forxinx_values:s=sigmoid(x)t=tanh(x)r=relu(x)st=step(x)print(f"{x:>4}|{s:>12.4f}|{t:>12.4f}|{r:>12.4f}|{st:>10.0f}")服务器真实输出:
x | Sigmoid | Tanh | ReLU | Step ------------------------------------------------------------ -2 | 0.1192 | -0.9640 | 0.0000 | 0 -1 | 0.2689 | -0.7616 | 0.0000 | 0 0 | 0.5000 | 0.0000 | 0.0000 | 1 1 | 0.7311 | 0.7616 | 1.0000 | 1 2 | 0.8808 | 0.9640 | 2.0000 | 1可视化:激活函数对比
(图2:4种常见激活函数的曲线对比)
2.3 神经网络的起源
神经网络的灵感来自于生物大脑:
生物神经元 人工神经元 ─────── ───────── Dendrite ───► 树突 输入 x1, x2, ..., xn │ │ ▼ ▼ Cell Body ───► 细胞体 加权求和 + 偏置 │ │ ▼ ▼ Axon ───► 轴突 激活函数 │ │ ▼ ▼ Synapse ───► 突触 输出 y人工神经元的数学模型:
y = activation(Σ(w_i × x_i) + b)2.4 神经网络的结构
三层神经网络
输入层 隐藏层 输出层 (3个节点) (3个节点) (2个节点) x1 ──w11──→ h1 ──w'11──→ o1 ╲ ╱ ╲ ╱ ╲╱ ╲╱ ╱╲ ╱╲ ╱ ╲ ╱ ╲ x2 ──w22──→ h2 ──w'22──→ o2 ╲ ╱ ╱ ╲ ╲╱ ╱ ╲ ╱╲ ╲ ╱ ╱ ╲ ╲ ╱ x3 ──w33──→ h3 ──w'33──→ 每个连接都有一个权重 w 全连接(Fully Connected): 每个节点与下一层所有节点相连参数数量计算
对于网络结构3-3-2:
输入层 -> 隐藏层:3 × 3 = 9 个权重 隐藏层 -> 输出层:3 × 2 = 6 个权重 偏置:3(隐藏层)+ 2(输出层)= 5 个 总参数:9 + 6 + 5 = 20 个通用公式:对于网络n_0 - n_1 - n_2 - ... - n_L:
总参数 = Σ(n_i × n_{i+1}) + Σ(n_i) (i从0到L-1) ↑ ↑ 层间权重 每层的偏置2.5 模型训练的本质
训练的本质是调整权重和偏置,使得网络的输出尽可能接近目标输出。
训练流程
1. 初始化权重(随机或小值) ↓ 2. 正向传播(Forward Propagation) - 输入 -> 隐藏层 -> 输出层 - 计算当前输出 ↓ 3. 计算误差(Loss) - Loss = target - output ↓ 4. 反向传播(Backward Propagation) - 将误差从输出层传回输入层 - 计算每个权重对误差的贡献 ↓ 5. 更新权重 - w_new = w_old - η × ∂Loss/∂w ↓ 6. 重复步骤2-5(多轮训练)2.6 全连接的意义
全连接(Fully Connected)意味着上一层每个节点都与下一层每个节点相连。
为什么全连接?
- 信息最大化:每个节点都能接收到上一层所有节点的信息
- 表达能力最强:理论上可以拟合任意函数(万能近似定理)
- 梯度传播充分:误差可以传播到每一个权重
计算量分析
全连接层的计算复杂度:
对于层A(n个节点)-> 层B(m个节点): - 权重矩阵大小:m × n - 一次前向传播:O(m × n) 次乘法 - 一次反向传播:O(m × n) 次乘法示例:MNIST网络784-100-10
输入层 -> 隐藏层:784 × 100 = 78,400 个权重 隐藏层 -> 输出层:100 × 10 = 1,000 个权重 总权重:79,400 个总结
在本篇博客中,我们学习了:
- 预测器:用线性回归模型根据输入预测输出
- 分类器:用阈值将连续输出转换为类别标签
- 线性分类器的局限:XOR问题无法用一条直线解决
- 激活函数:Sigmoid、Tanh、ReLU等引入非线性
- 神经网络结构:多层神经元,全连接
- 训练的本质:通过调整权重最小化误差
关键公式回顾:
预测器:y = w × x + b 神经元:y = activation(Σ(w_i × x_i) + b) Sigmoid:σ(x) = 1 / (1 + e^(-x)) 参数数量:Σ(n_i × n_{i+1}) + Σ(n_i)下一篇预告
第2篇:神经网络的正向传播与误差的反向传播
你将学习:
- 矩阵运算在神经网络中的应用
- 信号如何在多层网络中传播
- 误差如何反向传播到每一层
- 每个权重对误差的贡献如何计算
参考文献:
- Tariq Rashid, 《Python神经网络编程》
- Ian Goodfellow 等, 《深度学习》
- MNIST数据库:http://yann.lecun.com/exdb/mnist/
代码仓库:本文所有代码可在服务器/root/nn_blog/目录下找到。
作者:腾讯DevOps工程师 | 最后更新:2026年7月