一、Normlization
原因和动机
在机器学习和深度学习中,有一个共识:独立同分布的数据可以简化模型的训练以及提升模型的预测能力——这是通过训练数据获得的模型能够在测试集获得好的效果的一个基本保障。也就是说我们在使用机器学习和深度学习的时候,会把数据尽可能的做一个独立同分布的处理,用来加快模型的训练速度和提升模型的性能。说到这里就不得不提一下——白化whitening。
白化whitening
什么是白化呢?就是对数据进行如下的2个操作:
1. 去除数据之间的关联性,使之满足独立这个条件;
2. 使得特征具有相同的均值和方差,就是同分布。
首先看看,深度学习中的一个经典问题。Internal Covariate Shift——内部变量偏移
深度学习这种包含很多隐层的网络结构,在训练过程中,因为各层参数不停在变化。另一方面,深度神经网络一般都是很多层的叠加,每一层的参数更新都会导致上层的输入数据在输出时分布规律发生了变化,并且这个差异会随着网络深度增大而增大——这就是Internal Covariate Shift。它会导致什么样的问题呢?
每个神经元的输入数据不再是独立同分布的了,那么:
- 上层参数需要不断适应新的输入数据分布,降低学习速度
- 下层输入的变化可能趋向于变大或者变小,导致上层落入饱和区。反向传播时低层神经网络的梯度消失,这是训练深层神经网络收敛越来越慢的本质原因——梯度消失。
BN把每层神经网络任意神经元这个输入值的分布强行拉回到均值为0方差为1的标准正态分布,其实就是把越来越偏的分布强制拉回比较标准的分布。这样让梯度变大,避免梯度消失问题产生,而且梯度变大意味着学习收敛速度快,能大大加快训练速度。经过BN后,目前大部分Activation的值落入非线性函数的线性区内,其对应的导数远离导数饱和区,这样来加速训练收敛过程。
BN
BN的目标是标准化任何特定层的输入(即来自前一层的激活)。 标准化输入意味着网络中任何层的输入都应该具有近似为零的均值和单位方差。 在数学上,BN 层通过减去当前小批量中的输入均值并除以标准差来转换当前小批量中的每个输入。
但是每一层不需要期望具有零均值和单位方差的输入,相反,模型可能在其他一些均值和方差的情况下表现更好。 因此,BN 层还引入了两个可学习参数 γ 和 β。
整个层操作如下。 它接受输入\(x_i\) 并将其转换为 \(y_i\),如下图所述。
缺点:
- BN 在每次训练迭代中计算批次统计数据(Mini-batch 均值和方差),因此在训练时需要更大的批次大小,以便它可以有效地从 mini-batch 逼近总体均值和方差。 这使得 BN 更难训练用于对象检测、语义分割等应用的网络,因为它们通常在高输入分辨率(通常高达 1024x 2048)下工作,并且使用更大的批量进行训练在计算上是不可行的。
- 在Rnn中不适用。Rnn是根据时间步往后传递的,需要在每个时间步长都需要单独的计算γ 和 β,RNN和BN一起使用比较困难。此外在RNN中因为每条输入样本的长度是不同的,对padding后的样本计算均值和方差不太合理。
- 训练和测试阶段的不一致。在测试阶段是不计算均值和方差的,而是使用固定的均值和方差(从训练数据得到的),引入了计算的复杂度。
LN
简单总结来说:Batch Normalization 的处理对象是对一批样本, Layer Normalization 的处理对象是单个样本。Batch Normalization 是对这批样本的同一维度特征做归一化, Layer Normalization 是对这单个样本的所有维度特征做归一化。
二、过拟合和欠拟合
如何区分过拟合和欠拟合?
过拟合的原因?
- 训练数据包含噪声
- 训练集和测试集的数据分布就不同
- 训练数据量不足
- 训练过度
- 模型太复杂
解决方式
(要和原因一一匹配)
- 更多的数据
- early stopping
- 正则化
- 正则化表示的是在原来损失函数的基础上加上一些正则化项。或者称为模型复杂度的惩罚项。
- 正则化是结构风险最小化的策略实现。
- L1正则化是指权值向量中各个元素的绝对值之和,L2正则化是指权值向量中各个元素的平方和然后再求平方根。
西瓜书:以线性回归模型,平方误差为损失函数为例,优化目标为
当样本特征很多,而样本数量很少。容易出现过拟合,为了缓解过拟合,可以引入正则化项。
如果使用L2范数正则化(权值向量w中各元素的平方和再开根号)。则有
L1范数正则化(权值向量w中各元素的绝对值之和)
加入正则化项以后,优化目标的求解要在平方误差项和正则化项之间折中,(画图的话就是相交处)
采用\(L_1\)范数时,平方误差项等值线与正则化项等值线的交点常出现在坐标轴上,即w1 或者w2为0。而采用\(L_2\)范数的时候,两者交点常出现在某个象限中,即w1和w2均非0。因此L1范数比L2范数更容易得到稀疏解。
西瓜书:w 取得稀疏解意味着初始的d个特征中仅有对应着w的非零分量特征才会出现在最终的模型中。因此求解L1范数正则化的结果是得到了仅采用一部初始特征的模型。
- L1是拉普拉斯分布,L2是高斯分布
- L1正则化问题的求解可使用近端梯度下降。
- Dropout
- 直观上理解,dropout会使某些神经元失活,得到一个较小的网络,从而达到正则化的目的;
- 另一方面,它使得某一个节点不再依赖上一层的某个节点(因为这个节点可能会随机失活)所以该神经元不会再特别依赖于任何一个输入特征,即不会给任何一个输入特征设置太大的权重。(如果该特征是噪音的话,影响从而变小了)
- 在训练和测试阶段怎么用
- 训练阶段:每个神经元p%概率被删除,然后用新的网络结构训练。
- Training 使用Dropout,比如p%,而Testing不用Dropout. 但是Testing时权值需要乘以(1-p%)
!! 重要的补充知识:BN和Dropout在训练和测试时的差别
三、常见的激活函数 & 导数
激活函数的主要作用是提供网络的非线性建模能力,如果没有激活函数,那么神经网络只能表达线性映射,此刻即便是有再多的隐藏层,其整个网络跟单层神经网络也是等价的。因此可以说,只有加入了激活函数之后,深度神经网络才具备了分层的非线性的学习能力。
激活函数至少应该满足以下几点:
- 可微性:因为优化方法是基于梯度的,这个性质是必须的
- 单调性:当激活函数是单调的时候,能够保证单层网络是凸函数
1. sigmoid
或者是:
对应的导函数:
将输入值映射到区间(0,1),当z很大时,f(z)趋近于1;当z很小时,f(z)趋近于0.
导数在z很大或者很小的时候,都趋近于0,造成梯度消失的现象。
2. tanh
3. relu
对应的导函数:
ReLU是针对sigmoid和tanh的饱和性提出的新的激活函数。从上图中可以很容易的看到,当 \(z>0\) 的时候,不存在饱和问题,所以ReLU能够在 \(z>0\) 的时候保持梯度不衰减,从而缓解梯度消失的问题。
然而,随着训练的推进,部分输入会落入硬饱和区导致权重无法更新,这种现象称为“神经元死亡”。
- relu的优点:
- 解决了梯度消失、爆炸的问题
- 计算方便,计算速度快
- 加速了网络的训练
- relu的缺点:
- 由于负数部分恒为0,会导致一些神经元无法激活(可通过设置小学习率部分解决)
- 输出不是以0为中心的
3-1. LeakyRelu
四、常用损失函数
五、优化算法
BGD、SGD、小批量梯度下降、动量优化算法、自适应学习率优化算法;batch-size如何设置,过大过小会怎样,若硬件满足要求,为什么不能无限增大batch-size
六、评价指标
准确率、精确率、召回率、F1、AUC(GAUC)、RMSE等 意义是什么;都是在什么情况下使用
七、模型训练攻略
网络训练过程中几个关键点
批处理的大小
大的batch size梯度在更新的时候会更稳,且更新的时候更能精准的沿着梯度下降的方向做梯度更新。然而,实验证明,小的batch size反而更有助于模型训练,当batch size过分大的时候(大过几千),模型的精度会有明显的下降,这个现象不是Overfitting,也不是Model bias造成的,而是Optimization造成的。
原因:
大的 batch_size 为整个训练数据的时候
- 一个可能的解释是,当采用大batch size训练时,并且当参数更新至局部最优点或者鞍点的时候,显然梯度为0,就不会再更新了,因为下一次更新时输入数据没有改变,损失函数也不会有变化,但是,如果现在是将一小部分数据作为一个batch进行训练,每次训练时batch里面的数据都是不一样的(这也是为什么每个epoch都要将数据shuffle的原因),那在每一次做training update的时候,会得到不一样的梯度,损失函数在某个batch数据上关于参数 \(\theta\) (theta) 的梯度为0,这个时候在这个batch上不会更新梯度,但是,在另外一个batch上,损失函数关于参数 \(\theta\) 的梯度不一定为0,因为输入变了,损失函数也变了。
- 另外一种解释是,在大batch数据上训练容易造成过拟合,所谓过拟合意思是说,当我们使用大batch size做training和小batch size做training,并同时让它们在training data上达到一样的accuracy,此时在小batch size上训练得到的model在testing data上的accuracy要高于在大batch size上训练得到的model在testing data上的accuracy,也就是说小batch size上训练得到的model泛化性更好。这里李宏毅老师引用了一篇paper里的解释来说明是由于在大batch size上training的到的model更容易陷入”坏的“local minima,不容易跳出局部最优,因此它针对的是整个数据集上的梯度更新策略,如果模型陷入了”坏的“local minima,那么这个时候的损失函数只是适应了当前数据的梯度方向为0,而对于新的数据(比如testing data)也许在这个位置的梯度不一定为0,也就是说在testing data上损失还很大。假如我们现在采取的是小batch size做training的话,同样是陷入local minima,这个虽然也是局部最优,但是由于此时的损失函数是相对于很多个不同batch的数据在该点梯度方向都为0,也就是说有很强的泛化性,这就很有可能使得训练好的model在testing data也有较好的表现。
动量
所谓的动量就是在梯度更新的时候,人为的给与某个方向上的梯度,使得当损失函数到达局部最优的时候,有能力能跳出这个局部最优值。两个关键:动量的方向和大小。
每次朝着梯度的反方向更新梯度
- 普通梯度下降的更新规则:
- 加入Momentum技术后梯度更新规则
当前梯度的反方向 \(g\) 加上前一步参数更新的方向 \(m\) ,初始值为 0
也就是说参数更新的方向不只是取决于当前梯度的方向,还取决于过去的参数更新方向
自动调节学习率
假如模型训练至某一时刻,发现training loss不再下降,除了因为gradient很小,还有一种可能就是此时的学习率 \(\eta\) 已经很小了。
当学习率比较大的时候,梯度更新很离谱,几乎不会走到最优点,当梯度很小的时候,训练了很久都不能收敛到局部最优,因为在训练后期,学习率很小,这个时候梯度不起作用了。
普通的更新方式
改动学习率后的更新方式
不同的参数就有不同的学习率,相互之间是独立不影响的,同时不同的迭代周期对于同一个参数下也会有不同的学习率
下面介绍一些实现方式,主要是围绕着 \(\sigma\) ,\(\eta\) ,\(g\) 这三个变量进行改动。
第一种:对 \(\sigma\)(sigma) 的改进
- 当前时刻和过去时刻的梯度的平方和有关。Adagrad优化算法使用这种方式
- 当我们遇到一个比较平稳的局部最优区域时,此时该点附近的大部分区域梯度都很小,这个时候就可以给与一个较大的学习率
- 反之如果遇到的是一个比较陡峭的局部最优区域,此时该点附近的大部分区域梯度相对来说都比较大,这个时候就需要一个比较小的学习率,让参数更新慢一些。
- 但细心的同学也许会发现,Adagrad并没有对当前时刻的梯度和过去时刻的梯度给与不一样的权重考虑,因此Adagrad算法势必存在一些问题,下面我们来分析下。
- 自适应学习率(RMSProp)
- Adam = RMSProp + Momentum
先来总结一下Momentum和RMSProp这两个优化算法,Momentum的目的是防止陷入局部最优,当梯度更新陷入局部最优或者鞍点时,Momentum可以为梯度更新提供新的“动力”,而这个动力和最优点附近的梯度有关,也就是说Momentum是对梯度( \(g\) )本身的改进优化,RMSProp的目的则是自适应的调整学习率,使得模型能够快速并且稳定的到达最优点,RMSProp是对学习率系数( \(\sigma\) )的改进和优化,Adam则同时对 \(g\), \(\sigma\) 两个参数做改动,更新规则如下
如果能用二阶梯度,相当于梯度的梯度,那么也就知道坡度变化的趋势,因此一步就能走到位。
第二种:对 \(\eta\) (eta)的改进
- 学习率衰减
通常在我们的实际工程中就是给定一个学习率衰减系数,比如常见的指数型衰退法,式中的 \(\alpha\)为衰减系数, \(decay_{step}\) 代表了每多少步衰减一次。
- warm up
warm up的策略则是让学习率 \(\eta\)先增大,后减小,为什么warm up会有效果呢?李宏毅老师给出了一个可能的解释是:在模型刚开始训练的时候,每个数据点对模型来说都是新的,并没有学到任何东西,或者说并不知晓数据的分布情况,这个时候的 \(\sigma\) 统计是不精准的,模型这个时候如果给与比较大的学习率很容易学偏,并且在一开始的时候很难把错误的点拉回来,因此在模型一开始训练的时候让它慢慢学,等到学到一定的先验知识,对数据分布有了解之后,再加大学习率去学习,至于后面为什么要小下去,这个解释和前面的learning rate decay的思想一样。