首页
/ 从感知机到多层感知机:理解梯度下降与反向传播,用 Python 搭建自己的神经网络框架

从感知机到多层感知机:理解梯度下降与反向传播,用 Python 搭建自己的神经网络框架

2026-09-07 13:35:10作者:谭伦延

本文解析的关联文档是 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.mdframeworks.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 可以取更复杂的形式。

两个值得细读的补充点:

  1. softmax 归一化:分类场景下,通常希望网络输出各类别的概率。把任意实数向量转成概率,常用 softmax 函数 σ,此时 f 变为 f(x) = σ(wx + b)。softmax 保证输出值非负且和为 1,是后续多分类输出的关键。
  2. 参数的统一定义:上式中的 w 与 b 统称参数 θ = ⟨w, b⟩。给定数据集 ⟨X, Y⟩,就能把整个数据集上的总误差写成关于参数 θ 的函数。

神经网络训练的目标:通过调整参数 θ,使整体误差最小化。 这是后续梯度下降与反向传播两条技术主线的共同出发点。

梯度下降优化:沿负梯度方向迭代

函数优化的经典方法是梯度下降(gradient descent)。核心思想是:计算损失函数对各参数的导数(多维情形下称梯度),然后朝让误差减小的方向修改参数。形式化步骤如下:

  1. 用随机值初始化参数 w⁽⁰⁾、b⁽⁰⁾;
  2. 反复迭代更新:
    • w⁽ⁱ⁺¹⁾ = w⁽ⁱ⁾ − η·∂ℒ/∂w
    • b⁽ⁱ⁺¹⁾ = 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.ipynbdata/frameworks.mddata/own_framework.mddata/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)内容直接相关,可作为进阶阅读闭环。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.79 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
390