Generative AI for Beginners 第 15 课知识语料解析:感知机——二分类模型、感知机准则与梯度下降训练
本文以 generative-ai-for-beginners 课程第 15 课(RAG 与向量数据库)配套教学语料 perceptron.md 为主体,系统讲解感知机(Perceptron)的诞生背景、数学模型、感知机准则、梯度下降训练流程与 Python 实现,并结合该语料在 RAG 知识库流水线中的真实用法(分块、向量化、检索)做补充说明。读完后你将掌握感知机的完整训练原理,能看懂并修正课程代码中的实现细节,同时理解这份"神经网络入门语料"如何作为示例数据支撑 RAG 应用。
这份文档在课程仓库中的定位
perceptron.md 是第 15 课 RAG(Retrieval Augmented Generation)实战的三份知识语料之一,与 frameworks.md、own_framework.md 共同构成"AI for Beginners 神经网络课程"的本地知识库。课程说明文档 README 中明确写道,该课会把这些神经网络课程文档作为 LLM 应用的 grounding 数据。
在配套笔记本 notebook-rag-vector-databases.ipynb 中,可以看到它被完整读入并进入 RAG 流水线:
data_paths = ["data/frameworks.md", "data/own_framework.md", "data/perceptron.md"]
rows = []
for path in data_paths:
with open(path, 'r', encoding='utf-8') as file:
file_content = file.read()
rows.append({'path': path, 'text': file_content})
df = pd.DataFrame(rows, columns=['path', 'text'])
后续流程将全文分块(chunking)、经嵌入模型转成向量并存入索引,最终用示例查询 what is a perceptron? 做语义检索——命中的正是本文件的内容。因此这份文档既是可独立学习的机器学习小课,也是 RAG 演示中被真实检索的语料,理解它有助于理解检索结果为什么与"感知机"相关。
仓库中还存在该文档的保加利亚语翻译版本 translations/bg/15-rag-and-vector-databases/data/perceptron.md,内容与英文原版一致,多语言版本用于课程的多语言站点;本文以英文原版结构为准进行讲解。
历史背景:1957 年的 Mark-1 硬件感知机
感知机由 Cornell Aeronautical Laboratory 的 Frank Rosenblatt 于 1957 年首次实现,这是最早接近现代神经网络雏形的尝试之一。Mark-1 是一台纯硬件设备,目标是识别三角形、正方形、圆等基础几何图形。原文档引用了维基百科的 Rosenblatt 肖像与 Mark-1 照片(对应 images/Rosenblatt-wikipedia.jpg、images/Mark_I_perceptron_wikipedia.jpg,当前仓库该目录未随附这两张图片,故此处仅引用文字描述)。
其关键硬件规格:
- 输入:一张输入图像由 20×20 的光电元件阵列(photocell array)采集,因此网络共有 400 个输入和 1 个二值输出;
- 结构:整个"简单网络"只含一个神经元,也称为阈值逻辑单元(threshold logic unit);
- 权重:神经网络权重表现为电位器(potentiometer),训练阶段需要人工手动调节。这里文档还补充了一个小常识:电位器是允许用户调节电路中电阻值的器件。
当时《纽约时报》对它的描述颇具时代色彩:一台电子计算机的胚胎,[美国海军]预计它能够行走、说话、看、书写、自我复制,并意识到自身的存在。 这段引文值得保留——它直观反映了上世纪 50 年代对神经计算能力边界的天真想象,而今天的课程正是从这台机器出发讲现代模型。
感知机的数学模型:一个二分类器
假设模型有 N 个特征,则输入向量 x 是 N 维向量。感知机是一个二分类(binary classification)模型,即只能在两个类别之间做区分。对任意输入向量 x,输出取 +1 或 -1,取决于所属类别,输出计算式为:
y(x) = f(wᵀx)
其中 f 是阶跃激活函数(step activation function):线性组合 wᵀx 经过阶跃函数后输出 +1 或 -1。从公式可以读出三个核心要素:
| 要素 | 含义 | 说明 |
|---|---|---|
| x | 输入特征向量,N 维 | 例如一张 2×2 图像的 4 个像素值 |
| w | 权重向量,N 维 | 决定每个特征对决策的贡献方向与强度 |
| f | 阶跃激活函数 | 将加权和映射为 +1 / -1 两个类 |
这个模型本质上是一条划分超平面 wᵀx = 0,落在哪一侧决定输出符号——这也是单层感知机只能处理线性可分问题的根源,后文会展开。
训练感知机:感知机准则与梯度下降
训练的目标是找到一个权重向量 w,使绝大多数样本被正确分类,即让错误最小。错误由**感知机准则(perceptron criterion)**定义:
E(w) = -Σ wᵀxᵢtᵢ
其中:
- 求和只针对被错误分类的训练样本 i(分类正确的样本不产生误差项);
- xᵢ 是输入数据,tᵢ 是标签:正样本取 +1,负样本取 -1。
把 E 视为权重 w 的函数,训练就是最小化 E(w)。常用方法是梯度下降(gradient descent):从某个初始权重 w⁽⁰⁾ 出发,每步按
w⁽ᵗ⁺¹⁾ = w⁽ᵗ⁾ - η∇E(w)
更新权重。其中 η 是学习率(learning rate),∇E(w) 是 E 对 w 的梯度。代入感知机准则的梯度后,得到文档给出的最终更新式:
w⁽ᵗ⁺¹⁾ = w⁽ᵗ⁾ + Σ η xᵢtᵢ
这条更新式有非常直观的几何含义:每个被分错的样本 xᵢ 都按自己的方向(正样本 +xᵢ、负样本 -xᵢ)把权重"推"过去一步,学习率 η 控制每次推动的幅度;只有分错的样本才参与修正,分对的样本不产生梯度贡献——这正是感知机准则把求和限制在误分类样本上的意义所在。
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
参数含义:num_iterations=100 为训练迭代轮数;eta=1 为学习率;weights=[0,0,0] 表示 2 维特征加 1 个偏置项(初始化为全零)。每一轮从正/负样本集中各随机抽一个样本,分别计算加权和 z,若正样本被判为负类(z < 0)则沿该样本方向修正权重,若负样本被判为正类(z ≥ 0)则反向修正。
但原代码有一处明显笔误:eta*weights.shape。weights 是普通列表,weights.shape 会抛 AttributeError;即便换成 NumPy 数组,.shape 返回的也是元组而非样本向量,无法表达权重更新。对照上一节的数学更新式 w ← w + Σ η xᵢtᵢ,更新方向应该是误分类样本本身(正样本 +pos、负样本 -neg)。结合原文还省略了 import random 与 import numpy as np,一个可直接运行的修正版本是:
import random
import numpy as np
def train(positive_examples, negative_examples, num_iterations=100, eta=1):
# 2 个特征 + 1 个偏置项,初始化为零
weights = [0.0, 0.0, 0.0]
for _ in range(num_iterations):
pos = random.choice(positive_examples)
neg = random.choice(negative_examples)
z = np.dot(pos, weights) # 计算感知机输出(加权和)
if z < 0: # 正样本被误判为负类
weights = [w + eta * d for w, d in zip(weights, pos)]
z = np.dot(neg, weights)
if z >= 0: # 负样本被误判为正类
weights = [w - eta * d for w, d in zip(weights, neg)]
return weights
这个实现与文档的推导完全一致:每次迭代对误分类样本执行 w ← w ± ηxᵢ,学习率由 eta 控制,迭代 num_iterations 轮后返回学到的权重。样本集可以是任何"特征 + 偏置位 1"构成的向量列表,例如把手写数字降采样为 2×2 像素后构造正负样本对——这也对应文档结尾作业中"在手写数字之间做二分类"的场景。
局限与延伸:从单层感知机到多层网络
单层感知机的能力边界是明确的:它只能解决线性可分的二分类问题。文档同目录的姊妹语料 own_framework.md 正好承接这一点,指出单层感知机是"线性二分类模型",并将其扩展为多层感知机(MLP):
- 引入非线性激活函数 α 与 softmax σ,使 f 可以逐层计算:z₁ = w₁x + b₁,z₂ = w₂α(z₁) + b₂,f = σ(z₂);
- 借助链式法则逐层回传求导,即反向传播(backpropagation),从而支持多分类与回归任务、分离非线性可分的类别;
- 优化上采用小批量随机梯度下降(SGD),每次只取随机采样的 minibatch 计算梯度。
也就是说,perceptron.md 讲的是"一个神经元 + 感知机准则"这一最简模型,own_framework.md 讲的是"堆叠成多层并用 backprop 训练",frameworks.md 则介绍现成的神经网络框架(TensorFlow、PyTorch、Keras)。三份语料恰好构成一条"从最简模型到工程框架"的学习路径——在 RAG 场景中,当用户问"what is a perceptron?"时,检索系统会命中 perceptron.md 的分块,而问"什么是反向传播"时则更可能命中 own_framework.md。
动手实践与延伸阅读
- 作业(Assignment):文档要求把二分类感知机推广为完整的数字识别任务——给定一张图像,判断它最可能是哪个数字,即从"两类判断"升级到"十类分类"。
- 挑战(Challenge):文档建议通过 Microsoft Learn 上基于 Azure ML Designer 的实验课动手搭建自己的感知机(此处按原文只保留文字指引,不附外部链接)。
- 自学者路径:从 notebook-rag-vector-databases.ipynb 开始,完整走一遍"分块 → 嵌入 → 建索引 → 语义检索 → LLM 生成"的 RAG 流程,你会看到本文讲解的感知机语料是如何被 chunk、被嵌入、再被
what is a perceptron?这一查询命中的,从而把本文的算法知识与第 15 课的向量检索实战真正串起来。
小结
本文围绕第 15 课的知识语料 perceptron.md 完成了以下主线:
- 历史:1957 年 Rosenblatt 的 Mark-1 硬件感知机——20×20 光电阵列(400 输入)、单一阈值逻辑单元、电位器手调权重;
- 模型:二分类器 y(x) = f(wᵀx),f 为阶跃函数,输出 +1 / -1;
- 训练:感知机准则 E(w) = -Σwᵀxᵢtᵢ(只对误分类样本求和),用梯度下降按 w⁽ᵗ⁺¹⁾ = w⁽ᵗ⁾ + Σηxᵢtᵢ 更新,η 为学习率;
- 实现:给出了参数注释完整的 Python 训练函数,并修正了原文档
weights.shape的笔误,使代码可运行; - 定位:该文档同时是 RAG 课被分块嵌入、被真实查询命中的知识库语料,与 own_framework.md(多层感知机与反向传播)、frameworks.md(神经网络框架)构成递进学习路径。
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