---
area: "tech-engineering"
category: technology
date: '2025-11-14'
draft: true
guest: ''
insight: ''
layout: post.njk
products_models:
- BERT
project: []
series: ''
source: https://www.youtube.com/watch?v=mPWvAN4hzzY
speaker: Hung-yi Lee
status: evergreen
summary: 本讲座系统性地介绍了训练神经网络的各种实用技巧，并提出了一个核心分析框架：任何技术都可从其修改的机器学习步骤（损失函数、模型架构、优化算法）及其主要目标（改善优化或强化泛化）两个维度进行理解。内容涵盖了从
  Adam 等高级优化器、CNN 和残差连接等网络架构设计，到数据增强、半监督学习和正则化等与损失函数相关的策略，为深入理解和应用深度学习提供了清晰的路线图。
tags:
- design
- learning
- model
- neural-network-training
- optimization
title: 训练神经网络的实用技巧：优化、泛化与模型架构全解析
---
### 前言：理解训练技巧的核心框架

今天这堂课旨在向大家介绍在训练类神经网络时会用到的各种技巧。在上一堂课中，我们已经明确了机器学习的三个核心步骤：
1.  定义损失函数（Loss Function）。
2.  确定函数的选择范围（模型架构）。
3.  选择一个最优的函数（优化过程）。

完成这三个步骤训练出模型后，不能立即进行测试，必须先进行验证（Validation）。只有当验证结果足够好时，才能进入测试环节；否则，就需要回到学习的三个步骤中，检查是哪个环节出了问题。

上周我们还探讨了深度学习的基本观念，即所谓的深度学习或类神经网络，本质上是划定一个更大的函数选择范围，从而有机会包含更多样化的函数。

今天，我们将介绍一系列在训练类神经网络时常用的技巧。由于内容繁多且时间有限，许多技术可能只会以较快的节奏带过，但我会指出在过去课程的哪些部分可以找到更详细的资料。如果你没有训练类神经网络的经验，今天的内容可能会有些挑战。

本堂课的重点是，每当你听到一个关于训练类神经网络的新方法或技巧时，都应该问自己一个问题，并尝试填写下面的表格：

| 方法/技巧 | 改变了哪个步骤？ (1, 2, or 3) | 带来了什么好处？ (优化/泛化) |
| :--- | :--- | :--- |
|           |                               |                              |

首先，这个方法改变了机器学习三个步骤中的哪一个？它是一个新的损失函数，还是一个不同的网络架构（即划定了不同的选择范围），抑或是一种更高效的优化算法？

其次，这个方法到底带来了什么好处？很多人在介绍新方法时只会说“这个方法好”，但“好”可以有很多不同的面向。今天课程中提到的好处大致可分为两个方向：
1.  **更好的优化 (Optimization)**：这意味着我们可以找到更低的训练损失（Training Loss）。
2.  **更好的泛化 (Generalization)**：这意味着训练损失和验证损失（Validation Loss）更接近，能够有效避免**过拟合 (Overfitting)** 的发生。

每个方法针对的目标和解决的问题是不同的。因此，当你听到一个新技巧时，必须思考它带来的具体好处是什么，并根据不同情况选择合适的应对方法。

### 区分优化问题与泛化问题

举例来说，假设你先训练了一个线性模型（Linear Model），发现其损失可以降得很低。接着，你尝试训练一个类神经网络，却发现它的损失降得不如线性模型低。有些人会不假思索地称之为“过拟合”，这是不准确的。

如果深度学习模型的训练损失本身就降不下去，这不叫过拟合，而是在优化环节出了问题。深度网络的参数远多于线性模型，理论上它能做到的事情，线性模型也能做到。因此，它的损失至少应该和线性模型一样低，甚至更低。如果你发现深度网络的训练损失无法达到线性模型的水平，那就说明你的优化过程存在问题，此时应选择能强化优化的技巧。

反之，如果你发现训练损失已经足够低，但验证损失却无法随之下降，这才是真正的过拟合。在这种情况下，你才需要选择能够改善泛化的方法。

理解了这一点，今天的课程就没有白费。接下来，我们将系统地介绍一系列与训练类神经网络相关的方法，并按照它们所改变的步骤进行分类，同时指明其设计目标是优化还是泛化。我们将从步骤三开始，逆序进行讲解。

### 步骤三：优化算法的改进

我们先来回顾一下优化是如何进行的。通常我们使用最简单的**梯度下降法 (Gradient Descent)**，这是一种通过计算参数对损失函数的梯度来迭代更新参数，以寻找损失最小值的优化算法。其中，最原始、不加任何修饰的版本被称为 **Vanilla Gradient Descent**。

梯度下降的流程如下：
1.  随机初始化一组参数 $\theta_0$。
2.  计算在 $\theta_0$ 位置的梯度 $g_0$。
3.  使用学习率（Learning Rate）$\eta$ 更新参数：$\theta_1 = \theta_0 - \eta \cdot g_0$。
4.  重复此过程，直到梯度变得非常小，参数不再更新为止。

#### Optimizer：超越当前梯度的智慧

最原始的梯度下降法仅根据当前计算出的梯度来决定更新方向。如果当前梯度为零，更新就会停止。然而，有一系列被称为**优化器 (Optimizer)** 的技术，它们不仅考虑当前的梯度，还会综合利用从 $g_0$ 到 $g_t$ 的所有历史梯度信息，来共同决定下一步的前进方向。

在 PyTorch 等深度学习框架中，使用这些优化器通常只需在代码中修改一个英文单词。尽管实现简单，但理解其背后的原理至关重要。

#### 学习率的挑战与 Adagrad 的诞生

为什么我们需要优化器？一个主要原因是学习率（Learning Rate）极难调整。学习率设置得太大，参数更新可能会“飞出”损失函数的山谷；设置得太小，更新速度又会极其缓慢。

问题的根源在于，损失函数在不同参数维度上的“地势”变化可能截然不同。例如，在某个方向上梯度很大，需要较小的学习率；而在另一个方向上梯度很小，则需要较大的学习率。传统的梯度下降法对所有参数使用相同的学习率，这显然不是最佳策略。

我们应该因材施教，为每个参数设置不同的学习率。一个直观的想法是：如果某个方向的梯度通常很大，就给它较小的学习率；反之，如果梯度通常很小，就给它较大的学习率。

这个想法催生了 **Adagrad (Adaptive Gradient Algorithm)**，一种自适应学习率的优化器。它通过累积每个参数过去所有梯度的平方和来调整该参数的学习率。具体来说，参数 $\theta$ 的第 $i$ 个维度的更新公式如下：
$$
\theta_{t+1, i} = \theta_{t, i} - \frac{\eta}{\sigma_{t,i}} g_{t,i}
$$
其中，$g_{t,i}$ 是在第 $t$ 步时第 $i$ 个维度的梯度，而 $\sigma_{t,i}$ 是从第 0 步到第 $t$ 步所有梯度的平方和的平方根：
$$
\sigma_{t,i} = \sqrt{\sum_{j=0}^{t} (g_{j,i})^2}
$$
通过这种方式，梯度历史值越大的参数，其有效学习率就越小。

在实际演示中，使用普通梯度下降法时，学习率设为 0.0001 训练 100 步后进展缓慢，而设为 0.001 则会直接发散。但换用 Adagrad 后，我们可以将初始学习率设得更大（例如 1.0），因为它会自动调整每个参数的学习率。尽管初期更新可能不稳定，但模型很快就能走上正轨，在同样 100 步内达到的效果远超普通梯度下降法。

#### RMSprop：应对变化的梯度

Adagrad 有一个很强的假设：过去梯度的平均大小可以很好地预测未来。然而，在复杂的损失曲面上，同一个方向的梯度可能时大时小。Adagrad 会累积所有历史梯度，导致其对近期梯度的变化反应迟缓。

为了解决这个问题，**RMSprop (Root Mean Square Propagation)** 被提了出来。它是一种改进版的 Adagrad，通过引入一个衰减因子 $\alpha$，给予最近的梯度更大的权重。其 $\sigma$ 的计算方式变为一个指数移动平均：
$$
\sigma_{t,i}^2 = \alpha \cdot \sigma_{t-1,i}^2 + (1-\alpha) \cdot g_{t,i}^2
$$
这样，$\sigma$ 就能更及时地反映梯度的近期变化，使得学习率的调整更加灵活。

在一个形如香蕉的 **Rosenbrock 函数**（一个经典的优化测试函数）上进行测试，Adagrad 在 1000 次迭代后仍离最优点有显著距离。而 RMSprop 在同样步数下，由于能更快地调整学习率，可以走得更远，更接近最终结果。

#### Momentum：冲出局部最优的动量

除了学习率问题，梯度下降还可能在梯度很小的地方停滞，例如局部最小值（local minima）或鞍点（saddle point）。在现实物理世界中，一个滚下山坡的球因为有动量，并不会在平坦处立即停下。我们可以将**动量 (Momentum)** 的概念引入优化过程。

Momentum 方法的核心思想是，参数的更新方向不仅取决于当前的梯度，还取决于过去所有梯度的累积。我们将历史梯度的加权平均值记为 $m_t$：
$$
m_t = \beta \cdot m_{t-1} + (1-\beta) \cdot g_t
$$
然后，我们使用这个动量 $m_t$ 来更新参数，而不是直接使用梯度 $g_t$：
$$
\theta_{t+1} = \theta_t - \eta \cdot m_t
$$
这样，即使当前梯度为零，只要历史动量不为零，参数更新仍会继续，从而有机会“冲”过鞍点甚至一些较浅的局部最小值。

在一个布满局部最小值的 **Rastrigin 函数**上测试，RMSprop 很快就陷入了一个局部最优并停止更新。而 Momentum 方法则能凭借累积的动量，成功翻越一个又一个“山丘”，最终在全局最优解附近稳定下来。

#### Adam：动量与自适应学习率的结合

RMSprop 累积的是梯度平方（不考虑方向），用于调整学习率；Momentum 累积的是梯度本身（考虑方向），用于决定更新方向。这两者可以结合吗？当然可以。

将它们结合起来，就得到了 **Adam (Adaptive Moment Estimation)**，这至今仍是深度学习中最常用、最默认的优化器之一。Adam 同时维护了梯度的一阶矩估计（动量）和二阶矩估计（类似 RMSprop 的自适应学习率项），并将两者结合起来更新参数。

在香蕉函数上进行测试，Adam 的表现优于 RMSprop。在同样 1000 次迭代下，Adam 能够稳定地走到全局最优点，而 RMSprop 则无法做到。

#### 学习率调度：动态调整学习率

除了优化器本身，我们还可以动态地改变基础学习率 $\eta$。这种技术称为**学习率调度 (Learning Rate Scheduling)**。一种在训练大模型时常见的策略是“先增后减”：
*   **Warm-up (预热)**：在训练初期，逐渐增大学习率。这可以看作是给优化器一个探索地形的机会，让它更好地估计动量和梯度方差。
*   **Decay (衰减)**：在训练后期，逐渐减小学习率。这有助于模型在最优点附近稳定下来，进行精细调整，避免因学习率过大而在最优解两侧震荡。

#### 优化器总结

| 方法/技巧 | 改变了哪个步骤？ | 带来了什么好处？ |
| :--- | :--- | :--- |
| **Optimizer** (Adagrad, Adam 等) | 步骤三：优化算法 | **优化** (找到更低的训练损失) |

优化器通常对泛化没有直接帮助。有时使用 Adam 虽然降低了训练损失，但验证损失反而可能比普通梯度下降更高，因为在训练集上找到更低的损失不保证在验证集上表现更好。

#### Dropout：为泛化而生的优化步骤修改

有一个特殊的方法叫 **Dropout**，它是一种在训练过程中随机丢弃（即暂时忽略）一部分神经元的技术。在验证和测试时，则会使用所有神经元。

这个概念类似于在腿上绑沙袋进行训练，比赛时取下沙袋就能跑得更快。通过在训练时增加难度，强迫网络学习到更鲁棒的特征，而不是依赖于少数几个神经元的协同作用。

| 方法/技巧 | 改变了哪个步骤？ | 带来了什么好处？ |
| :--- | :--- | :--- |
| **Dropout** | 步骤三：优化算法 | **泛化** (降低过拟合) |

需要注意的是，Dropout 对优化本身没有好处，甚至会使训练损失变得更高。因此，它只适用于已经出现过拟合（即优化已经做得很好，但验证效果不佳）的情况。

#### 初始化与预训练：赢在起跑线上

梯度下降的起始点，即参数的**初始化 (Initialization)**，也会对最终结果产生巨大影响。不同的初始位置可能会导向不同的局部最优解。

即便使用强大的优化器，好的初始化依然至关重要。例如，使用 **Kaiming 初始化**（一种根据网络层维度来调整随机初始值范围的方法，由何愷明提出）可以显著改善训练效果，让模型收敛到更低的损失。

更进一步，初始化不仅影响能否找到最低点，还影响找到的最低点的“质量”。一个平坦宽阔的“盆地”型最低点通常比一个尖锐狭窄的“峡谷”型最低点具有更好的泛化能力，因为它对训练数据和测试数据之间的微小差异不那么敏感。

在 2025 年，一个通用的、强大的初始化大招是**预训练 (Pre-training)**。其核心思想是，在针对目标任务（如下游任务，downstream task）进行训练之前，先让模型在一个大规模、通用的任务（如**代理任务，pretext task**）上进行学习。例如，在教模型分类动物之前，先让它学习预测一张图片被旋转了多少度。通过这个代理任务，模型可以学到通用的视觉特征，这些特征为后续的分类任务提供了一个极佳的起点。

这种方法通常也被称为**自监督学习 (Self-supervised Learning)**。

| 方法/技巧 | 改变了哪个步骤？ | 带来了什么好处？ |
| :--- | :--- | :--- |
| **Initialization / Pre-training** | 步骤三：优化算法 (选择起点) | **优化** + **泛化** |

预训练的神奇之处在于，它能同时改善优化（提供更好的起点）和泛化（学到更鲁棒、通用的特征）。

### 步骤二：函数选择范围（网络架构）

我们希望函数（模型）的选择范围不大不小，恰到好处。范围太小，可能不包含最优解；范围太大，则容易过拟合。设计一个好的网络架构，就是利用**领域知识 (Domain Knowledge)** 来划定一个既小又包含最优解的函数范围。

#### CNN：为图像处理量身定做的架构

**卷积神经网络 (Convolutional Neural Network, CNN)** 是一个利用领域知识设计网络架构的经典范例。对于一张 1000x1000 像素的彩色图像，其输入维度高达 300 万。如果使用全连接网络（MLP），第一层若有 1000 个神经元，参数量就将达到惊人的 30 亿。

然而，处理图像真的需要每个神经元都观察整张图片吗？人类的智慧告诉我们并非如此。
1.  **局部性 (Receptive Field)**：图像中的基本模式（如鸟嘴、眼睛）通常只占很小一部分区域。因此，我们可以让每个神经元只负责观察一个小的**感受野 (Receptive Field)**，而不是整张图片。这极大地减少了参数数量。
2.  **平移不变性 (Parameter Sharing)**：同一个模式（如鸟嘴）可能出现在图片的不同位置。检测这些模式的神经元，其功能是相同的，因此它们可以共享同一组参数（这组共享的参数被称为**滤波器 Filter** 或**卷积核 Kernel**）。

通过引入感受野和**参数共享 (Parameter Sharing)**，CNN 本质上是全连接网络的一个简化版。它限制了函数的搜索范围，排除了那些我们根据领域知识认为不可能是最优解的函数，从而形成了一个更小、更优的函数集合。

| 方法/技巧 | 改变了哪个步骤？ | 带来了什么好处？ |
| :--- | :--- | :--- |
| **CNN** | 步骤二：函数范围 | **泛化** (为图像任务设计，避免过拟合) |

#### Skip Connection 与 Normalization：为优化服务的架构

网络架构的设计不仅影响泛化，也深刻影响优化过程。在深度网络中，一个常见的问题是**梯度消失 (Gradient Vanishing)** 或**梯度爆炸 (Gradient Explode)**，即梯度在反向传播过程中变得过小或过大，导致底层网络难以训练。

**跳跃连接 (Skip Connection)** 或称**残差连接 (Residual Connection)**，通过在网络中创建“高速公路”，让输入信号可以直接跳过多层传递到后面，从而也为梯度提供了一条无障碍的传播路径。这极大地缓解了梯度消失问题，使得损失曲面变得更加平滑，让训练非常深的网络成为可能。

另一类有助于优化的架构设计是**归一化 (Normalization)**，如**批量归一化 (Batch Normalization)** 和**层归一化 (Layer Normalization)**。它们通过对每一层网络的输出进行重新缩放，将其限制在特定范围内（例如均值为0，方差为1）。这有助于稳定训练过程，使得我们可以使用更大的学习率，从而加速优化。

| 方法/技巧 | 改变了哪个步骤？ | 带来了什么好处？ |
| :--- | :--- | :--- |
| **Skip Connection** | 步骤二：函数范围 | **优化** (让损失曲面更平滑) |
| **Normalization** | 步骤二：函数范围 | **优化** (稳定训练) + 轻微**泛化** |

### 步骤一：损失函数的定义

#### 分类任务的损失函数：交叉熵

对于回归任务，我们通常使用均方误差（MSE）作为损失函数。但对于分类任务，例如图像分类，我们关心的是**准确率 (Accuracy)**。然而，准确率是一个不可微的函数（参数的微小变化通常不会改变最终分类结果，导致梯度为零），因此不能直接用作梯度下降的损失函数。

为了解决这个问题，我们使用**交叉熵 (Cross-Entropy)** 作为分类任务的标准损失函数。它是一种衡量两个概率分布之间差异的指标。我们会先通过 **Softmax** 函数将网络输出的原始分数（logits）转换为一个概率分布，然后计算这个预测概率分布与表示真实标签的“one-hot”概率分布之间的交叉熵。交叉熵是平滑且可微的，非常适合梯度下降。

| 方法/技巧 | 改变了哪个步骤？ | 带来了什么好处？ |
| :--- | :--- |
| **Cross-Entropy** | 步骤一：损失函数 | **优化** (使分类任务可被梯度下降优化) |

需要注意的是，训练时优化交叉熵，而测试时评估准确率，这本身就引入了训练和评估之间的不匹配，可能对泛化产生细微的负面影响。

#### 数据的力量：更多数据与数据增强

克服过拟合最直接、最有效的方法就是**收集更多的训练数据**。数据越多，模型就越能学习到具有代表性的真实世界分布。

| 方法/技巧 | 改变了哪个步骤？ | 带来了什么好处？ |
| :--- | :--- | :--- |
| **更多数据** | 步骤一：损失函数 (改变求和项) | **泛化** (最有效的抗过拟合方法) |

当无法收集更多真实数据时，我们可以使用**数据增强 (Data Augmentation)** 来人工创造新数据。例如，对于图像，可以进行翻转、裁剪、模糊、变色等操作；对于语音，可以改变音量、语速或转换声音。一种有趣的技术是 **Mixup**，它将两张图片及其标签按一定比例混合，生成新的训练样本。

数据增强同样会使优化变得更困难，但能显著提升模型的泛化能力。

#### 半监督学习：利用无标签数据

在很多场景下，无标签数据远比有标签数据更容易获取。**半监督学习 (Semi-supervised Learning)** 就是利用大量无标签数据来辅助模型训练的方法。这通常基于一些假设：
1.  **聚类假设**：相似的数据点应该属于同一类别。
2.  **低密度分离假设**：决策边界应该穿过数据密度低的区域。

基于这些假设，我们可以设计额外的损失项来利用无标签数据。例如，可以鼓励模型对无标签数据的预测具有较低的熵（即更自信的预测），或者鼓励相似的无标签数据点拥有相似的预测结果。

| 方法/技巧 | 改变了哪个步骤？ | 带来了什么好处？ |
| :--- | :--- | :--- |
| **Semi-supervised Learning** | 步骤一：损失函数 | **泛化** |

#### 正则化：对参数的偏好

除了基于数据的损失，我们还可以定义一些与数据无关、仅反映我们对参数偏好的损失项，这被称为**正则化 (Regularization)**。我们通常偏好更“简单”或“平滑”的函数，因为根据奥卡姆剃刀原则，这样的函数泛化能力更强。

在实践中，“简单”通常被定义为参数的数值更小。**L2 正则化**通过在损失函数中加入一个惩罚项（所有参数的平方和），来鼓励模型学习到更小的权重。

在优化算法的视角下，L2 正则化等价于**权重衰减 (Weight Decay)**，即在每次参数更新时，都先将参数值乘以一个小于 1 的系数（如 0.999），使其“衰减”一点。

**AdamW** 是一个将权重衰减与 Adam 优化器正确结合的版本。它在 Adam 的基础上加入了权重衰减，从而在保持强大优化能力的同时，提升了泛化性能。

| 方法/技巧 | 改变了哪个步骤？ | 带来了什么好处？ |
| :--- | :--- | :--- |
| **L2 Regularization / Weight Decay** | 步骤一 (损失) / 步骤三 (优化) | **泛化** |
| **AdamW** | 步骤三：优化算法 | **优化** + **泛化** |

### 结语：掌握分析框架

今天我们介绍了大量训练神经网络的技巧。如果你无法记住所有细节，请务必记住这个核心的分析框架：

**当你遇到任何一个新方法时，问自己两个问题：**
1.  **它改变了机器学习的哪一个步骤？（损失、架构、还是优化？）**
2.  **它的主要目的是为了改善优化，还是为了增强泛化？**

掌握了这个框架，你就能更深刻地理解各种技术的本质，并在实践中做出更明智的选择。