多层感知机

为什么直接堆线性层不行?激活函数如何打破线性,配合全连接层堆叠出能拟合 XOR、同心圆、月牙的多层感知机(MLP)。

知识课 · 约 50 分钟 · 更新于 2026-06-06

实验:堆叠两个线性层

上节课我们用 一个线性层 拟合简单的二维数据, 但碰到 XOR 这种弯曲的边界就完全没辙—— 因为单层线性模型只能画出一条 直线 分界。

而深度学习的核心想法,就是 把多层「层叠」起来 , 通过多层组合让网络变深、表达能力变强,从而拟合更复杂的数据。 我们能不能直接把两个线性层堆起来,搞定 XOR 呢?我们正面试一下:

下面这张图就是上述公式对应的网络结构(从左到右:输入 → 隐藏层 → 输出):

每个隐藏神经元 都是输入的加权和加偏置; 每个输出 又是 的加权和加偏置。 看起来是「两步」运算,下面我们把它合并成一步看看。

把第一行代入第二行,展开计算:

令:

于是 —— 两个线性层的组合,等价于一个线性层 。

突破口:引入非线性

既然问题出在「线性的复合还是线性」,那就在层与层之间塞一个 非线性变换 ,打破这种线性传递性:

其中 是某种非线性函数, 它就是 激活函数 (Activation Function)。

那么,一个合格的激活函数应该具备哪些性质?我们逐条来看:

  • 非线性(必需) : 这是激活函数 唯一硬性 的要求。 若激活函数本身是线性的,多层网络仍然会塌缩成单层, 上一节的「两个线性层等价于一个线性层」会再次发生—— 网络失去深度带来的表达力。
  • 处处可导(强烈推荐) : 神经网络靠 梯度 来更新参数(下一课就会讲反向传播)。 激活函数最好处处可导,反向传播才能顺畅地把梯度传回每一层。 ReLU 在 0 点不可导,但在工程上可以约定取一个次梯度,影响很小。
  • 计算便宜 : 深度网络在每一层、每个神经元都要执行一次激活函数。 如果函数本身计算昂贵(比如要算指数、除法),整体训练和推理都会被拖慢。 ReLU 之所以流行,一部分原因就是它便宜到极致——只是一次比较。
  • 梯度不易消失 : 如果在某些区间内导数趋近 0(比如 Sigmoid 在两端), 反向传播时梯度会被这些区间反复乘小数,越往前层越接近 0, 深层网络就更新不动——这就是 梯度消失 。 ReLU 在正区间导数恒为 1,能在很大程度上缓解这个问题。 这里梯度消失只是「先记住名字」, 后面讲反向传播时会专门展开,现在不懂也没关系。
  • 输出范围合理 : 有时希望输出限定在 (0, 1) 表示概率(Sigmoid), 有时希望以 0 为中心便于优化(Tanh), 有时希望保持原始数值范围(ReLU)。不同任务对值域有不同偏好。

总结一下: 非线性 是底线,其他性质决定训练效率与稳定性。 因此实践中我们会在「最便宜、最常用、表现也够好」的几个函数里选—— 这就是下一节要介绍的「激活函数三剑客」。

三种常见激活函数

初次见到这些激活函数的公式,很多人会困惑:「为什么要长这样?」—— 别想多了, 激活函数的公式本身没有什么深意 , 前人尝试过各种函数,能引入非线性、又便宜好算的就被留了下来。

因此面对它们, 不需要背公式 ,只要记住三件事就够了:

  • 值域 :函数把输入映射到什么区间
  • 大致形状 :曲线长什么样
  • 特性 :常见用途与典型坑
  • 值域 :
  • 优点 :
  • 缺点 :

现代深度学习中, ReLU 是默认选择 , Sigmoid 和 Tanh 主要出现在二分类输出层与一些 RNN 门控结构中。

全连接层

在正式介绍 MLP 之前,我们先把 MLP 最基本的「积木」单独拎出来—— 全连接层 (Fully-Connected Layer,简称 FC 层; 在 PyTorch 里对应 nn.Linear , 有时也叫 Dense 层、线性层)。

定义

一个全连接层把维度为 的输入向量, 映射到维度为 的输出向量。 每一个输出神经元,都是 所有输入神经元 的加权求和加偏置:

用矩阵形式写更紧凑(也是代码里最常见的写法):

「全连接」三个字直观说明了它的结构: 输入与输出之间,每一对神经元都有一条边 (即一个权重)。

超参数 vs 参数

  • 超参数 :人为指定、训练前固定,决定层的「形状」 输入维度 输出维度 是否带偏置(PyTorch 里的 bias=True/False )
  • 参数 :训练过程中由数据自动学出来 权重矩阵 共 个数 偏置向量 共 个数 合计可学习参数:

直观看一眼

下面是一个 的全连接层。 鼠标悬停在权重边上 可以看到具体的 值; 悬停或点击「权重」按钮 可以浮窗查看完整的权重矩阵。 共 个可学习参数。

全连接层是最朴素也最通用的网络层。MLP、CNN 的分类头、Transformer 的 FFN, 本质上都靠它在不同维度间做线性映射。

多层感知机的标准结构

把 全连接层 和 激活函数 交替堆叠起来, 就得到了 多层感知机 (Multilayer Perceptron, MLP):

每个隐藏层做两件事:

  1. 线性变换 :
  2. 非线性激活 :

输出层根据任务类型而不同——回归任务通常不接激活,分类任务接 Softmax。

交互式 MLP 拓扑

下面这个 MLP 你可以 自由调节 : 点击顶部 + / − 增减隐藏层; 点击每一列下方的 + / − 增减该层神经元数。 每条边的颜色与粗细会反映权重值(红正蓝负、绝对值越大越粗); 鼠标悬停在边上看权重数值,点击或悬停顶部「权重」按钮可以打开 权重矩阵 表查看完整参数。

随便加几层试试——隐藏层越多、每层越宽, 网络就能拟合越复杂的边界,但也意味着参数更多、需要更多数据来训练。

实践:手写 MLP 前向传播

我们用 PyTorch 手动堆出一个最小的 MLP, 给定一组输入,逐层算出输出,验证激活函数确实把数据揉出了非线性。

点下方的「下一步」逐步推进——左边代码会高亮当前正在执行的行, 右侧画布会同步刷新对应的张量。

看到了吗? ReLU 把 中的负元素「清零」, 破坏了从 到 整体的线性关系—— 这就是激活函数发挥作用的瞬间。

Playground:MLP 决策边界探索

前面我们一直在「描述」MLP,下面真刀真枪地训一个—— 看看在 XOR、同心圆、月牙这类 非线性可分 数据上, MLP 到底能画出什么样的决策边界。

玩法 :选数据集、选激活函数、调网络结构, 然后点「开始」让 TF.js 在浏览器里直接训练。 训练时拓扑图里的权重会持续刷新, 左下散点图叠加预测概率热力图(红色 = 预测为 1,蓝色 = 预测为 0), 右下是 loss 曲线。

附录:激活函数对比表

除了上面三剑客,工程中还会用到 Leaky ReLU、GELU 等。 下表罗列了五个最常见的激活函数,方便日后查阅; 每张图都支持鼠标悬停查看具体坐标。

  • 导数 :
  • 值域 :
  • 典型场景 :
  • 缺点 :