D2L 第四章知识点梳理:多层感知机
d2l 第四章知识点梳理:多层感知机
说明:本笔记对应《动手学深度学习》(d2l)第 4 章,覆盖 4.1(多层感知机)、4.4(模型选择)、4.5(权重衰减)、4.6(暂退法)、4.8(数值稳定性与初始化)。原笔记中的 LaTeX 公式截图已转写为 LaTeX 公式,其余截图(函数图像、结构图、示意图等)均保留原图引用。4.2/4.3(实现代码)与 4.7(前向传播、反向传播与计算图)不在本笔记范围内。
4.1 多层感知机
4.1.1 感知机模型
感知机是构成神经网络的最基本单元。给定输入 、权重 和偏置 ,感知机的输出为:
其中 是权重向量与输入向量的内积, 是激活函数。在最原始的感知机中, 取阶跃函数:
即感知机先对输入做一次仿射变换(内积加偏置),再经过激活函数输出结果。它可以处理二分类问题:输出为 1 或 0,对应两个类别。
注:严格的历史定义(Rosenblatt,1958)中感知机以阶跃函数为激活;d2l 中「感知机」一词有时也泛指「仿射变换 + 激活函数」构成的一层,即现代意义上的线性层加非线性激活。
4.1.2 线性模型的局限性:XOR 问题
单个感知机表示的是一个仿射变换(带偏置项)。如果想拟合的映射本身就是线性(仿射)的,那么单层感知机可以精确地表示它,不需要更复杂的结构。
但线性是一个很严格的条件,许多真实映射并不是线性的。典型的例子是异或(XOR)函数:
| XOR | ||
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
在二维平面上,这四个样本点无法用一条直线把输出为 0 和输出为 1 的点分开(即线性不可分)。而单层感知机能画出的决策边界只有直线,因此它无法拟合 XOR——这就是单层感知机的局限,也是引入多层结构的直接动机。
4.1.3 线性模型的另一个约束:单调性假设
单层感知机的线性结构还隐含了一个单调性假设:任何特征的增大,要么导致模型输出增大(对应权重为正时),要么导致模型输出减小(对应权重为负时),每个特征对输出的影响方向固定、幅度恒定。
但很多真实关系并不满足这一点。例如收入与死亡风险的关系:一个人从身无分文到年收入五万,死亡风险会大幅下降;而从一百万到一百零五万,死亡风险几乎不变。同样是增加五万收入,在不同的收入区间上对输出的影响完全不同,这种关系无法用线性模型刻画。
有时我们可以通过特征工程(例如对收入取对数)把关系转换成近似线性的,但很多时候做不到。此时单层感知机就不能很好地拟合这种关系。
4.1.4 加入隐藏层
为了拟合非线性关系,我们可以在输入层和输出层之间加入一个或多个隐藏层,构成多层感知机(MLP)。
图 4.1.1:一个单隐层的多层感知机,具有 5 个隐藏单元。

隐藏层之所以叫「隐藏」,是因为它们的值在训练数据中观测不到,完全由网络自己学习。
4.1.5 堆叠线性层的退化问题
加入了隐藏层之后,是不是就可以直接拿去训练了呢?我们看一下这个单隐层网络的公式:
把第一式代入第二式:
两个权重矩阵相乘仍是矩阵,两个偏置项合并后仍是向量——也就是说,两个仿射变换的复合仍是一个仿射变换。这个「多层」网络退化成了单层感知机,而且无论再堆叠多少个线性层,结果都一样。这不是我们想要的。
4.1.6 引入非线性激活函数
要避免退化,我们需要在隐藏层的仿射变换之后、送入下一层之前,对每个隐藏单元应用一个非线性的激活函数 :
此时隐藏表示 不再是输入 的线性函数,两层也就无法再合并成一个单层模型。为了增强模型能力,我们可以继续堆叠这样的「仿射变换 + 激活函数」隐藏层。
拓展(万能近似定理):理论上,一个带非线性激活、宽度足够大的单隐层 MLP,可以以任意精度逼近 任意紧子集上的连续函数(Cybenko 1989,Hornik 1991)。但该定理没有告诉我们「足够大」到底要多大,也没有给出训练方法;实践中「深而窄」的网络通常比「浅而宽」的网络更高效。
4.1.7 常见激活函数
(1)ReLU 函数
原函数图像:

导函数(ReLU 在 0 点严格来说不可导,实现中通常约定取 1 或 0):
导函数图像:

ReLU 是目前最受欢迎的激活函数,因为它简单、易于计算(没有指数运算)且性能良好:当 时信号和梯度都原样通过(导数恒为 1),当 时被置零,这种「要么全通过、要么全截断」的性质有效缓解了梯度消失问题。
拓展(Dead ReLU 与变体):ReLU 的隐患是「神经元死亡」——如果某个神经元的输入长期为负(例如一次大梯度更新后参数变得很差),它的导数恒为 0,将永远无法再被更新。为此衍生出一系列变体:LeakyReLU 在 时给一个小斜率 (如 0.01)而非置零;ELU 在负半轴用指数形式;GELU、Swish/SiLU 等平滑变体则是 Transformer 等现代架构的常见选择。
(2)Sigmoid 函数
Sigmoid 是最早被采用的激活函数之一,灵感来自对生物神经元「全或无」发放特性的建模。
原函数图像(S 形曲线,关于点 中心对称,两端进入饱和区):

导函数:
导函数图像(在 处取最大值 ,值域为 ):

由于导数始终不超过 0.25,在深层网络中逐层连乘后梯度会指数级缩小,很容易导致梯度消失,所以 sigmoid 如今已很少用于隐藏层,大部分时候被更简单、更容易训练的 ReLU 取代。不过,当我们想把输出解释为二分类问题的概率时,sigmoid 仍然广泛用作输出层的激活函数(它可以视为两类 softmax 的特例)。
(3)tanh 函数
tanh 与 sigmoid 形状类似,可以看作 sigmoid 的缩放平移版本:
原函数图像(关于原点中心对称的 S 形曲线,值域 ):

导函数:
导函数图像(在 处取最大值 1,值域为 ):

tanh 的输出以 0 为中心,实践中通常比 sigmoid 收敛更快;但它在两端同样饱和,导数最大也只有 1(没有增益),堆叠多层后依然面临梯度消失问题。
(4)三种激活函数小结与拓展
| 激活函数 | 表达式 | 导数 | 导数范围 | 典型用途 |
|---|---|---|---|---|
| ReLU | ()/ () | 隐藏层默认选择 | ||
| Sigmoid | 二分类输出层 | |||
| Tanh | RNN 等传统结构 |
拓展(激活函数的分工):隐藏层激活函数追求的是表达能力与可训练性,而输出层激活函数由任务决定:回归任务通常不加激活,二分类用 sigmoid,多分类用 softmax(将输出归一化为概率分布)。
4.4 模型选择、欠拟合和过拟合
针对不同任务,我们需要选择不同的模型。这些模型的差异主要体现在两个方面:
(1)本质上不同的模型。例如决策树和线性模型属于不同的模型族,可表示的函数集合根本不同。
(2)同一族模型但超参数不同。例如隐藏层数不同的 MLP、卷积层数不同的 CNN,以及学习率、L2 正则化系数等取值不同的配置。超参数在训练开始前设定、不由训练数据学习得到。
拓展:除了上述两点,损失函数、优化算法和训练数据本身的差异也会影响最终模型。模型选择主要指在给定模型族下挑选超参数的过程。
下面围绕第二个方面,说明如何评估和选择模型。
4.4.1 验证集
测试集不能随便动用。如果我们用测试集来指导模型选择,就会造成对测试数据的过拟合,此时测试误差再也无法真实反映模型的泛化能力。(过拟合训练数据并不可怕,我们仍然可以用测试集来检验泛化能力;可一旦连测试集也「被过拟合」了,我们就失去了最终的裁判。)
因此,我们需要独立于训练集和测试集之外的第三种数据集——验证集:用它来评估当前超参数下模型的泛化能力,进而挑选超参数。
在实际研究和竞赛中,真正的测试集(带不公开标签的独立数据)往往并不存在,人们常常把划出的验证集直接称作「测试集」。但要清楚,这个「测试集」本质上只是验证集,只能相对地反映当下模型的泛化水平、判断有无过拟合或欠拟合,并不是严格意义上的测试集。
获取验证集大致有两种方式:一是另外收集一个独立数据集充当验证集;二是从训练集中分离。数据量充足时,直接按一定比例(常见如 8:2)从训练集中切分即可;训练集稀少时,则采用 K 折交叉验证来更充分地利用数据。
4.4.2 K 折交叉验证
把原始训练数据集分成 个不重叠的子集。然后执行 次模型训练和验证:每次在 个子集上进行训练,并在剩余的那一个子集(该轮中没有用于训练的子集)上进行验证。最后,对 次实验的结果取平均,来估计训练误差和验证误差。
根据估计出的训练误差和验证误差来调整超参数,从而得到泛化能力尽可能强的模型。整个过程中真正的测试集始终不参与,只在最后评估时使用一次。
4.4.3 欠拟合与过拟合
比较训练集误差和验证集误差,可以判断模型是否适合当前任务。不适合的情况一般分为两类:
| 拟合状态 | 训练误差 (Training Error) | 验证误差 (Validation Error) | 两者差距(泛化误差) | 核心原因与特征 | 建议改进方向 |
|---|---|---|---|---|---|
| 欠拟合 (Underfitting) | 高(难以降低) | 高 | 很小 | 模型过于简单,表达能力不足,无法捕获数据中的模式。 | 使用更复杂的模型、增加特征、提升模型表达能力。 |
| 过拟合 (Overfitting) | 低 | 高 | 较大(训练误差明显低于验证误差) | 模型过度学习了训练集中的噪声与细节,泛化能力偏弱。 | 增加正则化、扩充数据量、采用 early stopping 等。 |
损失随模型复杂度的变化(泛化损失最低点对应的复杂度为「最佳」,其左侧为欠拟合区,右侧为过拟合区):

4.4.4 模型容量与数据集大小
欠拟合和过拟合是否发生,取决于模型容量与数据集大小(以及数据规律的复杂程度)是否匹配。模型容量可以简单理解为参数的数量与结构的复杂程度;数据集大小就是训练样本的多少。

例如,用一个高次多项式去拟合由二次函数生成的少量数据:模型容量远超过数据所能约束的程度,模型就会「记住」样本中的噪声而不是真正的规律,从而过拟合。
由此可以得到几条经验规律:
- 训练样本越少,我们越有可能(且更严重地)过拟合;
- 随着训练数据量的增加,泛化误差通常会减小,而且更多的数据一般没有坏处;
- 对于固定的任务和数据分布,模型复杂度和数据集大小之间存在对应关系:数据更多时,可以放心拟合更复杂的模型,这往往是有益的;数据不足时,简单模型反而更有用;
- 对于许多任务,深度学习只有在拥有数千个训练样本时才优于普通的线性模型。
4.5 正则化(一):权重衰减
既然模型复杂度与数据集大小的错配会引发过拟合或欠拟合,那么有什么缓解办法呢?
- 欠拟合的缓解方向是提高模型容量:加深加宽网络、引入更多特征;
- 过拟合在理论上可以通过扩充数据集来缓解,但数据往往昂贵或不可得,于是就有了另一条主流路线——正则化。
正则化包含很多种方法,本章讨论两种:权重衰减和 Dropout(暂退法)。
权重衰减(weight decay)正如其名:让权重在训练时不要太大,从而限制模型的拟合能力,缓解过拟合。实现方式是把模型参数的大小以某种方式并入损失函数。以最常用的均方误差损失为例,常规的损失函数是:
引入权重的 L2 范数作为惩罚项后,新的优化目标为:
其中 是正则化系数(权重衰减系数),一个待调整的超参数,控制惩罚的强度; 是权重向量的 L2 范数的平方;前面的 是为了求导方便(求导后与平方项产生的 2 相消)。后面这一项通常称为正则化惩罚项。
这样,训练目标就从单纯的最小化损失,变为「在最小化损失的同时,尽可能让参数不要太大」。参数越小,模型函数越平滑,拟合能力受到约束,过拟合得以缓解。
拓展(为什么叫「衰减」):对加罚后的目标做梯度下降,权重的更新式为
即每一步更新前,权重先被乘以一个小于 1 的因子 「衰减」一点,再沿梯度方向移动,权重衰减因此得名。在 SGD 下,L2 正则化与权重衰减是等价的(同一方法的两种称呼)。
注:对偏置 施加权重衰减没有必要,实践证明了这一点——偏置只决定输出的整体平移,不会像权重那样造成过拟合。
拓展(L1 与 L2):把惩罚项换成 即 L1 正则化(Lasso),它倾向于把部分权重精确压到 0,产生稀疏解;L2 正则化(Ridge)则让所有权重整体、平滑地向 0 收缩。深度学习中默认使用的权重衰减对应 L2。
4.6 正则化(二):Dropout(暂退法)
除了权重衰减,还有一种常用的正则化方法:暂退法(Dropout)。值得一提的是,Dropout 在提出之初并不被认为是正则化方法,后来的研究才揭示了它的正则化效果。
权重衰减的思路是「限制参数的大小」,而 Dropout 走的是另一条路:在训练时直接削弱模型的有效容量。具体做法是:训练时,每次前向传播都以概率 随机将一些神经元的输出置为 0,同时把其余(未被删除的)神经元的输出除以 。除以 的作用是保持每一层输出的数学期望与删除前相同:被删除的神经元以概率 贡献 0,存活的神经元以概率 贡献 ,期望恰好仍为 。
这样做破坏了神经元之间的共适应性(co-adaptation),迫使每个神经元不过度依赖其他某些神经元的特定组合,转而独立地学习更鲁棒的特征——也就是降低模型对训练集细节的拟合能力,从而避免过拟合。删除概率 是一个超参数,常用取值在 0.1–0.5 之间(d2l 示例中对两个隐藏层分别取 0.2 和 0.5); 过大(如 0.9)意味着丢弃绝大多数神经元,模型难以训练,实践中很少使用。
在推理(测试)阶段不删除任何神经元:由于训练时已经用除以 的方式修正了输出的期望,推理时直接使用全部神经元的原始输出即可,无需再做缩放。
这种方式常常被解释为:训练时模拟了大量随机扰动,使模型在测试时对环境噪声和数据扰动更具鲁棒性,从而提高泛化能力。
注:Dropout 的提出者 Hinton 一直认为,它的本质是把模型拆成指数级多的子网络(共享权重)来同时训练——每次前向传播都相当于随机采样出一个子网络,测试时的完整网络近似于这些子网络的平均。这让每个子网络的能力都得到训练,而不高度依赖其他子网络(破坏神经元共适应性,不依赖特定的神经元组合),思想类似随机森林的 bagging。
拓展(使用要点):Dropout 一般只施加在全连接隐藏层上,且只在训练时启用、推理时关闭(例如 PyTorch 中
model.train()与model.eval()的切换正是为了控制这类行为)。在 CNN、Transformer 等架构中,它也常与批归一化、随机深度等技术配合或互相替代。
4.8 数值稳定性与初始化
4.8.1 梯度消失
反向传播求梯度依赖链式法则:深层参数的梯度是各层导数逐层连乘的结果。早期的深度神经网络普遍采用饱和激活函数,如 Sigmoid 和 Tanh——它们的导数数值很小(sigmoid 导数最大仅 0.25),且有效区间很窄:输入绝对值稍大,激活就进入饱和区、导数趋近于 0。这样的导数逐层连乘,梯度会指数级地越乘越小,导致深层参数几乎得不到有效更新。这就是梯度消失。
Sigmoid 与其导数的图像(sigmoid 在 较大处饱和,导数仅在 附近有峰值 0.25):

正如上图所示,当 sigmoid 函数的输入很大或很小时,它的梯度都会消失。此外,当反向传播通过许多层时,除非我们刚好处于 sigmoid 输入接近零的「刚刚好的地方」,否则整个乘积的梯度可能会消失。当网络有很多层时,除非非常小心,否则梯度很可能在某一层被切断。事实上,这个问题曾经长期困扰着深度网络的训练。因此,更稳定的 ReLU 系列函数已成为从业者的默认选择(虽然从神经科学的角度看,它不太像生物神经元的行为)。
4.8.2 梯度爆炸
连乘同样会带来反方向的问题——梯度爆炸。如果各层权重矩阵的范数乘积大于 1,梯度在逐层连乘中会指数级增长。一个直观的例子(截图转写):
随机生成一个 矩阵,元素量级约为 1;将它连续乘以 100 个这样的矩阵后,元素的量级达到 –,例如:
1
2
3
4
5
6
7
8
9
10
11# 一个矩阵
[[ 2.21, 1.16, 0.77, 0.48],
[ 1.04, 0.30, 1.18, 0.15],
[ 1.89, -1.17, -1.23, 1.56],
[-1.77, -0.55, -0.45, -2.36]]
# 乘以100个矩阵后
[[ 3.4e+23, -7.8e+23, 6.0e+23, 4.5e+23],
[ 2.5e+23, -5.7e+23, 4.4e+23, 3.3e+23],
[ 1.4e+24, -3.1e+24, 2.4e+24, 1.8e+24],
[-4.5e+23, 1.0e+24, -7.8e+23, -5.9e+23]]
梯度达到如此量级时,梯度下降的更新步长会巨大,优化器无法有效收敛,模型训练直接失败。
4.8.3 打破模型的对称性
神经网络设计中的另一个问题,是其参数化所固有的对称性。假设我们有一个简单的多层感知机:一个隐藏层、两个隐藏单元。在这种情况下,我们可以对第一层的权重进行重排列,并对输出层的权重做相应的重排列,得到的仍然是完全相同的函数——第一个隐藏单元与第二个隐藏单元没有任何本质区别。换句话说,同一层的隐藏单元之间具有排列对称性。
现在假设输出层把上述两个隐藏单元汇聚为一个输出单元。想象一下,如果把隐藏层的所有参数初始化为同一个常量,会发生什么?在前向传播中,两个隐藏单元接收相同的输入、拥有相同的参数,产生相同的激活值,并被同样地送到输出单元;在反向传播中,对输出单元关于参数求导,得到的梯度中每个元素也都取相同的值。因此,在基于梯度的迭代(例如小批量随机梯度下降)之后,权重矩阵 的所有元素仍然取相同的值。这样的迭代永远不会打破对称性,我们可能永远无法发挥网络的表达能力——隐藏层的行为就好像只有一个单元。
请注意,虽然小批量随机梯度下降不会打破这种对称性,但暂退法(Dropout)正则化可以(每层随机删除不同的神经元,本身就破坏了对称性)。
4.8.4 缓解方法
(1)合理的初始化策略
- 用正态分布等分布随机化初始权重,打破对称性,同时把方差控制在小范围内;
- 如果训练失效(发散),可以重新初始化后再训练。
但随机初始化的方差大小需要讲究:太小容易梯度消失,太大容易梯度爆炸。这就引出了两种经典的方差匹配初始化方法。
(2)Xavier 初始化
Xavier 初始化(也称 Glorot 初始化)由 Xavier Glorot 和 Yoshua Bengio 于 2010 年提出。其核心目标是保持网络各层激活值(前向传播)和梯度(反向传播)的方差一致,防止网络较深时出现梯度消失或梯度爆炸。
具体如何做到「方差一致」?设权重从均值为 0、方差为 的分布中独立采样,且输入各分量与权重相互独立:
- 前向传播:某层输出是 个乘积项之和。若各输入分量的方差为 1,则输出的方差为 。要让它与输入方差不变,需要满足
- 反向传播:类似的分析要求
两个条件一般无法同时满足(除非 )。Xavier 等人取折中,要求两者平均为 1,即初始化方差满足:
这样就同时兼顾了前向与反向两个条件,保证各层激活值和梯度的方差大致一致。实际采样有两种方式:
- 正态分布形式:直接从均值为 0、方差为 的高斯分布中采样;
- 均匀分布形式:从 中采样。由于 的方差为 ,令 ,解得
Xavier 初始化在搭配传统激活函数(tanh、sigmoid)时效果拔群。但对于 ReLU、LeakyReLU 这类非对称激活函数,零点以下的输出被置零,输出均值不再为 0,有效方差减半,Xavier 初始化的前提假设不再成立,深层网络依然容易发生梯度衰减。
(3)He 初始化
为了解决 ReLU 族激活函数带来的问题,何恺明等人(2015)提出了 He 初始化(Kaiming 初始化):既然 ReLU 会把一半的输出置零、使方差减半,那就把目标方差加倍补偿回来:
(上式为 fan-in 模式;还有使用 的 fan-out 模式。)与 Xavier 类似,He 初始化同样有正态分布与均匀分布两种形式,均匀分布形式的区间端点为 。
(4)Xavier 与 He 初始化对比
| 特性 | Xavier (Glorot) 初始化 | He (Kaiming) 初始化 |
|---|---|---|
| 适用激活函数 | Tanh、Sigmoid、线性激活 | ReLU、LeakyReLU、PReLU |
| 目标方差 | ||
| 主要解决问题 | S 型激活函数的梯度消失 | ReLU 族激活函数的梯度消失 |
拓展:除了合适的初始化,批归一化(Batch Normalization)等归一化技术可以从结构上进一步缓解梯度消失/爆炸;梯度裁剪(gradient clipping)则是应对梯度爆炸的标准手段(在循环神经网络中尤为常用)。