1. 引言

深度学习因其较高的复杂性和众多的参数,我们很不容易训练出好的模型,模型也缺乏可解释性,因此深度学习从业者一般也自嘲自己是“炼丹师”。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数

为了快速训练出好的模型,过去的学者也总结出来很多技巧进行辅助训练。在前人的基础上,我们可以学习、理解各种影响训练过程和结果的问题及其对应的解决方案。

需要注意的是,根据可用数据的规模和质量、模型的类型和复杂度、任务的类型和应用要求、可用设备的性能等,我们在具体训练时需要解决的问题也不同,应当因地制宜,活学活用。

2. 当梯度≈0时

2.1 判断critical point的类型

2.1.1 理论分析

梯度近似为0的时候,训练损失几乎不再改变,此时损失可能达到了全局最小值,也有可能停在了局部最小值(Local Minima)和马鞍点(Saddle Point)。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_02

我们需要判断梯度近似为0的原因,才能针对性地进行处理,而判断的前提是知道 loss function 的形状。然而,深度学习的网络非常复杂,我们无法得知完整的 loss function,但可以使用泰勒公式近似局部的 loss function来帮助我们稳定点(critical point)的位置。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_03

如上图所示,可以使用点如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_04的值来近似如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_05的值,其中绿线是一阶导数项的贡献,红线是二阶导数项的贡献。

当处于critical point时,一阶导数为0,此时需要通过二阶导数项来判断具体类型。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_06

我们可以发现,不同critical point周边点的大小是不同的,可以直观判断出所处的类型,但问题在于我们实际上无法绘制出类似的图形来进行判断。正确方式是基于 Hessian 矩阵的奇异值来判断。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_07

2.1.2 举例说明

为方便理解,我们构建了一个最简单的神经网络,而且仅用一个样本训练,然后计算损失分布。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_08

在上图中,颜色越亮,说明损失值就越大。critical point有七个,分为 Minima 和 saddle 两种。

在已知损失函数的情况下,我们可以直接计算出 critical point 的一阶和二阶微分(以(0,0)点为例),然后根据二阶微分的值判断出该点的类型为 saddle point。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_09

类似地,我们也可以判断其他6个 critical point 的类型。

2.2 应对方案

2.2.1 Saddle Point

Hessian

如果遇到了 saddle point,不用担心,可以通过 Hessian 计算出可行的方向进行参数更新。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_10

按照之前的示例,我们可以计算得出更新的方向可以为(1,1)。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_11

但实际上,这种寻找参数更新方向的方法计算量天大,实际还有其他高效的计算方法。

Momentum

Momentum 将现实世界中的惯性概念引入到了模型训练中,是一项对抗 saddle point 和 local Minima 的技术。它的主要思想是,让每次的更新步伐在本次梯度的基础上加上之前梯度的值,这样可以避免本次梯度为0时模型不再更新的问题。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_12

更具体的运算过程如下图所示:

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_13

要注意的是,Momentum 不仅考虑了过去的梯度的值,还包括梯度的方向。

2.2.2 Local Minima

另外要注意的是,在高维空间中,Local Minima几乎不会出现,因为不大可能所有的维度的梯度都近似为0。低维空间中找不到的路,在高维空间可能很容易找到。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_14

实证研究也证实了这一点,如下图所示。因此,我们也不必担心 Local Minima 的问题。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_15

3. 当梯度≠0但训练损失不下降

3.1 原因分析

除了 critical point 的问题外,我们经常遇到的问题是损失函数不变,梯度却来回振荡。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_16

我们在实际训练的时候,即使是一个很简单的深度学习模型,我们都可能 train 不起来。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_17

背后的原因在于,不同的参数使用的学习率的相同的,A参数合适的学习率对于B参数可能就会过小,也可能过大导致无法收敛。因此,我们需要为不同的参数设置不同的学习率。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_18

3.2 应对方案

根据调整学习率的不同方式,有不同的方法可以使用来解决梯度振荡的问题。

3.2.1 Adagrad

Adagrad 使用 Root Mean Square 作为参数依赖的 如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_19,考虑过去梯度调整当前学习率。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_20

3.2.2 RMSProp

即使是同一个参数,在更新过程中可能会经历梯度逐渐下降和上升的不同过程,需要快速反应。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_21

以下是具体的算法过程,其中我们需要设置权重 如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_22 来表示过去梯度的重要性。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_23

下图可以形象表达 RMSProp 的工作特点,相比 Adagrad,它给予不同时期梯度以不同的权重。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_24

3.2.3 Adam

Adam 是目前最常用的模型训练方法,需要设置超参数。但是默认的超参数设置已经很好了。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_25

3.2.4 Learning Rate Scheduling

当使用 Adagrad 训练模型时,若某个维度一直未能更新,则 如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_19 会变得很小导致很大的学习率,该维度会经历一次很大的剧变,然后逐渐收敛回来,周而复始。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_27

解决这个问题的方法是动态调整 learning Rate 的数值,大方向是随着时间而降低。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_28

经过实验发现,Warm up在训练 Bert 模型时很好用,一种解释是刚开始的时候因为数据量不足、统计值不具备代表性所以先降低学习率避免风险。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_29

3.2.5 总结


如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_30

4. 权衡模型训练的速度和质量

4.1 Batch 的一般理解

Batch 是深度学习模型训练时经常使用的方法,它不使用所有样本的损失总和去做微分,而是使用部分(batch size)样本的损失做微分。一般认为,small Batch 的使用会加快参数更新的速度,但会降低看完整个数据集(epoch)的速度,以及每次参数更新的质量不够高。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_31

然而,实际上我们可以使用GPU平行计算加快大batch的运算速度(非倍增),但存在极限。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_32

另一方面,当batch较小时,运算完一个epoch所需要的时间会很大。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_33

也就是说,当使用了GPU后,Full batch 的参数更新速度快且稳定,优于 batch,是这样吗?

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_34

4.2 Small Batch 的出乎意料

反直觉的是,实验发现 smaller batch 反而增强了模型训练后的效果。noisy 反而是有价值的?

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_35

不稳定有助于跳出 critical point

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_36

不稳定有助于收敛到平稳 Minima

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_37

当处于平稳 Minima 时,测试集与训练集的细微变化对结果的影响不会很大,避免overfiting。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_38

4.3 Batch 使用总结


如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_39

目前也有很多学者探讨如何结合 small batch 和 large batch的优势,达到鱼与熊掌兼得的目的。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_40

5. 重置模型的损失函数及影响

损失函数会影响我们训练模型的难度以及最终模型的性能。因此,我们可以尝试修改损失函数。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_41

5.1 更改损失函数

回归和分类是机器学习中常见的两个任务,对于任务完成的好坏也有不同的损失函数,如果错用可能很难训练出满意的模型。例如,如果将一个分类任务当做回归任务来处理,可能会出现问题。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_42

与回归不同的是,在处理分类任务时,我们需要使用 one-hot vector 来处理类别变量。即,在神经网络模型中,回归任务的输出只有一项,而分类任务会有很多项。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_43

为了更方便的进行分类,一般会使用softmax函数将连续值映射为0-1的值。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_44

注意:Softmax和 Sigmoid 本质上是一样的,后者用于二分类任务中。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_45

分类任务的损失函数一般使用 cross-entropy,要比使用 MSE 要好得多。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_46

从下图中可以直观发现使用 MSE 训练分类模型的不足:很容易陷入 critical point。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_47

5.2 更改输入变量

除了更改损失函数外,我们还可以更改输入的变量尺度,来间接降低模型训练的难度。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_48

从上图可知,改变两个参数相同大小,参数对应的变量范围大小决定了影响模型性能的程度。反之,如果将变量的范围归一化,那么不同参数的敏感性就相同,可以使用相同的学习率。

如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_49

在实际操作中,可以对 如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_50如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_51 做标准化,结果差异并不大,任意选择一个即可。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_52

要注意在每一层网络中都要进行标准化的操作,而不仅仅是一开始做一次而已。另外,均值和方法的计算需要考虑所有样本,但这样计算效率就会很低,可以考虑使用Batch Normalization技术。

如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_53

Batch 需要设置足够大,以便计算有效的均值和方差(保证代表性)。如何使用别人训练好的神经网络 如何训练一个神经网络_深度学习_54如何使用别人训练好的神经网络 如何训练一个神经网络_损失函数_55 是引入是为了防止均值为0带来的负面影响,具体值由学习得到。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_56

再具体实施时,我们不能等到样本达到一个 Batch 才开始计算。当达不到时,我们使用移动平均来考虑之前的数据进行均值和方差的计算。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_57

实验表明,Batch normalization 可加快收敛速度,但未必提高收敛质量。目前没有很好的解释。

如何使用别人训练好的神经网络 如何训练一个神经网络_最小值_58

参考资料

  1. 李宏毅深度学习教程视频