基于 Numpy 实现感知机模型构建与训练详解
详细讲解了感知机模型的数学原理及其基于 Numpy 的实现。内容涵盖感知机的线性分类特性、学习策略(最小化误分类点到超平面距离)、参数更新过程以及 SGD 优化方法。通过完整代码示例展示了如何构建数据、初始化模型、训练迭代及测试评估。同时分析了感知机在异或问题上的局限性,并引出多层感知机(MLP)的概念作为扩展解决方案。

详细讲解了感知机模型的数学原理及其基于 Numpy 的实现。内容涵盖感知机的线性分类特性、学习策略(最小化误分类点到超平面距离)、参数更新过程以及 SGD 优化方法。通过完整代码示例展示了如何构建数据、初始化模型、训练迭代及测试评估。同时分析了感知机在异或问题上的局限性,并引出多层感知机(MLP)的概念作为扩展解决方案。

感知机(Perceptron)是神经网络和深度学习领域中最基础的模型之一,由 Frank Rosenblatt 于 1957 年提出。它本质上是一个二分类的线性分类器,其输入空间为特征向量,输出空间为类别标记(通常为 +1 或 -1)。感知机的结构非常简单,仅包含一个神经元,通过加权求和与激活函数来决定样本的归属。
尽管结构简单,感知机在机器学习发展史上具有里程碑意义。它是许多复杂模型的基础,理解感知机有助于深入掌握后续的逻辑回归、支持向量机以及多层感知机等算法的核心思想。
感知机试图找到一个超平面,将不同类别的数据点分开。假设输入向量为 $x \in \mathbb{R}^d$,权重向量为 $w \in \mathbb{R}^d$,偏置为 $b \in \mathbb{R}$。感知机的预测函数定义为:
$$f(x) = \text{sign}(w^T x + b)$$
其中,$\text{sign}$ 是符号函数:
该超平面方程为 $w^T x + b = 0$。法向量 $w$ 决定了超平面的方向,偏置 $b$ 决定了超平面距离原点的距离。
感知机的目标是找到一组参数 $(w, b)$,使得训练集中的所有样本都能被正确分类。直接最小化误分类点的个数是不可微的,因此感知机采用最小化误分类点到超平面的距离作为损失函数。
对于任意一个误分类点 $(x_i, y_i)$,其到超平面的距离为: $$\frac{1}{||w||}(-y_i(w^T x_i + b))$$ 忽略常数项 $\frac{1}{||w||}$,感知机的损失函数定义为所有误分类点距离之和: $$L(w, b) = -\sum_{i \in M} y_i(w^T x_i + b)$$ 其中 $M$ 为误分类点的集合。
为了最小化损失函数,通常使用随机梯度下降法(SGD)进行参数更新。对损失函数关于 $w$ 和 $b$ 求偏导: $$\nabla_w L(w, b) = -\sum_{i \in M} y_i x_i$$ $$\nabla_b L(w, b) = -\sum_{i \in M} y_i$$
每次迭代时,随机选取一个误分类点 $(x_i, y_i)$,更新规则如下: $$w \leftarrow w + \eta y_i x_i$$ $$b \leftarrow b + \eta y_i$$
其中 $\eta$ 为学习率(Learning Rate),控制更新的步长。
以下代码完整展示了感知机的数据准备、模型初始化、训练循环及测试评估过程。代码中已修复原始逻辑中的变量作用域问题,并统一了标签范围(-1/1)。
import numpy as np
def prepare_data(n=100, input_size=2):
"""
生成模拟的二分类数据,用于演示 OR 门逻辑
:param n: 样本数量
:param input_size: 特征维度
:return: 输入数据 X,标签 Y
"""
def OR_gate(x):
# 简单的 OR 逻辑:只要有一个特征大于 0.5 则为正类
w_true = np.array([0.5, 0.5])
b_true = -0.4
tmp = np.sum(w_true * x) + b_true
return 1 if tmp > 0 else -1
# 生成随机输入数据,范围 [-1, 1]
inputs = np.random.randn(n, input_size)
# 计算真实标签
labels = np.array([OR_gate(inputs[i]) for i in range(n)])
return inputs, labels
class Perceptron:
"""
单神经元感知机模型
"""
def __init__(self, input_size, lr=0.01):
# 初始化权重为随机小值
self.w = np.random.randn(input_size) * 0.01
# 初始化偏置
self.b = np.random.randn(1) * 0.01
# 学习率
self.lr = lr
def predict(self, x):
"""
预测单个样本的类别
:param x: 输入特征向量
:return: 预测类别 (-1 或 1)
"""
tmp = np.dot(self.w, x) + self.b[0]
return 1 if tmp > 0 else -1
def update(self, x, y):
"""
根据误分类样本更新参数
:param x: 输入特征向量
:param y: 真实标签 (-1 或 1)
"""
# 梯度下降更新规则
self.w = self.w + self.lr * y * x
self.b = self.b + self.lr * y
if __name__ == "__main__":
# 配置参数
n_samples = 1000
train_ratio = 0.8
input_dim = 2
learning_rate = 0.01
epochs = 100
print(f"正在生成 {n_samples} 个训练样本...")
X, Y = prepare_data(n=n_samples, input_size=input_dim)
# 划分训练集和测试集
split_idx = int(n_samples * train_ratio)
train_X, train_Y = X[:split_idx], Y[:split_idx]
test_X, test_Y = X[split_idx:], Y[split_idx:]
# 初始化模型
model = Perceptron(input_size=input_dim, lr=learning_rate)
# 打印初始预测示例
sample_idx = 0
pred_init = model.predict(train_X[sample_idx])
print(f"初始预测示例 - 输入:{train_X[sample_idx]}, 真实:{train_Y[sample_idx]}, 预测:{pred_init}")
# 开始训练
print("\n开始训练...")
for epoch in range(epochs):
loss = 0
wrong_indices = []
# 遍历训练集统计损失和错误样本
for idx in range(len(train_X)):
pred_y = model.predict(train_X[idx])
if pred_y != train_Y[idx]:
wrong_indices.append(idx)
# 计算当前误分类点到超平面的距离作为损失
margin = abs(np.dot(model.w, train_X[idx]) + model.b[0])
loss += margin
# 输出每轮训练情况
if (epoch + 1) % 10 == 0 or epoch == 0:
print(f"Epoch {epoch + 1}/{epochs} | 错误样本数:{len(wrong_indices)} | 总损失:{loss:.4f}")
# 如果无错误样本,提前终止
if len(wrong_indices) == 0:
print("训练收敛,无错误样本")
break
# 更新参数
for idx in wrong_indices:
model.update(train_X[idx], train_Y[idx])
# 测试评估
print("\n开始测试...")
test_wrong_num = 0
test_loss = 0.0
for j in range(test_X.shape[0]):
pred_y = model.predict(test_X[j])
if pred_y != test_Y[j]:
test_wrong_num += 1
margin = abs(np.dot(model.w, test_X[j]) + model.b[0])
test_loss += margin
print(f"测试集错误样本数:{test_wrong_num} / {test_X.shape[0]}")
print(f"测试集总损失:{test_loss:.4f}")
print(f"最终权重 w: {model.w}, 偏置 b: {model.b[0]:.4f}")
在上述实现中,我们观察到了以下几个关键点:
prepare_data 生成了 OR 门数据,这是典型的线性可分问题,因此训练通常会收敛。lr 过大可能导致震荡无法收敛,过小则收敛速度慢。在实际应用中,通常需要根据验证集表现调整。感知机只能处理线性可分的数据。最著名的反例是异或(XOR)问题。XOR 的真值表如下:
在二维平面上,XOR 的正负样本点呈对角分布,无法用一条直线完全分开。这意味着无论怎么调整 $w$ 和 $b$,感知机都无法完美拟合 XOR 数据,训练误差将无法降为零。
为了解决非线性问题,可以将多个感知机组合起来,形成多层感知机(Multi-Layer Perceptron, MLP)。通过引入隐藏层和非线性激活函数(如 Sigmoid, ReLU),MLP 具备了万能近似定理的能力,即给定足够多的隐藏单元,它可以近似任意连续函数。
例如,可以通过组合 AND、OR、NOT 三个感知机来构建 XOR 逻辑电路。这种深度结构的引入标志着从传统机器学习向深度学习的跨越。
此外,感知机也是逻辑回归(LR)和支持向量机(SVM)的理论基础。它们共享类似的线性判别函数形式,但在损失函数和优化目标上有所区别,以适应不同的应用场景。
本文详细讲解了感知机模型的数学原理及其基于 Numpy 的实现。内容涵盖感知机的线性分类特性、学习策略(最小化误分类点到超平面距离)、参数更新过程以及 SGD 优化方法。通过完整代码示例展示了如何构建数据、初始化模型、训练迭代及测试评估。同时分析了感知机在异或问题上的局限性,并引出多层感知机(MLP)的概念作为扩展解决方案。掌握感知机是深入理解现代深度学习架构的重要第一步。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online