自研神经网络框架实战:多层感知机、梯度下降与反向传播全解析(generative-ai-for-beginners 配套指南)
本指南以 generative-ai-for-beginners 仓库内 15-rag-and-vector-databases/data/ 目录下的专题文档为核心,系统讲解如何将单层感知机扩展为多层感知机(MLP):从机器学习问题的形式化、常见损失函数,到梯度下降 / 随机梯度下降的更新规则,再到前向计算、链式法则与反向传播(backprop)的原理推导。读完你将能够理解神经网络"从数据中学习"的完整闭环,并为在配套 notebook 中亲手实现一个可复用的模块化神经网络框架、完成 MNIST 手写数字分类实验打下坚实的数学与代码基础。
一、本文档在仓库中的定位与阅读前提
本专题的英文原版位于 data/own_framework.md,并提供了多语言译本,例如 希腊语译本 translations/el/15-rag-and-vector-databases/data/own_framework.md。该文件在仓库中承担着双重角色:
- 作为一份独立的技术教程,它是"神经网络从零构建"系列中承上启下的一讲;
- 作为第 15 课(RAG 与向量数据库)的示例语料,RAG 示例 notebook 中的
data_paths把data/frameworks.md、data/own_framework.md、data/perceptron.md等 Markdown 文件当作真实文档切块后构建向量索引,用于演示检索增强生成全流程。
阅读本文前,建议先掌握先导篇 感知机(Perceptron):它介绍了 Frank Rosenblatt 1957 年的 Mark-1 硬件感知机、二元分类模型 y(x) = f(wᵀx)、步阶激活函数,以及基于感知机准则 E(w) = -∑wᵀxᵢtᵢ 的梯度下降训练法和一段约 10 行的 Python 训练伪代码。而 框架导览篇(Frameworks) 则站在更高视角说明:训练神经网络需要两类基本能力——张量运算(乘法、加法、sigmoid/softmax 等)与梯度自动计算,并对比了 TensorFlow/Keras 与 PyTorch/PyTorch Lightning 的低层、高层 API。
本文聚焦的就是这个承上启下的中间环节:在单层线性模型之上,加入非线性激活与多层堆叠,把模型推广到多分类、回归乃至非线性可分问题,并从数学上拆解训练所需的反向传播原理。
二、机器学习问题的形式化:数据集、模型与损失函数
本讲首先把机器学习问题做了一次标准化的数学抽象。假设我们有一个带标签的训练集 X(输入数据)与 Y(标签),需要构造一个模型 f,使其做出的预测尽可能准确。预测质量由**损失函数(loss function)**ℒ 度量。文档给出了不同任务下最常使用的两类损失函数:
| 任务类型 | 损失函数 | 数学形式 | 说明 |
|---|---|---|---|
| 回归(预测一个数值) | 绝对误差 | ∑ᵢ|f(x⁽ⁱ⁾) − y⁽ⁱ⁾| | 对离群点更鲁棒 |
| 回归(预测一个数值) | 平方误差 | ∑ᵢ(f(x⁽ⁱ⁾) − y⁽ⁱ⁾)² | 对大误差惩罚更重 |
| 分类 | 0-1 loss | —— | 本质上等价于模型"准确率" |
| 分类 | 逻辑损失(logistic loss) | —— | 平滑可导,利于梯度优化 |
对于单层感知机,模型 f 被定义为线性函数:
f(x) = wx + b
其中 w 是权重矩阵,x 是输入特征向量,b 是偏置向量。而对于更复杂的神经网络架构,f 会呈现出更复杂的复合形式。
值得注意的一点是文档中的提示:在做分类任务时,通常希望网络输出的是各类别的概率。为了把任意实数转化为概率(即对输出做归一化),常用 softmax 函数 σ,此时模型变为:
f(x) = σ(wx + b)
在上述 f 的定义里,w 与 b 被统称为参数 θ = ⟨w, b⟩。给定数据集 ⟨X, Y⟩ 后,我们可以把整个数据集上的总体误差写成参数 θ 的函数。
✅ 神经网络训练的目标,就是通过改变参数 θ 来最小化误差。
三、梯度下降与随机梯度下降(SGD)
函数优化有一个经典方法,叫做梯度下降(gradient descent)。核心思想是:计算损失函数关于各参数的导数(在多维情形下称为梯度 gradient),然后沿误差减小的方向调整参数。其形式化过程如下:
- 用随机值初始化参数 w⁽⁰⁾、b⁽⁰⁾;
- 反复执行下面的更新步骤:
- w⁽ⁱ⁺¹⁾ = w⁽ⁱ⁾ − η·∂ℒ/∂w
- b⁽ⁱ⁺¹⁾ = b⁽ⁱ⁾ − η·∂ℒ/∂b
这里的 η 即学习率(learning rate),控制每次参数更新的步长;∂ℒ/∂w、∂ℒ/∂b 表示损失对权重和偏置的偏导数。
在实际训练中,如果每一步都基于整个数据集计算损失(回顾:损失是所有训练样本误差的加和),代价会非常高昂。因此在工程实践中会每次取数据集的一小部分,称为 minibatch(小批量),仅基于这批子集计算梯度。由于子集是每次随机抽取的,这种方法被称为随机梯度下降(Stochastic Gradient Descent,SGD)。这一"用子样本近似全量梯度"的做法,正是现代深度学习训练框架在高维、海量数据场景下依然高效的原因。
补充:本文档引用的 感知机先导篇 中给出的感知机权重更新式
w⁽ᵗ⁺¹⁾ = w⁽ᵗ⁾ + ∑η·xᵢ·tᵢ,正是上面通用梯度下降公式在单层线性分类器上的特例——可见本文的公式体系是对上一讲的直接推广。
四、多层感知机:从线性可分到非线性模型
单层网络正如前面所见,只能分类线性可分的类别。为了构造更丰富的模型,我们把多个网络层组合起来。数学上这意味着函数 f 拥有更复杂的形式,并按多个步骤前向计算:
- z₁ = w₁x + b₁
- z₂ = w₂α(z₁) + b₂
- f = σ(z₂)
其中:
- α 是非线性激活函数(non-linear activation function)——正是它的存在使多层堆叠不再退化为单个线性变换,从而让网络能够划分非线性可分的类别、逼近复杂的决策边界;
- σ 是 softmax 函数,负责把最后一层的输出归一化为类别概率;
- 此时参数集扩展为 θ = ⟨w₁, b₁, w₂, b₂⟩。
这套"若干层权重变换 + 非线性激活 + 最终 softmax"的骨架,就是后面所有更复杂神经网络架构(包括本仓库第 17 课 AI Agent 中涉及的语言模型链路)共享的底层计算范式。
五、链式法则与反向传播(Backpropagation)
多层化之后,梯度下降算法本身没有变化——我们依然要最小化损失——但梯度的计算变得困难了。幸运的是,借助微积分中的链式法则(chain differentiation rule),可以逐层求出导数:
- ∂ℒ/∂w₂ = (∂ℒ/∂σ)·(∂σ/∂z₂)·(∂z₂/∂w₂)
- ∂ℒ/∂w₁ = (∂ℒ/∂σ)·(∂σ/∂z₂)·(∂z₂/∂α)·(∂α/∂z₁)·(∂z₁/∂w₁)
✅ 链式法则用于计算损失函数对每一个参数的偏导数。
请注意上面两个表达式的最左端因子完全相同(都是 (∂ℒ/∂σ)·(∂σ/∂z₂) 这部分乘积的开头),这意味着我们可以从损失函数出发,沿着计算图"反向"逐层复用已算出的梯度,从而高效地计算出所有参数的偏导数——而无需为每一层重复求最外层的导数。这种"从输出端向输入端逐层回传误差梯度"的训练方法,就是反向传播(backpropagation),简称 backprop。
反向传播的意义在于:它将"对复合函数求梯度"这个貌似需要大量独立求导的问题,转化为一次前向传播 + 一次逆向的动态规划式复用,使深层网络的训练在计算上变得可行。这正是 框架导览篇 中所强调的"框架需要能对任意表达式求梯度"这一能力背后的算法基石。
六、配套实践:从手写框架到 MNIST 分类实验
本讲末尾给出了一条明确的动手路线:
- 结论(Conclusion):在这一课中,你应当亲手构建出自己的神经网络库,并用它解决一个简单的二维分类问题,从而直观验证框架的可用性;
- 挑战(Challenge):在配套的 OwnFramework notebook 中,自己动手实现用于构建和训练多层感知机的框架,借此深入看清现代神经网络内部的运作方式;文档还提示,backprop 的更多实现细节会在该 notebook 示例中展开;
- 作业(Assignment):使用本课构建的框架,解决 MNIST 手写数字分类问题——把感知机时代"区分两个数字"的任务升级为"判断图像最可能是 0~9 中的哪一个"的完整多分类任务。
需要说明的是:OwnFramework notebook 与 MNIST 实验属于该专题所属课程体系的配套材料,在当前 generative-ai-for-beginners 仓库内并不存在对应 notebook 文件;仓库中本文件的主要落地场景是作为 RAG 示例 notebook 的索引语料(其 data_paths 配置引用了本文件与 data/frameworks.md、data/perceptron.md)。读者若要以代码验证本讲原理,可参考先导篇中基于 numpy 的感知机训练代码来体会梯度更新的实现风格,或借助 框架导览篇 推荐的 TensorFlow+Keras / PyTorch 高层 API 完成等价实验。
七、延伸知识串联与自查要点
如果把本讲放进整条学习链中,它与仓库其他知识点的关联如下:
- 模型复杂度与泛化:文档只给了多层模型的形式,但并没有"层越多越好"。相邻的 框架导览篇 紧接着用 5 个数据点、2 参数线性模型 vs 7 参数非线性模型的对比,解释了过拟合(overfitting):训练误差低至 0 而验证误差高达 20,正是因为模型强大到"记住"了噪声;其更一般的统计表达是偏差-方差权衡(Bias-Variance Tradeoff)——训练中偏差误差下降、方差误差上升,必须恰好在某个点停住训练(人工早停或用 Dropout 等正则化手段)。这套经验对本讲自研框架的训练循环设计(如何判断该停、要不要加正则)有直接指导意义。
- 框架与课程的关系:整个第 15 课 README(15-rag-and-vector-databases/README.md)展示的是 RAG 应用,而
data/下的这三篇 Markdown 恰好充当了演示用的领域文档语料——也就是说,你正在阅读的这篇教程本身,也可以作为验证向量化检索效果的真实数据。 - 自查清单:读完本讲,你可以用下面几个问题检验自己是否真正掌握——softmax 为什么能把网络输出变成概率?学习率 η 过大或过小分别会带来什么后果?为什么 minibatch 抽样使梯度下降被称为"随机"?为什么非线性激活 α 对多层网络必不可少?为什么反向传播可以复用最左端公共因子而高效地算出所有梯度?
结语
本讲以不到两页的篇幅,完成了从"线性单层感知机"到"非线性多层感知机"的关键一跃:先建立"数据集 + 模型 f + 损失函数 ℒ"的形式化框架,再引入以 SGD 为代表的梯度下降优化,随后用链式法则推导出高效的反向传播算法,最终引导读者自建神经网络框架并挑战 MNIST 多分类任务。掌握本讲的数学骨架,意味着你已经理解了深度学习中"前向计算—损失评估—反向回传—参数更新"这一贯穿始终的核心循环,无论后续使用的是 Keras、PyTorch Lightning 这类高层 API,还是深入 LLM 微调、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 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