AI-For-Beginners/translations/zh-CN/lessons/4-ComputerVision/08-TransferLearning/TrainingTricks.md

108 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 深度学习训练技巧
随着神经网络的加深,其训练过程变得越来越具有挑战性。一个主要问题是所谓的[梯度消失](https://en.wikipedia.org/wiki/Vanishing_gradient_problem)或[梯度爆炸](https://deepai.org/machine-learning-glossary-and-terms/exploding-gradient-problem#:~:text=Exploding%20gradients%20are%20a%20problem,updates%20are%20small%20and%20controlled)。[这篇文章](https://towardsdatascience.com/the-vanishing-exploding-gradient-problem-in-deep-neural-networks-191358470c11)对这些问题进行了很好的介绍。
为了使深度网络的训练更高效,可以使用一些技巧。
## 保持数值在合理范围内
为了使数值计算更稳定,我们需要确保神经网络中的所有数值都在合理的范围内,通常是 [-1..1] 或 [0..1]。这并不是一个非常严格的要求,但浮点计算的特性决定了不同数量级的数值无法被准确地一起操作。例如,如果我们将 10<sup>-10</sup> 和 10<sup>10</sup> 相加,结果很可能是 10<sup>10</sup>,因为较小的值会被“转换”到与较大值相同的数量级,从而导致尾数丢失。
大多数激活函数在 [-1..1] 范围内具有非线性特性,因此将所有输入数据缩放到 [-1..1] 或 [0..1] 范围是有意义的。
## 初始权重初始化
理想情况下,我们希望数值在通过网络层后仍保持在相同的范围内。因此,初始化权重时需要确保数值分布的保留。
正态分布 **N(0,1)** 并不是一个好选择,因为如果我们有 *n* 个输入,输出的标准差将是 *n*,数值很可能会超出 [0..1] 的范围。
以下是常用的初始化方法:
- 均匀分布 -- `uniform`
- **N(0,1/n)** -- `gaussian`
- **N(0,1/√n_in)** 保证对于均值为零、标准差为 1 的输入,输出的均值和标准差保持不变
- **N(0,√2/(n_in+n_out))** -- 所谓的 **Xavier 初始化** (`glorot`),有助于在前向传播和反向传播中保持信号在合理范围内
## 批量归一化
即使有了合适的权重初始化,训练过程中权重仍可能变得非常大或非常小,从而使信号超出合理范围。我们可以通过使用某种**归一化**技术将信号拉回合理范围。虽然有多种归一化方法(如权重归一化、层归一化),但最常用的是批量归一化。
**批量归一化**的思想是考虑小批量中的所有数值,并基于这些数值进行归一化(即减去均值并除以标准差)。它被实现为一个网络层,在应用权重后但在激活函数之前进行归一化。结果是,我们通常会看到更高的最终准确率和更快的训练速度。
以下是关于批量归一化的[原始论文](https://arxiv.org/pdf/1502.03167.pdf)、[维基百科解释](https://en.wikipedia.org/wiki/Batch_normalization)以及[一篇很好的入门博客](https://towardsdatascience.com/batch-normalization-in-3-levels-of-understanding-14c2da90a338)(还有[俄文版](https://habrahabr.ru/post/309302/))。
## Dropout
**Dropout** 是一种有趣的技术,它在训练过程中随机移除一定比例的神经元。它被实现为一个具有一个参数的层(移除神经元的百分比,通常为 10%-50%),在训练过程中,它会将输入向量的随机元素置零,然后再传递到下一层。
虽然这听起来像是一个奇怪的想法,但你可以在 [`Dropout.ipynb`](../../../../../lessons/4-ComputerVision/08-TransferLearning/Dropout.ipynb) 笔记本中看到 Dropout 对训练 MNIST 数字分类器的效果。它加速了训练,并使我们能够在更少的训练轮次中达到更高的准确率。
这种效果可以通过以下几种方式解释:
- 它可以被认为是对模型的随机冲击因素,从而将优化从局部最小值中拉出
- 它可以被视为*隐式模型平均化*,因为我们可以说在 Dropout 过程中我们训练了略有不同的模型
> *有人说,当一个醉酒的人试图学习某些东西时,与清醒的人相比,他第二天早上会记得更清楚,因为一个有一些功能失常神经元的大脑会更努力地适应以抓住意义。我们自己从未验证过这是否属实。*
## 防止过拟合
深度学习中一个非常重要的方面是能够防止[过拟合](../../3-NeuralNetworks/05-Frameworks/Overfitting.md)。虽然使用非常强大的神经网络模型可能很有吸引力,但我们应该始终平衡模型参数的数量与训练样本的数量。
> 确保你理解我们之前介绍的[过拟合](../../3-NeuralNetworks/05-Frameworks/Overfitting.md)概念!
以下是防止过拟合的几种方法:
- 提前停止 -- 持续监控验证集上的误差,当验证误差开始增加时停止训练。
- 显式权重衰减 / 正则化 -- 在损失函数中添加一个额外的惩罚项,用于限制权重的绝对值过大,从而防止模型产生非常不稳定的结果
- 模型平均化 -- 训练多个模型,然后对结果进行平均。这有助于最小化方差。
- Dropout隐式模型平均化
## 优化器 / 训练算法
训练的另一个重要方面是选择合适的训练算法。虽然经典的**梯度下降**是一个合理的选择,但它有时可能过于缓慢,或者导致其他问题。
在深度学习中,我们使用**随机梯度下降**SGD它是对从训练集中随机选择的小批量数据应用的梯度下降。权重通过以下公式调整
w<sup>t+1</sup> = w<sup>t</sup> - η∇ℒ
### 动量
在**动量 SGD** 中,我们保留了前几步的部分梯度。这类似于当我们以惯性移动时,如果受到一个不同方向的冲击,我们的轨迹不会立即改变,而是保留了一部分原始运动。这里我们引入另一个向量 v 来表示*速度*
- v<sup>t+1</sup> = γ v<sup>t</sup> - η∇ℒ
- w<sup>t+1</sup> = w<sup>t</sup> + v<sup>t+1</sup>
这里参数 γ 表示我们考虑惯性的程度:γ=0 对应于经典 SGDγ=1 是一个纯粹的运动方程。
### Adam, Adagrad 等
由于在每一层中我们将信号乘以某个矩阵 W<sub>i</sub>,根据 ||W<sub>i</sub>||,梯度可能会减小接近于 0或者无限增大。这正是梯度爆炸/消失问题的本质。
解决此问题的一种方法是仅在公式中使用梯度的方向,而忽略其绝对值,即:
w<sup>t+1</sup> = w<sup>t</sup> - η(∇ℒ/||∇ℒ||),其中 ||∇ℒ|| = √∑(∇ℒ)<sup>2</sup>
这种算法被称为 **Adagrad**。其他使用相同思想的算法包括:**RMSProp****Adam**
> **Adam** 被认为是许多应用中非常高效的算法,因此如果你不确定使用哪种算法,可以选择 Adam。
### 梯度裁剪
梯度裁剪是上述思想的扩展。当 ||∇ℒ|| ≤ θ 时,我们在权重优化中使用原始梯度;当 ||∇ℒ|| > θ 时,我们将梯度除以其范数。这里 θ 是一个参数,在大多数情况下我们可以取 θ=1 或 θ=10。
### 学习率衰减
训练的成功往往取决于学习率参数 η。可以合理地假设,较大的 η 值会导致更快的训练,这是我们通常在训练初期所希望的,而较小的 η 值则允许我们对网络进行微调。因此,在大多数情况下,我们希望在训练过程中逐渐减小 η。
这可以通过在每个训练轮次后将 η 乘以某个数(例如 0.98)来实现,或者使用更复杂的**学习率调度**。
## 不同的网络架构
为你的问题选择合适的网络架构可能会很棘手。通常,我们会选择一个已被证明适用于我们特定任务(或类似任务)的架构。这里有一个关于计算机视觉神经网络架构的[很好的概述](https://www.topbots.com/a-brief-history-of-neural-network-architectures/)。
> 选择一个足够强大的架构来匹配我们拥有的训练样本数量是很重要的。选择过于强大的模型可能会导致[过拟合](../../3-NeuralNetworks/05-Frameworks/Overfitting.md)。
另一种好的方法是使用能够自动调整到所需复杂度的架构。在某种程度上,**ResNet** 架构和 **Inception** 是自适应的。[更多关于计算机视觉架构的信息](../07-ConvNets/CNN_Architectures.md)
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。