感知机(Perceptron)完全解析:单层神经网络的分类原理与训练实现 —— generative-ai-for-beginners RAG 数据篇
本文以仓库中 translations/de/15-rag-and-vector-databases/data/perceptron.md(同内容英文版见 15-rag-and-vector-databases/data/perceptron.md)为骨架展开,系统讲解感知机——现代神经网络最原始的单神经元模型——从 1957 年的硬件实现到数学建模、误差定义、梯度下降训练与 Python 编码的全过程。读者将理解"感知机=加权求和 + 阶跃激活"这一核心事实,掌握用权重向量做二分类的训练算法,并能把感知机知识作为知识库文档接入本仓库第 15 课 RAG(检索增强生成)应用进行检索与问答。
一、感知机:神经网络的起点
感知机是早期模仿现代神经网络的一次重要尝试。1957 年,康奈尔航空实验室的 Frank Rosenblatt 实现了名为 Mark-1 的硬件装置,它被设计用来识别三角形、正方形、圆形等基本几何图形。
从实现细节看,Mark-1 的输入图像由 20×20 的光电二极管阵列表示,这意味着网络拥有 400 个输入和 1 个二进制输出。这样一个"简单网络"只包含一个神经元,它也被称为阈值逻辑单元(Threshold Logic Unit)。当时网络中的权重被设计得类似电位器(Potentiometer)——一种允许使用者调节电路电阻的元件——必须在训练阶段被手动调节到合适的阻值。在当时,《纽约时报》甚至称感知机为"一台电子计算机的胚胎,海军期望它将能够行走、说话、观看、书写、自我复制并意识到自身的存在"。
需要说明的是:这些描述并非可运行的软件,而是感知机作为单层线性分类器的原始形态。对理解本文后续所有数学推导而言,只需记住两个要点——输入是固定维数的向量,输出是二值的类别(+1 / -1)。
二、感知机模型:一个加权求和加阶跃的函数
假设模型共有 N 个特征,那么输入向量就是 N 维向量 x。感知机是一个二分类模型,即它能区分两类输入数据。对每个输入向量 x,感知机的输出按所属类别被定义为 +1 或 -1,计算公式为:
y(x) = f(wᵀx)
其中 w 是权重向量,wᵀx 是权重与输入的内积(加权求和),而 f 是一个阶跃激活函数(step activation function)——当加权和超过阈值时输出一类,否则输出另一类。整个模型不包含隐藏层,也不存在任何非线性变换,因此它只能划分线性可分的两类数据;这也正是下一节训练目标得以化简的原因。
三、训练感知机:误差、感知机准则与梯度下降
3.1 目标:寻找使误差最小的权重向量 w
训练一个感知机,本质上就是寻找一个权重向量 w,使得绝大多数样本都被正确分类,也就是让某种误差最小。该误差由**感知机准则(perceptron criterion)**定义:
E(w) = -∑ wᵀxᵢ·tᵢ
其中:
- 求和仅针对被错误分类的训练数据点 i 进行;
- xᵢ 是输入数据;
- tᵢ 取 -1(负例)或 +1(正例)。
直观理解:如果一个正例被误判为负例,则 wᵀxᵢ 与 tᵢ 异号,乘积为负,累加进 E(w) 后会增大误差的绝对值,于是最小化 E(w) 就是在惩罚那些分类错误的方向。
3.2 优化方法:梯度下降(Gradient Descent)
误差 E 被看作权重 w 的函数,训练即是要最小化 E(w)。常用方法是梯度下降:从初始权重 w⁽⁰⁾ 出发,每一步按负梯度方向更新权重:
w⁽ᵗ⁺¹⁾ = w⁽ᵗ⁾ - η·∇E(w)
- η 称为学习率(learning rate),控制每次更新的步长;
- ∇E(w) 表示误差函数对权重的梯度。
计算该准则的梯度后,由于 E(w) 是对误分类样本的求和形式,梯度下降更新式可进一步化简为:
w⁽ᵗ⁺¹⁾ = w⁽ᵗ⁾ + ∑ η·xᵢ·tᵢ
即:每次迭代,对误分类样本 xᵢ,按 η·xᵢ·tᵢ 的方向修正权重——把权重朝"纠错"的方向移动。这正是感知机学习规则的本质:只有被分错的样本才会触发权重更新。
四、Python 实现:逐行拆解训练循环
原文档给出了如下训练算法(伪代码风格):
def train(positive_examples, negative_examples, num_iterations = 100, eta = 1):
weights = [0,0,0] # Initialize weights (almost randomly :)
for i in range(num_iterations):
pos = random.choice(positive_examples)
neg = random.choice(negative_examples)
z = np.dot(pos, weights) # compute perceptron output
if z < 0: # positive example classified as negative
weights = weights + eta*weights.shape
z = np.dot(neg, weights)
if z >= 0: # negative example classified as positive
weights = weights - eta*weights.shape
return weights
这段代码展示了感知机训练的三要素:
- 初始化:
weights = [0,0,0]将权重置零,对应"从初始权重 w⁽⁰⁾ 出发"; - 随机采样:每一轮从正例、负例中各随机抽一个样本(
random.choice),体现"用错分样本驱动更新"的思想; - 错分即更新:
z = np.dot(pos, weights)计算内积(感知机输出);若正例被判为负例(z < 0)则增大权重,若负例被判为正例(z >= 0)则减小权重——正好对应梯度下降推导出的更新式w ← w ± η·x·t。
需要指出(从代码结构可推断):原示例中
eta*weights.shape属于教学示意写法——weights.shape在 NumPy 中返回的是元组而非向量。若要在真实环境中运行,正确做法是把更新方向换成被错分的那个样本向量本身。一个可直接运行的等价实现如下:
import random
import numpy as np
def train(positive_examples, negative_examples, num_iterations=100, eta=1.0):
# 权重维度与单条样本特征数一致
dim = len(positive_examples[0])
weights = np.zeros(dim) # 初始权重置零
pos_examples = [np.array(p) for p in positive_examples]
neg_examples = [np.array(n) for n in negative_examples]
for i in range(num_iterations):
pos = random.choice(pos_examples) # 随机抽一个正例
neg = random.choice(neg_examples) # 随机抽一个负例
if np.dot(pos, weights) < 0: # 正例被误判为负例 -> 向正例方向修正
weights = weights + eta * pos
if np.dot(neg, weights) >= 0: # 负例被误判为正例 -> 向负例反方向修正
weights = weights - eta * neg
return weights
两者对照,可以清晰看到公式 w⁽ᵗ⁺¹⁾ = w⁽ᵗ⁾ + η·xᵢ·tᵢ 是如何落到代码里的:xᵢ·tᵢ 对于正例就是 +pos,对于负例就是 -neg,学习率 η 控制每次修正幅度。训练完成后,得到的权重向量即可用于对新样本做分类预测:np.dot(x, w) >= 0 判为正类,否则判为负类。
五、仓库中的延续:从单层感知机到更复杂的网络
感知机只是神经网络家族的起点,本仓库中还有两份与该文档配套的知识文档,可用于继续学习:
- data/own_framework.md:讲解多层感知机。其开篇即指出"上一节你学到的单层感知机是线性二分类模型",随后将其扩展为可做多分类、回归以及处理线性不可分数据的一般框架;文中把单层感知机的模型记为线性函数
f(x)=wx+b,并将训练统一抽象为"通过调整参数 θ 使损失最小化",进而引出随机梯度下降(SGD)、softmax、非线性激活函数与反向传播(backpropagation)——这正是感知机"加权求和 + 阶跃"思想在深度网络中的推广。 - data/frameworks.md:说明训练神经网络需要框架支持(如 TensorFlow、PyTorch),高层 API 将网络视为层序列,这与感知机"一个神经元即一层"的直觉一脉相承。
若想亲手实践完整的手写数字识别,可参考原文档作业:在完成二分类(区分两个手写数字)的基础上,进一步解决完整的数字分类问题——对给定图像判定其最可能对应哪一个数字。
六、实战视角:感知机文档如何成为 RAG 知识库
在 15-rag-and-vector-databases/README.md 的教学场景中,作者明确把"AI 初学者课程中的神经网络一课"作为用于锚定 LLM(grounding)的数据。因此本仓库 15-rag-and-vector-databases/data/ 下的三份文档——frameworks.md、own_framework.md、perceptron.md——正是被当作知识库文档使用。
这一用法在 notebook-rag-vector-databases.ipynb 中有直接证据:代码中通过 data_paths 显式加载三份数据文档(参见 notebook 中 data_paths = ["data/frameworks.md...", "data/own_framework.md...", "data/perceptron.md..."] 的定义),随后按照 RAG 的标准流水线处理:
- 切分(Chunking):把长文档拆成小块,控制进入模型的 token 规模;
- 向量化(Embedding):用嵌入模型把文本块转成数值向量;
- 建索引与检索(Index & Retrieval):用近邻搜索在索引中找到与用户问题最相似的文档块;
- 增强生成(Augmented Generation):把检索到的感知机相关内容拼进 prompt,交给 LLM(如
gpt-4o-mini)生成 grounded 回答——例如用户问 "what is a perceptron?",系统会先从感知机知识块中取上下文再作答,而不是仅依赖模型的预训练记忆。
从评估角度看,该课还讨论了groundedness(回答是否来自所给文档)、相关性、流畅度等指标——这也是把感知机这样的教学文档做成可检索知识库时验证答案质量的关键。
七、小结
通过本文你可以掌握三件事:第一,感知机是只有一个神经元的二分类模型,输出由 y(x)=f(wᵀx) 决定,f 是阶跃激活函数;第二,训练的目标是最小化感知机准则 E(w)=-∑wᵀxᵢtᵢ,采用梯度下降并按 w ← w + η·xᵢ·tᵢ 在误分类样本上修正权重;第三,这段知识与本仓库的 RAG 课程直接衔接——data/perceptron.md 被 notebook-rag-vector-databases.ipynb 作为知识库文档做切分、嵌入、索引与检索,用于让 LLM 的回答"扎根"于真实教材内容。若想进一步挑战自己,可尝试构建自己的感知机(例如借助可视化建模工具),并完成从二分类扩展到完整手写数字识别的课后练习。
说明:本文所引德文版由该翻译子仓库维护,其数学公式与英文原版(data/perceptron.md)一致;作为 RAG 数据源使用时,建议以仓库根目录的英文数据文档为权威基准。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00