7.1 为什么深层网络需要正则化与归一化

Author

jshn9515

Published

2026-06-26

Modified

2026-06-26

随着神经网络变得更深、参数量变得更大,模型通常会获得更强的表达能力。它可以拟合更复杂的函数,学习更丰富的特征,也更有可能在训练数据上取得很低的误差。但模型变强以后,训练并不会自动变得更容易。相反,我们经常会遇到两类不同的问题。

第一类问题是,模型在训练集上表现很好,在没有见过的数据上却表现不佳。模型可能记住了训练样本中的偶然模式和噪声,却没有学到真正能够泛化的规律。这就是过拟合(overfitting)

第二类问题是,模型虽然理论上可以表示目标函数,但训练过程并不稳定。不同层的激活值可能落在完全不同的数值范围里,参数更新对初始化和学习率十分敏感,模型可能收敛得很慢,甚至根本无法正常优化。

Dropout 和归一化方法经常一起出现在神经网络中,但它们主要处理的并不是同一个问题:

因此,这一章虽然把 dropout 和各种归一化方法放在一起讨论,但我们首先需要分清它们各自在解决什么问题。只有先建立这个整体视角,后面看到不同公式和 PyTorch API 时,才不会把所有方法都简单理解成让训练更稳定的技巧。

import torch
import torch.nn as nn
from torch import Tensor

print('PyTorch version:', torch.__version__)
PyTorch version: 2.12.1+cpu

7.1.1 模型变强以后,为什么更容易过拟合

神经网络的参数决定了它能够表示哪些函数。一般来说,网络越深、隐藏层越宽、参数越多,它能够表示的函数就越复杂。这种表达能力是深度学习成功的重要原因,但它也带来一个直接问题:模型不仅能够学习训练数据中的真实规律,也可能把训练样本中的偶然细节一起记下来。

假设我们正在训练一个图像分类模型。训练集中某一类图片刚好经常出现在浅色背景中,模型可能把背景颜色当成分类依据。这样做可以降低训练误差,但当测试图片换成其他背景时,模型就可能做出错误判断。因此,训练误差很低,并不代表模型真的学会了任务。我们真正关心的是模型在没有见过的数据上的表现,也就是模型的泛化能力(generalization)

过拟合通常表现为:

  • 训练损失持续下降;
  • 训练准确率持续上升;
  • 验证损失不再下降,甚至开始上升;
  • 训练集和验证集之间的性能差距越来越大。

这说明模型仍然在适应训练数据,但新学到的内容已经不能帮助它处理没见过的样本。

我们可以把模型训练的目标粗略地理解为:

既要有足够强的表达能力,又不能让模型毫无约束地记忆训练集。

正则化就是为这个目标服务的。它不是简单地让训练损失变得更低,而是通过限制模型、扰动训练过程或增加额外约束,让模型更倾向于学习能够泛化的模式。

常见的正则化方法包括权重衰减、数据增强、early stopping 和 dropout。本章重点讨论 dropout,因为它直接作用于神经网络的中间激活,并且和后面介绍的归一化层一样,通常会作为网络结构的一部分出现。

7.1.2 Dropout 解决的核心问题

Dropout 的核心做法并不复杂:在训练过程中,随机把一部分中间激活设为 0。

假设某一层的输出为:

\[ x = [x_1, x_2, \dots, x_d] \]

Dropout 会采样一个随机 mask:

\[ m_i \sim \operatorname{Bernoulli}(1-p) \]

其中,\(p\) 是丢弃概率。然后得到新的激活:

\[ \tilde{x} = \frac{m \odot x}{1-p} \]

这里除以 \(1-p\) 是为了让训练阶段输出的期望值和原始输入保持一致。具体原因会在下一节完整讨论。

Dropout 的关键并不是把激活值变小,而是让网络在每次前向传播时都不能依赖完全相同的特征组合。

假设某个预测高度依赖三个隐藏单元同时出现。如果训练过程中这些单元中的一部分会被随机丢弃,那么网络就必须学习更加分散、更加稳健的表示,而不能把所有能力都压在某一条固定路径上。

从这个角度看,dropout 给训练过程加入了随机扰动。模型在每个 mini-batch 中看到的都像是一个略有不同的子网络,但这些子网络共享同一组参数。最终得到的模型通常不会过度依赖某几个特定神经元。

因此,dropout 的主要关键词是:

随机失活、减少共适应、缓解过拟合。

Dropout 可能间接影响训练稳定性,但它的首要目的并不是统一激活值的尺度,也不是修复梯度爆炸。它首先是一种正则化方法。

7.1.3 深层网络为什么会难以优化

过拟合不是深层网络面临的唯一问题。即使训练集足够大,模型没有明显过拟合,网络仍然可能很难优化。

考虑一个包含很多层的前馈网络:

\[ h^{(l)} = f\left(W^{(l)}h^{(l-1)} + b^{(l)}\right) \]

\(l\) 层的输入来自第 \(l-1\) 层的输出,而第 \(l-1\) 层又依赖更前面的所有层。因此,只要前面某一层的参数发生变化,后面很多层看到的输入分布都会随之改变。

在训练过程中,所有层都在同时更新。某一层不仅要学习适合当前输入的参数,还要不断适应前面各层产生的新输入。这会让优化过程对以下因素更加敏感:

  • 参数初始化;
  • 网络深度;
  • 激活函数;
  • 学习率;
  • Mini-batch 的大小;
  • 输入和中间特征的数值尺度。

一个特别直观的问题是,不同层的激活值可能具有完全不同的均值和方差。有些层的输出集中在很小的范围内,有些层的输出却非常大。经过多层复合以后,这些尺度差异还可能继续被放大。

下面用一个简单例子观察线性变换如何改变激活的尺度。这里暂时不使用任何归一化方法,只连续经过几个随机线性层。

x = torch.randn(256, 128)
layers = nn.ModuleList([nn.Linear(128, 128, bias=False) for _ in range(5)])

with torch.inference_mode():
    print(f'Input   mean={x.mean(): .4f}, std={x.std():.4f}')

    for i, layer in enumerate(layers, start=1):
        x = 1.8 * layer(x)
        print(f'Layer {i} mean={x.mean(): .4f}, std={x.std():.4f}')
Input   mean= 0.0071, std=1.0037
Layer 1 mean= 0.0042, std=1.0343
Layer 2 mean= 0.0063, std=1.0755
Layer 3 mean= 0.0086, std=1.0990
Layer 4 mean=-0.0054, std=1.1576
Layer 5 mean= 0.0111, std=1.2078

可以看到,当每一层都会对输入做新的线性变换,权重尺度的细小变化经过多层传播后,可能让激活值越来越大或越来越小。

激活尺度不合适时,可能带来很多问题。例如,一些激活函数会进入饱和区域,梯度变得很小;某些层输出过大时,后续计算可能变得不稳定;不同参数接收到的梯度尺度差异很大时,一个统一的学习率也更难同时适合所有参数。

因此,深层网络不仅要学习正确的函数,还要让整个优化过程保持在一个相对合理的数值范围内。

7.1.4 Normalization 在做什么

归一化方法的共同思路是:对某一组激活值计算统计量,然后根据这些统计量重新调整激活值。

最常见的形式是:

\[ \hat{x} = \frac{x-\mu}{\sqrt{\sigma^2+\epsilon}} \]

其中,\(\mu\)\(\sigma^2\) 是某些维度上的均值和方差,\(\epsilon\) 是为了避免分母过小而加入的数值稳定项。

标准化之后,模型通常还会使用可学习参数 \(\gamma\)\(\beta\) 做仿射变换:

\[ y = \gamma \hat{x} + \beta \]

这一步很重要。归一化层并不是强迫所有特征永远保持均值为 0、方差为 1。标准化只是提供一个更加稳定的参考尺度,后面的 \(\gamma\)\(\beta\) 允许模型重新学习适合当前任务的缩放和平移。

不同归一化方法的公式看起来非常相似。对于 BatchNorm、LayerNorm、InstanceNorm 和 GroupNorm,最关键的差别通常在于:

均值和方差究竟是在哪些维度上计算的?

而 RMSNorm 与它们稍有不同。它不减去均值,也不显式计算中心化后的方差,而是在指定的最后若干个维度上计算均方根:

\[ \operatorname{RMS}(x) = \sqrt{\frac{1}{d}\sum_{i=1}^{d}x_i^2+\epsilon} \]

然后使用这个均方根缩放激活:

\[ \operatorname{RMSNorm}(x) = \frac{x}{\operatorname{RMS}(x)}\odot\gamma \]

因此,RMSNorm 仍然属于归一化方法,但它只控制特征尺度,不进行均值中心化。

以卷积网络中常见的四维输入为例:

\[ X \in \mathbb{R}^{N \times C \times H \times W} \]

各种 Normalization 都可以从“哪些元素共享统计量”这个角度理解,但它们选择的统计范围和统计量类型不同。

  • Batch Normalization 通常为每个通道在 batch 和空间维度上计算统计量;
  • Layer Normalization 在单个样本内部,对指定的最后若干个维度计算统计量;
  • Instance Normalization 为每个样本的每个通道独立计算空间统计量;
  • Group Normalization 把通道划分成若干组,在每个样本的组内计算统计量;
  • Root Mean Square Normalization 在单个样本内部,对指定的最后若干个维度计算均方根,并只对特征尺度进行归一化。

因此,理解归一化方法最有效的方式不是分别背诵五套公式,而是始终追问四个问题:

  1. 哪些元素共享同一组统计量?
  2. 使用的是均值与方差,还是只使用均方根?
  3. 可学习参数的形状是什么?
  4. 训练阶段和推理阶段是否使用相同的统计量?

后面的几节都会围绕这四个问题展开。

7.1.5 Dropout 和 Normalization 不是一回事

Dropout 和 normalization 经常一起出现在模型结构中,因此很容易被放进同一个模糊的概念里:它们都能让模型训练得更好。但从机制上看,两者的差别非常明显。

Dropout 在训练阶段引入随机性。相同的输入经过同一层 dropout,两次得到的结果可能不同。它通过随机丢弃特征,减少模型对特定激活路径的依赖。

Normalization 通常根据一组激活的统计量重新缩放特征。它更关心激活值在数值上处于什么尺度,以及不同样本、通道或特征之间如何共享统计量。

可以把两者粗略总结为:

表 1:Dropout 与 Normalization 的核心区别
方法 主要目标 核心操作 训练与推理是否相同
Dropout 缓解过拟合 随机丢弃部分激活 不同
Normalization 改善激活尺度和优化过程 根据统计量平移和缩放激活 取决于具体方法

这里最后一列需要特别注意。Dropout 在推理阶段通常会被关闭,因为推理时我们希望使用完整网络进行确定性预测。Batch Normalization 在训练时使用当前 mini-batch 的统计量,在推理时通常使用训练期间积累的 running statistics;Layer Normalization、Group Normalization 和 RMSNorm 不依赖跨样本的 batch 统计,因此训练和推理时的计算方式基本一致。

所以,dropout 和 normalization 虽然都可以出现在网络结构中,但不能互相替代。一个模型可以只用其中一种,也可以同时使用两者,它们分别从不同角度影响训练和泛化。

7.1.6 Normalization 也不等于输入标准化

在准备表格数据或图像数据时,我们也经常会做标准化,例如:

\[ x' = \frac{x-\mu_{\text{data}}}{\sigma_{\text{data}}} \]

这种数据预处理和网络内部的归一化层形式上很相似,但它们发生的位置和使用的统计量不同。

输入标准化发生在模型之前。数据集的均值和方差通常预先计算好,然后所有样本使用同一组固定统计量。它的作用是让输入特征具有更合适的尺度。

网络内部的归一化发生在隐藏层之间。隐藏激活会随着参数更新不断变化,因此归一化层需要在训练过程中根据当前激活计算统计量,或者维护用于推理的运行时统计量。

另外,归一化也不意味着模型把所有激活都变成严格的标准正态分布。减去均值、除以标准差,只能控制一阶和二阶统计量,并不能保证数据的分布形状就是高斯分布。

因此,更准确的理解是:

Normalization 调整的是激活的中心和尺度,而不是把任意分布变成正态分布。

这个区别看起来很细,但很重要。后面分析各种归一化层时,我们关注的是它们如何选择统计范围、如何缩放激活,以及这种选择带来了什么归纳偏置,而不是假设所有中间特征都必须服从某种固定概率分布。

7.1.7 本章将如何组织这些方法

这一章会按照下面的顺序介绍 dropout 和各种归一化方法。

首先介绍 dropout。我们会从 bernoulli mask 出发,解释为什么训练时需要除以保留概率,以及 PyTorch 里 Dropout1dDropout2dDropout3d 为什么不是简单地对每个元素独立采样。

然后介绍 Batch Normalization。它是归一化方法中最适合建立完整直觉的一种,因为它同时涉及 batch statistics、running statistics、训练和推理模式,以及卷积网络中的通道维度。我们还会进一步讨论为什么推理时可以把 Batch Normalization 融合进卷积层。

接下来介绍 Layer Normalization。它不依赖 batch 中的其他样本,而是在每个样本内部进行归一化,因此非常适合 Transformer 和序列模型。

之后介绍 Instance Normalization 和 Group Normalization。这两种方法在视觉任务中很常见,它们可以帮助我们进一步理解:只要改变统计量覆盖的维度,就会得到具有不同性质的归一化方法。

最后介绍 Root Mean Square Normalization。它和 Layer Normalization 类似,通常作用于输入的最后若干个维度,但不减去均值,而是只根据均方根控制隐藏特征的尺度。Root Mean Square Normalization 已经成为现代大语言模型中非常常见的归一化方法。

在章节末尾,我们会把几种归一化方法放回同一个张量中进行比较,统一回答下面几个问题:

  • 哪些维度被归一化?
  • 哪些元素共享统计量?
  • 使用均值和方差,还是只使用均方根?
  • 是否依赖 batch size?
  • 是否维护 running statistics?
  • 训练和推理阶段是否存在差异?
  • 更适合 CNN、Transformer,还是图像生成任务?

从这一章开始,可以先记住一个最重要的判断框架:

看到 dropout,先问它如何引入随机正则化;看到 normalization,先问它在哪些维度上计算统计量。

7.1.8 本章小结

这一节没有直接实现某一种归一化层,而是先区分了深层网络训练中几类容易混在一起的问题。

过拟合指的是模型过度适应训练数据,导致泛化能力下降。Dropout 通过随机丢弃部分激活,减少网络对固定特征组合的过度依赖,因此主要属于正则化方法。

优化困难则与网络深度、激活尺度、参数初始化和学习率等因素有关。Normalization 根据选定维度上的统计量重新调整激活,为网络提供更稳定的数值尺度。BatchNorm、LayerNorm、InstanceNorm 和 GroupNorm 主要通过均值与方差完成归一化,而 RMSNorm 只使用均方根控制特征尺度。不同方法之间最关键的区别,是哪些元素共享统计量、在哪些维度上计算统计量,以及是否进行均值中心化。

下一节我们会从 dropout 开始,具体分析它如何生成随机 mask,为什么训练时需要缩放,以及 PyTorch 中不同维度的 dropout 层究竟在丢弃什么。