小伙伴关心的问题:联想小新13iml2020(VL2020),本文通过数据整理汇集了联想小新13iml2020(VL2020)相关信息,下面一起看看。

联想小新13iml2020(VL2020)

Hung-yi Lee (李宏毅) MACHINE LEARNING 2021 SPRING课程 Week2笔记

ML 2021 Spring​speech.ee.ntu.edu.tw/~hylee/ml/2021-spring.html

全文内容目录:

Model Bias问题Optimization问题如何区分是Model Bias还是Optimization导致的Train Loss过大?训练时能够避免上述情况发生的一些Tips?Overfitting问题如何解决Overfitting问题?如何避免在Training Data上表现很好但是Testing Data上表现很差的问题—Cross Validation交叉验证技术?Optimization问题产生的原因: Small GradientOptimize训练Tips: Batch and Momentum:Optimize训练Tips: Automatic Learning Rate综合各种训练技巧的优化器:Adam改变Loss函数,也有可能影响训练:Feature Normalization: Batch Normalization 技术

本篇将会介绍一些机器学习深度学习训练过程中,容易发生的一些问题,以及经常使用的一些基础的Tricks。上篇已经阐明了机器学习任务的训练分为以下三个阶段。

同时也会有对应的测试集数据进行验证的部分。

那么在训练与测试的过程中,可能会出现一些问题,下面的图就是一个整体的Guidance,基本阐述了当在训练时我们遇到不同的现象时,大概是何种问题所致。

此篇将会顺着这个分支树进行前序遍历,一条条往下进行讲解。

一、Model Bias问题

当在训练数据上得到的Loss函数值较大的话,其中一种可能就是Model Bias.Model Bias一般指模型不够复杂,无法很好的拟合数据。从形式化的角度来讲就是,能够拟合数据的函数,不在你所寻找的函数空间中。举个例子来说:你在第一步中设定的拟合函数为Y = a + bx,然后使用梯度下降想要寻找使得Loss最低的一组a和b,但是你会发现,即使你找到了使得Loss最低的一组a和b,这组a和b计算得到的Loss还是很高。原因可能是,你需要拟合的数据其实是一个二次函数,或是更复杂的函数,而你却想要使用线性函数去进行拟合。

二、Optimization问题

当在训练数据上得到的Loss函数值较大的话,另外一种可能就是Optimization导致的。此种情况与第一种不同,其模型是有能力拟合数据的,但是由于优化方法的限制,我们没法找到能够使得Loss函数值最小的那一组未知参数。我们先前使用的Gradient Descent用于求解优化的方法,还是存在比较多的限制的。如下图为例,假设Loss函数的图像如下图所示,我们设定的θ的起点在左侧,那么经过一段时间的梯度下降后,其会到达图中蓝线所示的Local Minimum,也就是局部最优,但是其永远也无法找到右侧的全局最优。往往优化算法无法很好的执行是由于模型过于复杂,或不同的特征数据的尺度相差过大等原因导致。

此处仅先简单的介绍Optimization是怎样一种问题,后续第八章中会继续探讨这类问题的产生原因以及在第九章中讲如何解决优化这一问题(如何逃出Shaddle Point)。

三、如何区分是Model Bias还是Optimization导致的Train Loss过大?

我们先前说,当在训练数据上得到的Loss函数值较大的话,这两种问题都有可能,那么一般而言如何区分呢?一般来说,我们需要通过模型与模型的比较来获得一些见解。如下所示,在右侧的Training Data显示的图像中,20层的网络已经能够将Training Error降至比较低的水准了,那么56层的这个网络Training Error还处于一个较高的水准,那么肯定是Optimizaiton问题,而不是Model Bias的问题。为何这么说呢?因为56层的网络肯定比20层的网路复杂,如果20层的网络已经能够很好的拟合训练数据了,那么56层的网络肯定是具有拟合训练数据的能力的,但是现在Training Error还居高不下,说明是优化的时候出现了问题,或者是进入了一个局部最优点中,导致其找不到最好的那一组参数。

四、训练时能够避免上述情况发生的一些Tips?

一般新执行一个训练任务的时候,从较浅的网络开始训练,因为一般较浅的网络不会出现优化的问题。如果发现较浅的网络复杂度不够拟合数据,再逐渐加深网络。

如果更深的网络没有获得更小的损失训练数据,则存在优化问题。

五、Overfitting问题

当Training Loss已经降至较低水平,但是在Testing集上的Loss值仍然较高,其中一种可能就是出现了Overfitting过拟合的问题。如下图所示,很好的表现了过拟合问题。由于我们的模型非常有弹性,所以可能在训练集上(蓝色点)时非常好的拟合了,但是在测试集(橙色)上的表现就会比较差。

更为极端的情况就是训练出如下图所示的函数:在训练集上的数据,都是完全拟合的,但是对于不在训练集上的数据就是一个随机值。

六、如何解决Overfitting问题?

下述是一个随着模型逐渐变得复杂,Training Loss和Testing Loss 的值变化曲线。

对于Overfitting我们有如下的几种解决方案:

更多的训练数据

如果我们能够收集到更多的训练数据,就可以一定程度上减轻过拟合的问题。比较常用的增加训练数据的方法,叫做Data Augmentation. 如下图所示,比如说在一个图像检测的任务中,我们最开始数据集里的图片只有最左侧一张图片,我们可以将其左右翻转、或者进行放缩,就能够形成新的一些训练数据,来扩充我们的数据集。然而,上下翻转形成的新的图像,一般不会被我们放入数据集中,因为它并不是正常形成的图片,如果加入数据集中很可能让机器学到奇怪的内容。因此,Augmentation也不是随意的对数据进行变换,是需要有一定依据的。

2. 减少未知参数或共享部分参数:

减少模型的复杂度,或者使得模型中某些层共享一些参数,能够一定程度上解决Overfitting的问题。

3. 使用更少的特征

将一些对于结果影响较为不显著的特征进行丢弃,只保留一些关键重要的特征,也可以一定程度上解决Overfitting。例如:我们要训练一个模型预测车的价格,根据车的如下特征:车大小、车颜色、车品牌、车动力等。其实,在这么多特征中,车颜色应该是对价格影响较少的,所以我们在训练时可以将这个特征舍去,不参与训练。

4. Early Stopping机制(在Week1的Hw中已经提及)

5. Regularization正则化技术(见后)

6. DropOut技术(见后)

七、如何避免在Training Data上表现很好但是Testing Data上表现很差的问题——Cross Validation交叉验证技术?

我们将Training Set分割为Training Set和Validation Set两个 *** ,一般而言比例为9:1。我们使用划分后的Training Set进行训练,在每个Epoch结束后使用训练期间机器没有见到过的Validation进行验证,依据验证集得到的Loss值来进行模型好坏的衡量。

那么该如何进行划分呢?一般来说随即划分即可。但随即划分也可能带来一些问题,比如说可能训练集中的数据都偏向于某一类,而验证集的数据偏向于另一类,就可能导致Validation出现问题.故而又出现了N-Fold Cross Validation.如下图所示,我们将Training Set分为N个 *** (示例中为3个),其中N-1个 *** 用于训练,1个 *** 用于验证,然后每轮Epoch中,都执行N遍,每一遍都拿不同的 *** 用于训练与验证,然后计算一遍Loss值,最终选取平均Loss最小的那一组参数进行模型的更新.

八、Optimization问题产生的原因: Small Gradient

我们先来看一下优化无法进行的根本原因是什么?无论是训练了一段时间以后Loss无法再下降,还是一开始Loss就无法下降,其终极原因就是达到了梯度接近于0的点,我们通常称为critical point。注意,此处千万不能说是碰到了local minimum,因为这样子会非常不严谨。Critical point 不仅仅指Local Minimum,还有可能是 Saddle Point(鞍点)等情况。

所以我们首先要知道,当我们遇到一个Critical Point的时候,需要区分这到底是一个Local Minimum还是一个Saddle Point。因为如果是一个局部最小值,那么其实就已经无路可走了,但是如果是一个Saddle Point的话,周边仍然是有比他低的值的。还是有办法可以解决一番.

L(θ)函数本身会是一个非常复杂的函数,我们没法知道它的全貌,但是我们可以动用如下的数学手段来判断某一个Critical Point到底是Local Minimum还是Saddle Point,如下所示:

利用泰勒展开,我们可以知道L(θ)在某一个点θ’周围的函数的近似值: g为梯度,是L对θ的一阶导数组成的向量.H为海森矩阵,为L对θ的二阶微分组成的矩阵.

我们知道,在Critical Point上,梯度为0,所以我们可以将上述公式中中间那一项划掉不看,那么L(θ)在θ’周围的函数值就可以近似为L(θ’) 加上后面这一项.

因此,我们其实可以通过后面红色方框内的这一项的正负,来判断θ’周围的值的分布到底是如下图所示的三种中的哪一种:

为了后续的数学表示,我们先将(θ-θ)表示为符号v,那么如下图所示: 上述近似式子中的红色方框的那项,值有如下三种情况:

如果对于所有的v来说,该项恒大于0,那就代表在θ周围,所有的值都比该点大,该点即为局部最小值.但是问题在于我们没法验证所有的v,那应该如何呢?

已经有人为我们证明了, 对于所有v,vTHv 恒大于0这件事情,和 海森矩阵H是一个正定矩阵 是等价的, 也等价于 H矩阵的所有特征值都是正的这件事情.

所以理论上我们如果想要知道vTHv 的情况,知道θ周围的分布,那么其实只要计算出H矩阵的所有特征值,看一下分布即可.

那么如果我们发现这个点是一个Saddle Point的话, 应当如何去继续优化呢? 我们可以利用H进行优化, 我们找到一个矩阵H的特征向量u, 其对应的特征值为λ,λ<0 ,那么如下图所示: uTHu 这一项就应当为 < 0 的值.

故而: 我们令θ-θ’ = u, 即可得到一个比L(θ’)小的值,完成了L值的优化.

从执行上来讲,其实就是找一个H矩阵的特征值为负的特征向量u,这个向量u就指明了梯度下降的方向,沿着该方向走一小步,就可以完成Loss函数的值的优化.

到此为止,已经记录了Saddle Point和Local Minimum怎么去区分, 并且也发现Saddle Point并不可怕,可以通过计算H矩阵来进行求解.

在实际我们的训练过程中,其实达到Local Minimum的机会是很少的,基本上都会停留在Saddle Point上,那么这是不是就意味着我们如果碰到了Critical Point也就是梯度为0的点,基本上就可以用求解H来继续训练呢? 理论上应该是可以的,但是在实际操作中,其实我们并不会去这样子做,因为计算H矩阵所需要花费的时间代价太过昂贵了.我们会有其他的训练技巧,来帮助绕过这一些Saddle Point. 这些内容在下面的第9章中会讲述。同时最后的话还需要提及一点,其实大部分的训练优化做不下去了,并不是由于到达了Critical Point,而是由于学习率的原因,在一个山谷的两侧来回震荡,这一点会在10章中进行详细的叙述。

九、Optimize训练Tips: Batch and Momentum:

1、Batch技术:

先前我们说过在训练的过程中,每次进行梯度下降并不是参考所有的训练数据来计算Loss函数的,而是会像下图一样通过一个Batch一个Batch的进行计算。我们在每一轮Epoch之前,一般而言都会对数据集重新划分Batch,也就是说在不同的Epoch中,每一个Batch都是不一样的,这件事情叫做Shuffle。

接下去的问题就是我们为什么要使用Batch呢?考虑如下的一个例子,左侧的Full batch就是每一次机器都要看过所有的数据集以后再更新参数,而右侧的Batch Size = 1则是会在看过每个样例以后都更新一遍参数。从直观上来看,BatchSize越大,其就更新一次参数而言所需要花费的时间越大,但是其更新更有效。那么按照这样子说的话,我们为什么还要分Batch呢?实际状况跟我们的直觉有一些不同。

下面这张图显示了单次update以及一轮epoch训练的时间和BatchSize的关系,我们发现单次update的时间,对于batchsize = 1和=1000来说,竟然差别不大。导致这个的原因是我们考虑了并行计算的因素,也就是使用GPU进行运算的原因。当然,如果BatchSize再增长下去,我们的GPU也是有一定的上限的所以后面也会有较大的一个时间增长。那么,右侧的这幅图就比较好理解了,对于一轮Epoch来说,如果我们的Batch Size比较小的话,在一轮Epoch中,更新Update次数就会比较多,相对而言整体的一轮Epoch的耗时就会较长。所以随着Batch Size的增大,反而一轮Epoch的时间会变长。

这样看来,BatchSize越大,反而训练速度越快。这样的话BatchSize越大,速度又快,更新又准确,那为什么还要分Batch呢?下面一张图表示了BatchSize大小对训练出的网络的准确率的影响,我们可以看到,在BatchSize较大的时候,准确率直线下降,这是为什么呢?原因在于:我们先前所说BatchSize较大的话,每次Update较为准确,没有问题。但是对于网络而言,并不是一次Update就能解决问题的。

如果BatchSize过大,会导致优化问题的出现,如左图所示,原因就是因为其每次update都太准确,如果遇到 critical point或者是local minimum,那么其就会深陷其中,无法继续优化了。如过分了Batch的话,由于每次使用的是不同的Batch,所以每次的L函数都会有些许不一样,如果在L1处到达了一个critical point,在一个Batch训练的时候,也许该点又重新可以继续梯度下降训练了。所以,Batch Size较小的时候带来的单次更新的”Noisy”反而对整体的网络训练能够带来好处。那么,如何衡量就是一个需要我们手工调整的问题了。

最后,先辈们还发现了一个有趣的现象,就是如果我们使用BatchSize不一样的训练方法,训练同一个网络,将Training Loss训练到一样好以后,我们将其在测试集上进行测试,往往是BatchSize小的训练出来的网络,准确率较高。大致原因如下图所示:large batch容易让网络的参数进入一些Sharp Minima峡谷中,这样子的话,一旦训练数据集和测试数据集的分布有些许不同,在训练集上处于很低点的参数应用到测试集上可能会有一个比较大的Loss。相比较而言, *** all batch往往会跳出这种sharp minima的峡谷,找到一些较为平坦的flat minima,对于这些flat minima的参数来说,即使训练集与分布集的数据分布不同,表现出来的loss性能也不会相差太多。有兴趣的可以研读这篇paper.《On Large-Batch Training for Deep Learning: Generalization Gap and Sharp Minima 》

2、Momentum技术:

除了使用Batch来帮助我们训练以外,还有一种借鉴了物理世界的Momentum技术,可以帮助我们走出一些Critical point。

如下图所示,在梯度下降中,也许我们训练至一些critical point,参数就不会继续优化了,但是在物理世界中,如果一个小球从高处滚下,其将会靠着动量滚下saddle point,也有可能靠着动量滚出local minimum。

如下图所示是我们普通梯度下降的算法示意图:从θ0开始计算梯度,然后沿着梯度反方向移动下降,一步步进行优化。

那么在Gradient Descent + Momentum的算法如下:最开始第一步和原来的一样,从θ0开始计算梯度,然后沿着梯度反方向移动下降,达到θ1时,此时和原先就会发生不同了,其现在的移动会结合前一步的movement(即m1)以及当前点的梯度(g1),计算出一个新的下降方向m2,然后进行更新。如图所示:m2 是由 m1 和 -g1 两个向量相加所得到的。从公式上来讲就是 λm1 - ηg1,两者都有自己的参数,来控制影响整个梯度下降方向的比例。

其实从另一个角度来看,mi其实是先前所有的梯度的和,也就是g0 - gi-1的和。所以我们可以说Momentum是考虑了上一步的movement,也可以说Momentum是考虑了先前所有更新点的梯度值。

十、Optimize训练Tips: Automatic Learning Rate

其实,当我们训练卡住的时候,并不一定是碰到了梯度较低的地方,很有可能是在某个山谷的两侧由于学习率过大的问题来回震荡。那么这种现象是怎么产生的呢?

在Week1的HW1笔记中,曾经记录数据预处理归一化的重要性,否则很有可能因为不同特征的数据尺度相差太大导致震荡,从而导致训练不出结果,如下图所示:

下图是一个Error Surface,就是Loss函数的平面,我们使用两种不同大小的学习率去进行梯度下降,黄色的叉叉代表训练终点。我们发现整个Error Surface中,上下维度的梯度比较陡,左右维度的梯度比较缓。如果我们采用较大的学习率,就会产生左图这样子的黑色训练线,在竖直方向疯狂震荡。但是如果我们使用如右图所示的较小的学习率,一开始是可以沿着竖直方向的梯度慢慢更新,但是当要开始沿水平方向更新的时候,会发现学习率太小了,以至于更新了10w次,还距离我们的训练重点遥遥无期。

所以,我们发现,一个固定的学习率在训练中是不太合适的,最好的话是如图所示,要对不同的参数有不同的学习率,学习率要随着梯度的变化以及参数的变化而进行变化。

于是我们首先提出了如下想法,将原来的学习率η修改成 η/(σit), 这个σit既跟参数相关又跟训练步骤(不同点所在的梯度)相关。

以下就是一种最为简单的σ的计算方式,通过计算每次更新得到的参数空间所在点的梯度的Norm值的平方的平均,即RMS来计算每步中σ。

这种方法被用在Adagrad中,主要思想就是,如果Loss函数在某个方向上比较平坦,梯度比较小,那么我们希望Learning Rate比较大,快速的走过这一片平坦的区域。如果在某个方向上比较陡峭,我们希望Learning Rate比较小.

接下来一种较为进阶的做法叫做RMSProp,它在计算每一步的σ的时候,结合了上一步的σ以及该步的梯度g,同时还有一个超参数α,可以进行调整。如果我们调整α比较大的话,代表其参考当前的梯度较多,也就是说如果梯度突然产生较大变化,其就能快速的反应过来,对LearningRate进行快速的调整。相较于前RMS所有先前的梯度都平均权值考虑的做法,这一做法能够更快速的对梯度的变化进行响应。

如下所示,是一个较为公式化的写法,以及一个简单的示意图。

其实按照这种方法,进行训练的话,可能出现如下图所示的训练曲线:为何训练时过一段时间就会突然上下暴走呢?因为其σ是累积平均得到的,在先前的一段时间里,上下方向的更新梯度都近乎为0,累积一段时间以后,上下的梯度就会很小,然后学习率就会变得很大,但是马上又会因为我们的机制更新学习率回来,从而只会出现这样的震荡一下的现象,而不是一直的上下乱窜。

在自动修改学习率的方法中,还有一种形式叫做Learning Rate Sche *** ng:它在原先的基础上对η也进行了一些调整。

较为常见的就是Learning Rate Decay这种,随着优化的更新深入,我们使得η逐渐变小。这种想法也是比较能够理解的。类似于越往后快要到达终点了,我们就越要慢慢的靠近,精细的调整,而一开始可以以较大的速率进行更新。

也有一些网络会用到类似下面的Warming Up的黑科技:

十一、综合各种训练技巧的优化器:Adam

Adam是一种综合了RMSProp和Momentum技术的优化器,其大致算法如下图所示,在此处就不多赘述。原论文网址:

十二、改变Loss函数,也有可能影响训练:

此部分通过描述分类任务,来顺带阐明改变Loss函数的形式,也有可能影响训练这样一件事情。下图是回归与分类的任务一些差别,在分类任务中,最终的结果往往是一个类别,而不是一个数值,同时,类别往往会由One-hot向量进行表示。所以,我们分类任务所输出的内容往往是一个多个数值的向量y。然后我们需要比较y和 真实类别的标签直接的差别,尽可能的最小化这个差别即可。那么,由于标签往往都是One-hot 向量,所以我们为了比较y和标签的值,往往都会先对y做一个softmax函数进行处理,将y中的所有值归约化至0-1之间,并且所有值的和为1.

Soft-Max内部对输入进行的处理如下图所示,我们假设输入y1,y2,y3,我们先将三个输入计算exp(y1),exp(y2),exp(y3),然后求和,然后计算输出。

那么在得到归一化后的y’之后,我们如何去计算y’和label y 的差距呢?按照先前回归的想法是计算两个向量之间的MSE,也就是如下图所示:

但其实一般而言,我们在分类任务中,都会采用Cross-Entropy作为Loss函数,即如下所示的公式:

一个简单的解释是,最小化Cross-Entropy和最大化似然概率是完全等同的一件事情(至于为什么完全等同,可以找相关资料),分类任务就是要找出计算得到的y属于哪一类的概率最大,所以我们往往采用Cross-Entropy作为Loss函数。而计算Cross-Entropy之前,我们往往就是要对网络的输出进行SoftMax函数的处理。所以往往SoftMax会和Cross-Entropy绑定在一起,有趣的是Pytorch的底部实现中,如果你的Loss函数使用了Cross-Entropy,那么你在网络结构中是不需要实现SoftMax层的,因为它会自动将SoftMax层加到你的网络的最上面。

如下所示是一个比较直观的结果:当我们采用不同的Loss函数的时候,Error Map也会截然不同。左侧采用MSE的Error map在左上角的区域上(也就是Large Loss)的区域上,梯度就很平坦,就很难训练,而采用Cross-Entropy则会好训练很多。这也就是为什么说有的时候改变Loss函数,也可以改变训练的难度。

十三、Feature Normalization: Batch Normalization 技术

我们先前提及过,当训练数据不同维度的特征的尺度相差较大时,训练难度会较大,那么Feature Normalization就是为了使得不同特征的尺度类似,从而使得Error Surface较为平滑。如下图所示:左侧的Loss函数平面,不同特征的梯度变化不同,有Smooth和Steep两类不同的内容。右侧就是做了一个Feature Normalization以后的Error Surface,各个维度都较为平滑。

那么最为平常的特征归一化,如下所示:比如说给出一组x向量,我们计算向量中每个维度的平均值与方差,然后通过如下公式进行计算,我们就可以将所有维度的数据归约化至一个mean为0,deviation为1的一个分布中,使得大致的数据尺度差不多。

上述的归约化处理在HW1的代码中也已经有所体现,那么先前我们在说的是数据预处理步骤中,对于所有数据的归约化。那么对于深度学习来说,可能存在如下问题:

如下图所示,输入的特征经过归一化以后,在第一层的训练参数是比较正常的,但是经过第一层的参数以后,输出的不同维度的数据又可能回到了不同尺度这样一种状态。这样的话,对于第二层的网络来讲,参数优化又会变得较为困难。

所以我们需要在层与层之间也进行归一化的操作,如下示例来讲,就是通过z1,z2,z3计算出u和σ。

然后我们再将z1,z2,z3根据公式来进行归一化的操作,得到归约化后的z1,z2,z3。这边的话其实有一个有趣的内容:原本来说,如果参数更新了,z1更新了,那么只会影响a1的改变,但是现在而言,加入了BN以后,z1更新了以后,会影响到u和σ,从而会再影响归约化后的z1,z2,z3,随后a2,a3也会受到影响。所以,当我们加入归约化的时候,就需要将整个考虑成一个大的网络。所以就把BN做成一个Batch Normalization层。

并且,我们在训练过程中,由于输入数据往往是一个Batch一个Batch输入的,所以训练时计算的u和σ我们往往不会去计算所有的训练数据,而是计算该Batch内部的所有数据的u(向量)和σ(向量)。故而,这个技术叫Batch Normalization。

所以,Batch Normalization往往需要在Batch比较大的时候才会可以使用,会比较好一些。不然的话计算得到的u和σ并不能代表训练数据的一些分布,归约化就会出现一些问题。同时,再归约化时也会有一些小的问题如下:

因为我们归约化至了mean = 0, deviation=1的数据分布,会不会影响后续机器学习的性能,所以我们再归约化后又加入了γ和β两个参数,在训练开始时,γ 一般为1,β一般为0,帮助其更好的拟合后续的特征,同时又能较大程度的保持各个维度的数据在统一尺度下。

那么先前所讲的是在训练过程中的BatchNoramlization,那么如果在Testing的过程中,

每次输入一个数据,没有凑齐一个Batch的情况下,BatchNormalization又应当如何执行呢?此时,我们的u和σ就不来源于测试的Batch了,而是来源于训练时候每一个Batches计算得到的u的均值依据一些权重累加得到。

总而言之,Batch Normalization能让你的error surface 更加平滑,从而降低训练的难度,让网络拥有更好的性能,这样的解释无论是理论还是实验都已经被人所证实。具体可以参见这篇论文《How Does Batch Normalization Help Optimization?》。

更多联想小新13iml2020(VL2020)相关信息请关注本站,本文仅仅做为展示!