机器学习模型在训练数据集和测试数据集上的表现。若是你改变过实验中的模型结构或者超参数,你也许发现了:当模型在训练数据集上更准确时,它在测试数据集上却不⼀定更准确。这是为何呢?git
由于存在着训练偏差和泛化偏差:github
训练偏差的指望小于或等于泛化偏差。也就是说,⼀般状况下,由训练数据集学到的模型参数会使模型在训练数据集上的表现优于或等于在测试数据集上的表现。因为⽆法从训练偏差估计泛化偏差,⼀味地下降训练偏差并不意味着泛化偏差⼀定会下降。面试
机器学习模型应关注下降泛化偏差。算法
在机器学习中,一般须要评估若⼲候选模型的表现并从中选择模型。这⼀过程称为模型选择(model selection)。可供选择的候选模型能够是有着不一样超参数的同类模型。以多层感知机为例,咱们能够选择隐藏层的个数,以及每一个隐藏层中隐藏单元个数和激活函数。为了获得有效的模型,咱们一般要在模型选择上下⼀番功夫。网络
从严格意义上讲,测试集只能在全部超参数和模型参数选定后使⽤⼀次。不可使⽤测试数据选择模型,如调参。因为⽆法从训练偏差估计泛化偏差,所以也不该只依赖训练数据选择模型。鉴于此,咱们能够预留⼀部分在训练数据集和测试数据集之外的数据来进⾏模型选择。这部分数据被称为验证数据集,简称验证集(validation set)。例如,咱们能够从给定的训练集中随机选取⼀小部分做为验证集,而将剩余部分做为真正的训练集。机器学习
能够经过预留这样的验证集来进行模型选择,判断验证集在模型中的表现能力。函数
因为验证数据集不参与模型训练,当训练数据不够⽤时,预留⼤量的验证数据显得太奢侈。⼀种改善的⽅法是K折交叉验证(K-fold cross-validation)。在K折交叉验证中,咱们把原始训练数据集分割成K个不重合的⼦数据集,而后咱们作K次模型训练和验证。每⼀次,咱们使⽤⼀个⼦数据集验证模型,并使⽤其余K − 1个⼦数据集来训练模型。在这K次训练和验证中,每次⽤来验证模型的⼦数据集都不一样。最后,咱们对这K次训练偏差和验证偏差分别求平均。性能
给定训练数据集,学习
应对⽋拟合和过拟合的⼀个办法是针对数据集选择合适复杂度的模型。测试
训练数据集⼤⼩
影响⽋拟合和过拟合的另⼀个重要因素是训练数据集的⼤小。⼀般来讲,若是训练数据集中样本数过少,特别是⽐模型参数数量(按元素计)更少时,过拟合更容易发⽣。此外,泛化偏差不会随训练数据集⾥样本数量增长而增⼤。所以,在计算资源容许的范围以内,咱们一般但愿训练数据集⼤⼀些,特别是在模型复杂度较⾼时,例如层数较多的深度学习模型。
正则化
应对过拟合问题的常⽤⽅法:权重衰减(weight decay),权重衰减等价于L2范数正则化(regularization)。正则化经过为模型损失函数添加惩罚项使学出的模型参数值较小,是应对过拟合的常⽤⼿段。
除了上面提到的权重衰减之外,深度学习模型经常使⽤丢弃法(dropout)来应对过拟合问题。丢弃法有⼀些不一样的变体。本节中提到的丢弃法特指倒置丢弃法(inverted dropout)。
回忆⼀下,“多层感知机”描述了⼀个单隐藏层的多层感知机。其中输⼊个数为4,隐藏单元个数为5,且隐藏单元hi(i = 1, . . . , 5)的计算表达式为:
这⾥ϕ是激活函数,x1, . . . , x4是输⼊,隐藏单元i的权重参数为w1i, . . . , w4i,误差参数为bi。当对该隐藏层使⽤丢弃法时,该层的隐藏单元将有⼀定几率被丢弃掉。设丢弃几率为p,那么有p的几率hi会被清零,有1 − p的几率hi会除以1 − p作拉伸。丢弃几率是丢弃法的超参数。具体来讲,设随机变量ξi为0和1的几率分别为p和1 − p。使⽤丢弃法时咱们计算新的隐藏单元 。
因为E(ξi) = 1 − p,所以:
**即丢弃法不改变其输⼊的指望值。**让咱们对隐藏层使⽤丢弃法,⼀种可能的结果以下图所⽰,其中h2和h5被清零。这时输出值的计算再也不依赖h2和h5,在反向传播时,与这两个隐藏单元相关的权重的梯度均为0。因为在训练中隐藏层神经元的丢弃是随机的,即h1, . . . , h5都有可能被清零,输出层的计算⽆法过分依赖h1, . . . , h5中的任⼀个,从而在训练模型时起到正则化的做⽤,并能够⽤来应对过拟合。在测试模型时,咱们为了拿到更加肯定性的结果,⼀般不使⽤丢弃法。
训练神经网络,尤为是深度神经所面临的一个问题就是梯度消失或梯度爆炸,也就是你训练神经网络的时候,导数或坡度有时会变得很是大,或者很是小,甚至于以指数方式变小,这加大了训练的难度。
本质上,梯度消失和爆炸是一种状况。在深层网络中,因为网络过深,若是初始获得的梯度太小,或者传播途中在某一层上太小,则在以后的层上获得的梯度会愈来愈小,即产生了梯度消失。梯度爆炸也是一样的。通常地,不合理的初始化以及激活函数,如sigmoid等,都会致使梯度过大或者太小,从而引发消失/爆炸。
解决方案
预训练加微调
其基本思想是每次训练一层隐节点,训练时将上一层隐节点的输出做为输入,而本层隐节点的输出做为下一层隐节点的输入,此过程就是逐层“预训练”(pre-training);在预训练完成后,再对整个网络进行“微调”(fine-tunning)。
此方法有必定的好处,可是目前应用的不是不少了。
梯度剪切、正则
梯度剪切这个方案主要是针对梯度爆炸提出的,其思想是设置一个梯度剪切阈值,而后更新梯度的时候,若是梯度超过这个阈值,那么就将其强制限制在这个范围以内。这能够防止梯度爆炸。
另一种解决梯度爆炸的手段是采用权重正则化(weithts regularization)比较常见的是L1和L2正则。
ReLu、leakReLu等激活函数
ReLu:其函数的导数在正数部分是恒等于1,这样在深层网络中,在激活函数部分就不存在致使梯度过大或者太小的问题,缓解了梯度消失或者爆炸。同时也方便计算。固然,其也存在存在一些缺点,例如过滤到了负数部分,致使部分信息的丢失,输出的数据分布不在以0为中心,改变了数据分布。
leakrelu:就是为了解决relu的0区间带来的影响,其数学表达为:leakrelu=max(k*x,0)其中k是leak系数,通常选择0.01或者0.02,或者经过学习而来。
Batch Normalization
Batch Normalization是深度学习发展以来提出的最重要的成果之一了,目前已经被普遍的应用到了各大网络中,具备加速网络收敛速度,提高训练稳定性的效果,Batch Normalization本质上是解决反向传播过程当中的梯度问题。Batch Normalization,简称BN,即批规范化,经过规范化操做将输出信号x规范化到均值为0,方差为1保证网络的稳定性。
残差结构
残差的方式,能使得深层的网络梯度经过跳级链接路径直接返回到浅层部分,使得网络不管多深都能将梯度进行有效的回传。
LSTM
LSTM全称是长短时间记忆网络(long-short term memory networks),是不那么容易发生梯度消失的,主要缘由在于LSTM内部复杂的“门”(gates)。在计算时,将过程当中的梯度进行了抵消。
你能够把训练集分割为小一点的子集训练,这些子集被取名为 mini-batch,假设每个子集中只有 1000 个样本,那么把其中的𝑥 (1)到𝑥 (1000)取出来,将其称为第一个子训练集,也叫作 mini-batch,而后你再取出接下来的 1000 个样本,从𝑥 (1001)到𝑥 (2000),而后再取 1000个样本,以此类推。
在训练集上运行 mini-batch 梯度降低法,你运行 for t=1……5000,由于咱们有5000个各有 1000 个样本的组,在 for 循环里你要作得基本就是对𝑋 {𝑡}和𝑌 {𝑡}执行一步梯度降低法。
其中1<n<m,m表示整个训练集大小。
优缺点:
首先,若是训练集较小,直接使用 batch 梯度降低法,这里的少是说小于 2000 个样本。通常的 mini-batch 大小为 64 到 512,考虑到电脑内存设置和使用的方式,若是 mini-batch 大小是 2 的𝑛次方,代码会运行地快一些。
在每次迭代中,梯度降低根据⾃变量当前位置,沿着当前位置的梯度更新⾃变量。然而,若是⾃变量的 迭代⽅向仅仅取决于⾃变量当前位置,这可能会带来⼀些问题。
让咱们考虑⼀个输⼊和输出分别为⼆维向量x = [x1, x2]⊤和标量的⽬标函数 。,这⾥将
系数从1减少到了0.1。下⾯实现基于这个⽬标函数的梯度降低,并演⽰使⽤学习率为0.4时⾃变量的迭代轨迹。
能够看到,同⼀位置上,⽬标函数在竖直⽅向(x2轴⽅向)⽐在⽔平⽅向(x1轴⽅向)的斜率的绝对值更⼤。**所以,给定学习率,梯度降低迭代⾃变量时会使⾃变量在竖直⽅向⽐在⽔平⽅向移动幅度更⼤。**那么,咱们须要⼀个较小的学习率从而避免⾃变量在竖直⽅向上越过⽬标函数最优解。然而,这会形成⾃变量在⽔平⽅向上朝最优解移动变慢。
**动量法的提出是为了解决梯度降低的上述问题。**因为小批量随机梯度降低⽐梯度降低更为⼴义,本章后续讨论将沿⽤“小批量随机梯度降低”⼀节中时间步t的小批量随机梯度gt的定义。设时间步t的⾃变量为xt,学习率为ηt。在时间步0,动量法建立速度变量v0,并将其元素初始化成0。在时间步t > 0,动量法对每次迭代的步骤作以下修改:
其中,动量超参数γ满⾜0 ≤ γ < 1。当γ = 0时,动量法等价于小批量随机梯度降低。在梯度降低时候使用动量法后的迭代轨迹:
能够看到使⽤较小的学习率η = 0.4和动量超参数γ = 0.5时,动量法在竖直⽅向上的移动更加平滑,且在⽔平⽅向上更快逼近最优解。
因此,在动量法中,⾃变量在各个⽅向上的移动幅度不只取决当前梯度,还取决于过去的各个梯度在各个⽅向上是否⼀致。在本节以前⽰例的优化问题中,全部梯度在⽔平⽅向上为正(向右),而在竖直⽅向上时正(向上)时负(向下)。这样,咱们就可使⽤较⼤的学习率,从而使⾃变量向最优解更快移动。
优化算法中,⽬标函数⾃变量的每⼀个元素在相同时间步都使⽤同⼀个学习率来⾃我迭代。在“动量法”⾥咱们看到当x1和x2的梯度值有较⼤差异时,须要选择⾜够小的学习率使得⾃变量在梯度值较⼤的维度上不发散。但这样会致使⾃变量在梯度值较小的维度上迭代过慢。动量法依赖指数加权移动平均使得⾃变量的更新⽅向更加⼀致,从而下降发散的可能。本节咱们介绍AdaGrad算法,它根据⾃变量在每一个维度的梯度值的⼤小来调整各个维度上的学习率,从而避免统⼀的学习率难以适应全部维度的问题。
AdaGrad算法会使⽤⼀个小批量随机梯度gt按元素平⽅的累加变量st。在时间步0,AdaGrad将s0中每一个元素初始化为0。在时间步t,⾸先将小批量随机梯度gt按元素平⽅后累加到变量st:
其中⊙是按元素相乘。接着,咱们将⽬标函数⾃变量中每一个元素的学习率经过按元素运算从新调整⼀下:
其中η是学习率,ϵ是为了维持数值稳定性而添加的常数,如10的-6次方。这⾥开⽅、除法和乘法的运算都是按元素运算的。这些按元素运算使得⽬标函数⾃变量中每一个元素都分别拥有⾃⼰的学习率。
须要强调的是,小批量随机梯度按元素平⽅的累加变量st出如今学习率的分⺟项中。所以,
然而,因为st⼀直在累加按元素平⽅的梯度,⾃变量中每一个元素的学习率在迭代过程当中⼀直在下降(或不变)。因此,当学习率在迭代早期降得较快且当前解依然不佳时,AdaGrad算法在迭代后期因为学习率太小,可能较难找到⼀个有⽤的解。
当学习率在迭代早期降得较快且当前解依然不佳时,AdaGrad算法在迭代后期因为学习率太小,可能较难找到⼀个有⽤的解。为了解决这⼀问题,RMSProp算法对AdaGrad算法作了⼀点小小的修改。
不一样于AdaGrad算法⾥状态变量st是截⾄时间步t全部小批量随机梯度gt按元素平⽅和,RMSProp算法将这些梯度按元素平⽅作指数加权移动平均。具体来讲,给定超参数0 ≤ γ < 1,RMSProp算法在时间步t > 0计算:
和AdaGrad算法⼀样,RMSProp算法将⽬标函数⾃变量中每一个元素的学习率经过按元素运算从新调整,而后更新⾃变量:
其中η是学习率,ϵ是为了维持数值稳定性而添加的常数,如10的-6次方。由于RMSProp算法的状态变量st是对平⽅项gt ⊙ gt的指数加权移动平均,因此能够看做是最近1/(1 − γ)个时间步的小批量随机梯度平⽅项的加权平均。如此⼀来,⾃变量每一个元素的学习率在迭代过程当中就再也不⼀直下降(或不变)。
除了RMSProp算法之外,另⼀个常⽤优化算法AdaDelta算法也针对AdaGrad算法在迭代后期可能较难找到有⽤解的问题作了改进。有意思的是,AdaDelta算法没有学习率这⼀超参数。
AdaDelta算法也像RMSProp算法⼀样,使⽤了小批量随机梯度gt按元素平⽅的指数加权移动平均变量st。在时间步0,它的全部元素被初始化为0。给定超参数0 ≤ ρ < 1(对应RMSProp算法中的γ),在时间步t > 0,同RMSProp算法⼀样计算:
与RMSProp算法不一样的是,AdaDelta算法还维护⼀个额外的状态变量∆xt,其元素一样在时间步0时被初始化为0。咱们使⽤∆xt−1来计算⾃变量的变化量:
最后,咱们使⽤∆xt来记录⾃变量变化量 按元素平⽅的指数加权移动平均:
能够看到,如不考虑ϵ的影响,AdaDelta算法与RMSProp算法的不一样之处在于使⽤ 来替代超参数η。
Adam算法在RMSProp算法基础上对小批量随机梯度也作了指数加权移动平均。
Adam算法使⽤了动量变量vt和RMSProp算法中小批量随机梯度按元素平⽅的指数加权移动平均变量st,并在时间步0将它们中每一个元素初始化为0。给定超参数0 ≤ β1 < 1(算法做者建议设为0.9),时间步t的动量变量vt即小批量随机梯度gt的指数加权移动平均:
和RMSProp算法中⼀样,给定超参数0 ≤ β2 < 1(算法做者建议设为0.999),将小批量随机梯度按元素平⽅后的项gt ⊙ gt作指数加权移动平均获得st:
因为咱们将 v0 和 s0 中的元素都初始化为 0,在时间步 t 咱们获得 。将过去各时间步小批量随机梯度的权值相加,获得
。须要注意的是,当 t 较小时,过去各时间步小批量随机梯度权值之和会较小。例如,当β1 = 0.9时,v1 = 0.1g1。为了消除这样的影响,对于任意时间步 t,咱们能够将 vt 再除以
,从而使过去各时间步小批量随机梯度权值之和为1。这也叫做误差修正。在Adam算法中,咱们对变量 vt 和 st 均做误差修正:
接下来,Adam算法使⽤以上误差修正后的变量***v*ˆt和***s*ˆt,将模型参数中每一个元素的学习率经过按元素运算从新调整:
其中η是学习率,ϵ是为了维持数值稳定性而添加的常数,如10的-8次方。和AdaGrad算法、RMSProp算法以及AdaDelta算法⼀样,⽬标函数⾃变量中每一个元素都分别拥有⾃⼰的学习率。最后,使⽤ 迭代⾃变量:
一个具备高维度空间的函数,若是梯度为 0,那么在每一个方向,它多是凸函数,也多是凹函数。若是你在 2 万维空间中,那么想要获得局部最优,全部的 2 万个方向都须要是这样,但发生的机率也许很小,也许是2的-20000次方,你更有可能遇到有些方向的曲线会这样向上弯曲,另外一些方向曲线向下弯,而不是全部的都向上弯曲,所以在高维度空间,你更可能碰到鞍点。
而不会碰到局部最优。**至于为何会把一个曲面叫作鞍点,**你想象一下,就像是放在马背上的马鞍同样,若是这是马,这是马的头,这就是马的眼睛,画得很差请多包涵,而后你就是骑马的人,要坐在马鞍上,所以这里的这个点,导数为 0 的点,这个点叫作鞍点。我想那确实是你坐在马鞍上的那个点,而这里导数为 0。
鞍点中的平稳段是一个问题,这样使得学习十分缓慢,**这也是像 Momentum 或是RMSprop,Adam 这样的算法,可以加速学习算法的地方。**在这些状况下,更成熟的优化算法,如 Adam 算法,可以加快速度,让你尽早往下走出平稳段。
**数据角度 **
加强数据集。不管是有监督仍是无监督学习,数据永远是最重要的驱动力。更多的类型数据对良好的模型能带来更好的稳定性和对未知数据的可预见性。对模型来讲,“看到过的总比没看到的更具备判别的信心”。
模型角度
模型的容限能力决定着模型可优化的空间。在数据量充足的前提下,对同类型的模型,增大模型规模来提高容限无疑是最直接和有效的手段。
调参优化角度
若是你知道模型的性能为何再也不提升了,那已经向提高性能跨出了一大步。 超参数调整自己是一个比较大的问题。通常能够包含模型初始化的配置,优化算法的选取、学习率的策略以及如何配置正则和损失函数等等。
训练角度
在越大规模的数据集或者模型上,诚然一个好的优化算法总能加速收敛。但你在未探索到模型的上限以前,永远不知道训练多久算训练完成。因此在改善模型上充分训练永远是最必要的过程。充分训练的含义不只仅只是增大训练轮数。有效的学习率衰减和正则一样是充分训练中很是必要的手段。
做者:@mantchs
GitHub:github.com/NLP-LOVE/ML…