从感知机到多层感知机:理解梯度下降与反向传播,用 Python 搭建自己的神经网络框架
本文解析的关联文档是 translations/bn/15-rag-and-vector-databases/data/own_framework.md(英文原文见 15-rag-and-vector-databases/data/own_framework.md)。在 generative-ai-for-beginners 课程的第 15 课中,该文档与 perceptron.md、frameworks.md 一起被当作“知识库语料”喂入 RAG 检索增强生成示例 构建向量索引(见该 notebook 中
data_paths的定义),以演示向量检索的效果。
导读:这是一份神经网络基础讲义,完整讲解如何把上一节介绍的单层感知机推广为能处理多分类、回归与线性不可分数据的多层感知机(MLP),并用纯 Python 亲手搭建一个模块化的“自研框架”。读完本文,你将掌握机器学习的形式化建模、损失函数、随机梯度下降与反向传播(backprop)的完整推导脉络,理解主流深度学习框架在底层究竟做了什么。
从感知机到 MLP:为什么要“多层”
感知机文档 介绍的经典感知机是 1957 年 Frank Rosenblatt 提出的二分类线性模型:对每个输入向量 x,输出 +1 或 −1,即 y(x) = f(wᵀx),其中 f 是阶跃激活函数,训练目标是通过梯度下降找到使感知机准则误差最小的权重向量 w。
单层感知机有一个硬性天花板:它只能分开线性可分的类别。而本关联文档要解决的问题正是把这一模型升级成一个更灵活的框架,使其具备三种新能力:
- 除二分类外,还能执行多分类(multi-class classification);
- 除分类外,还能求解回归问题(regression);
- 能区分线性不可分的类别。
方案就是引入多个层并叠加非线性激活函数,同时用 Python 构建一个模块化的自研神经网络框架,用于拼装不同的网络架构。
机器学习的形式化:损失函数与参数
文档首先把机器学习问题形式化:设训练数据集为 X、标签为 Y,目标是构造模型 f,使其预测最准确。预测质量由损失函数(Loss function) ℒ 度量。常见损失函数分两类:
- 回归问题(预测一个数值):
- 绝对误差:Σᵢ|f(x⁽ⁱ⁾) − y⁽ⁱ⁾|
- 平方误差:Σᵢ(f(x⁽ⁱ⁾) − y⁽ⁱ⁾)²
- 分类问题:
- 0-1 损失(本质上等价于模型的准确率 accuracy)
- 逻辑损失(logistic loss)
对单层感知机,函数 f 定义为线性函数 f(x) = wx + b(w 为权重矩阵,x 为输入特征向量,b 为偏置向量);对不同网络架构,f 可以取更复杂的形式。
两个值得细读的补充点:
- softmax 归一化:分类场景下,通常希望网络输出各类别的概率。把任意实数向量转成概率,常用 softmax 函数 σ,此时 f 变为
f(x) = σ(wx + b)。softmax 保证输出值非负且和为 1,是后续多分类输出的关键。 - 参数的统一定义:上式中的 w 与 b 统称参数 θ = ⟨w, b⟩。给定数据集 ⟨X, Y⟩,就能把整个数据集上的总误差写成关于参数 θ 的函数。
✅ 神经网络训练的目标:通过调整参数 θ,使整体误差最小化。 这是后续梯度下降与反向传播两条技术主线的共同出发点。
梯度下降优化:沿负梯度方向迭代
函数优化的经典方法是梯度下降(gradient descent)。核心思想是:计算损失函数对各参数的导数(多维情形下称梯度),然后朝让误差减小的方向修改参数。形式化步骤如下:
- 用随机值初始化参数 w⁽⁰⁾、b⁽⁰⁾;
- 反复迭代更新:
w⁽ⁱ⁺¹⁾ = w⁽ⁱ⁾ − η·∂ℒ/∂wb⁽ⁱ⁺¹⁾ = b⁽ⁱ⁾ − η·∂ℒ/∂b
其中 η 为学习率(learning rate),控制每步更新的步长:η 过大容易震荡不收敛,η 过小收敛缓慢。严格来说,优化步应在整个数据集上计算(因为损失是对全部训练样本求和),但实际训练中我们只取数据集的一小部分——称为小批量(minibatch)——基于数据子集计算梯度;由于每次随机取样,这种方法称为随机梯度下降(Stochastic Gradient Descent,SGD)。这与 感知机文档 中展示的更新式 w⁽ᵗ⁺¹⁾ = w⁽ᵗ⁾ − η∇E(w) 一脉相承,只是从单权重推广到了全参数集。
多层感知机:前向传播的链式计算
为了拟合更丰富的函数,可将网络的多层叠加起来。数学上,函数 f 的计算变为多步链式:
z₁ = w₁x + b₁z₂ = w₂α(z₁) + b₂f = σ(z₂)
其中 α 是非线性激活函数,σ 是 softmax 函数,参数 θ = ⟨w₁, b₁, w₂, b₂⟩。引入 α 是 MLP 真正“变强”的原因:若没有非线性激活,无论堆叠多少层,整体仍是线性变换,模型表达能力不会超过单层感知机;只有插入非线性(如 sigmoid、ReLU 等)才能拟合线性不可分的决策边界。
提示:关于张量运算、激活函数/softmax 计算以及“为什么还需要框架帮我们自动算梯度”,可对照同目录的 frameworks.md。该文档明确指出:
numpy能完成张量乘加与 sigmoid、softmax 等函数计算,但梯度计算需要额外机制;在我们自研的框架中,所有导数函数此前都靠人手编写在backward方法里,理想框架应当能对任意可定义表达式自动求梯度,并支持 GPU/TPU 并行。
反向传播:从损失函数“倒着”算梯度
MLP 下梯度下降算法不变,但计算梯度更难。依据链式微分法则,各层权重的导数可逐级展开为:
∂ℒ/∂w₂ = (∂ℒ/∂σ)(∂σ/∂z₂)(∂z₂/∂w₂)∂ℒ/∂w₁ = (∂ℒ/∂σ)(∂σ/∂z₂)(∂z₂/∂α)(∂α/∂z₁)(∂z₁/∂w₁)
关键观察:上面每个表达式最左侧的因子完全相同——它们都共享从损失函数出发的部分。因此可以高效地从损失函数开始、沿着计算图“由后往前” 逐项求出各参数的导数,这就是反向传播(backpropagation),简称 “backprop”。
✅ 链式微分法则用于计算损失函数对各参数的导数。
反向传播的工程意义在于避免重复计算:前向传播先算各层输出,反向传播复用以损失为根的公共子表达式,一次反向遍历即可得到全部层参数 w₁、b₁、w₂、b₂ 的梯度,供 SGD 更新。这正是主流深度学习框架自动微分机制的雏形——frameworks.md 也提到,底层 API 的本质就是构建计算图(定义输入参数到输出/损失如何计算),再对图求导得到梯度用于优化;高层 API(Keras、PyTorch Lightning)则把网络视为层的序列,训练时调用 fit 即可。
从“自研框架”到理解主流框架
文档在本课中的落地场景是:用上述理论在配套 notebook 中亲手实现自己的 MLP 构建与训练框架,并借此看清现代神经网络的底层运作方式。对照仓库可知:
- 在 RAG 课的知识库构建环节,notebook-rag-vector-databases.ipynb 把
data/frameworks.md、data/own_framework.md、data/perceptron.md三份神经网络讲义作为文档语料读入(data_paths列表),切片后送入 Embedding 模型生成向量并建立索引;检索时再按向量距离返回文本片段。也就是说,这篇讲义本身既是一份神经网络“理论教材”,也是向量数据库实验里的“真实样本数据”。 - 理论层面,本文档属于一条完整的神经网络科普链条:感知机(二分类、线性)→ 多层感知机(多分类/回归/非线性,需反向传播)→ 框架与过拟合(见 frameworks.md 后半部分的过拟合与偏差-方差权衡讨论),从源码结构看,这与现代神经网络“先线性层、再激活、最终 softmax、用自动微分训练”的标准范式逐条对应。
结论
在本讲中,我们从数学上完成了机器学习问题的形式化(数据集 ⟨X,Y⟩、模型 f、损失函数 ℒ、参数 θ),推导了 SGD 的更新规则,把单层线性模型推广为带非线性激活的多层模型,并说明了反向传播为何能从损失出发沿计算图反向高效求导。实践上,我们据此构建了自己的神经网络库,并用它完成了一个简单的二维分类任务。
🚀 挑战:构建自己的 MLP 框架
按文档给出的任务路线:
- 在配套的 OwnFramework notebook 中,为构建与训练多层感知机实现你自己的框架;
- 借此一步步观察现代神经网络的前向计算、损失度量、梯度求解与参数更新是如何协作的;
- 用自研框架完成一个简单的二维分类任务(即上述结论中的实践验证)。
文档提示,backprop 更细节的讨论将在 notebook 示例中展开,建议先通读本文再动手写代码,实现时把 forward(前向求 z₁、z₂、f)与 backward(链式求各层梯度)拆成对称、模块化的结构,你的框架就能自然扩展到更多隐藏层与不同激活函数。
复习与自学建议
反向传播是 AI/ML 领域的通用核心算法,值得深入钻研。补充研读建议:
- 对照 感知机文档,先吃透单层情形(权重更新式、学习率 η、误差准则),再回到本文理解多层推广;
- 阅读 frameworks.md,弄清低级 API(TensorFlow / PyTorch)与高级 API(Keras / PyTorch Lightning)各自解决什么问题、为何需要张量框架自动求梯度并支持 GPU/TPU 并行,以及两层 API 如何混用;
- 动手推导两层网络对 w₁ 与 w₂ 的梯度展开式,体会“公共左因子复用”正是 backprop 高效的原因。
作业:MNIST 手写数字分类
本实验要求使用本讲构建的框架,解决 MNIST 手写数字分类问题:即根据每张 28×28 灰度手写数字图像,判定其对应 0–9 中的哪个数字。这正好把文中的两项能力用满:
- 输出层使用 softmax 将 logits 映射为 10 个类别的概率分布;
- 训练全程依赖随机梯度下降 + 反向传播更新网络参数。
作业包含配套的说明文档与 notebook(可在第 15 课 RAG 知识库构建路径 15-rag-and-vector-databases 下定位),完成时建议保留训练/验证误差曲线,警惕过拟合——这一点与 frameworks.md 后半部分的偏差-方差权衡、早停与正则化(如 Dropout)内容直接相关,可作为进阶阅读闭环。
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 StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00