本篇文章主要介绍梯度下降优化方法、损失函数及过拟合处理方法等问题:

梯度下降优化算法综述

   该文翻译自An overview of gradient descent optimization algorithms。

   总所周知,梯度下降算法是机器学习中使用非常广泛的优化算法,也是众多机器学习算法中最常用的优化方法。几乎当前每一个先进的(state-of-the-art)机器学习库或者深度学习库都会包括梯度下降算法的不同变种实现。但是,它们就像一个黑盒优化器,很难得到它们优缺点的实际解释。 
   这篇文章旨在提供梯度下降算法中的不同变种的介绍,帮助使用者根据具体需要进行使用。 
   这篇文章首先介绍梯度下降算法的三种框架,然后介绍它们所存在的问题与挑战,接着介绍一些如何进行改进来解决这些问题,随后,介绍如何在并行环境中或者分布式环境中使用梯度下降算法。最后,指出一些有利于梯度下降的策略。 
   梯度下降算法是通过沿着目标函数J(θ)参数θR的梯度(一阶导数)相反方向θJ(θ)来不断更新模型参数来到达目标函数的极小值点(收敛),更新步长为η。详细的介绍参见:梯度下降。

三种梯度下降优化框架

   有三种梯度下降算法框架,它们不同之处在于每次学习(更新模型参数)使用的样本个数,每次更新使用不同的样本会导致每次学习的准确性和学习时间不同。

  • 全量梯度下降(Batch gradient descent) 
       每次使用全量的训练集样本来更新模型参数,即:

    θ=θηθJ(θ)

   其代码如下:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(epochs):params_grad = evaluate_gradient(loss_function,data,params)params = params - learning_rate * params_grad</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

   epochs 是用户输入的最大迭代次数。通过上诉代码可以看出,每次使用全部训练集样本计算损失函数loss_function的梯度params_grad,然后使用学习速率learning_rate朝着梯度相反方向去更新模型的每个参数params。一般各现有的一些机器学习库都提供了梯度计算api。如果想自己亲手写代码计算,那么需要在程序调试过程中验证梯度计算是否正确,具体验证方法可以参见:这里。 
   全量梯度下降每次学习都使用整个训练集,因此其优点在于每次更新都会朝着正确的方向进行,最后能够保证收敛于极值点(凸函数收敛于全局极值点,非凸函数可能会收敛于局部极值点),但是其缺点在于每次学习时间过长,并且如果训练集很大以至于需要消耗大量的内存,并且全量梯度下降不能进行在线模型参数更新。

  • 随机梯度下降(Stochastic gradient descent)

   随机梯度下降算法每次从训练集中随机选择一个样本来进行学习,即:

θ=θηθJ(θ;xi;yi)



   批量梯度下降算法每次都会使用全部训练样本,因此这些计算是冗余的,因为每次都使用完全相同的样本集。而随机梯度下降算法每次只随机选择一个样本来更新模型参数,因此每次的学习是非常快速的,并且可以进行在线更新。

   其代码如下:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(epochs):np.random.shuffle(data)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> example <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> data:params_grad = evaluate_gradient(loss_function,example,params)params = params - learning_rate * params_grad</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

   随机梯度下降最大的缺点在于每次更新可能并不会按照正确的方向进行,因此可以带来优化波动(扰动),如下图:

 
图1 SGD扰动来源

   不过从另一个方面来看,随机梯度下降所带来的波动有个好处就是,对于类似盆地区域(即很多局部极小值点)那么这个波动的特点可能会使得优化的方向从当前的局部极小值点跳到另一个更好的局部极小值点,这样便可能对于非凸函数,最终收敛于一个较好的局部极值点,甚至全局极值点。 
   由于波动,因此会使得迭代次数(学习次数)增多,即收敛速度变慢。不过最终其会和全量梯度下降算法一样,具有相同的收敛性,即凸函数收敛于全局极值点,非凸损失函数收敛于局部极值点。

  • 小批量梯度下降(Mini-batch gradient descent)

   Mini-batch梯度下降综合了batch梯度下降与stochastic梯度下降,在每次更新速度与更新次数中间取得一个平衡,其每次更新从训练集中随机选择m,m<n个样本进行学习,即:

θ=θηθJ(θ;xi:i+m;yi:i+m)



   其代码如下:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(epochs):np.random.shuffle(data)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> batch <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> get_batches(data, batch_size=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">50</span>):params_grad = evaluate_gradient(loss_function,batch,params)params = params - learning_rate * params_grad</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

   相对于随机梯度下降,Mini-batch梯度下降降低了收敛波动性,即降低了参数更新的方差,使得更新更加稳定。相对于全量梯度下降,其提高了每次学习的速度。并且其不用担心内存瓶颈从而可以利用矩阵运算进行高效计算。一般而言每次更新随机选择[50,256]个样本进行学习,但是也要根据具体问题而选择,实践中可以进行多次试验,选择一个更新速度与更次次数都较适合的样本数。

   mini-batch梯度下降虽然可以保证收敛性。mini-batch梯度下降常用于神经网络中。

问题与挑战

   虽然梯度下降算法效果很好,并且广泛使用,但同时其也存在一些挑战与问题需要解决:

  • 选择一个合理的学习速率很难。如果学习速率过小,则会导致收敛速度很慢。如果学习速率过大,那么其会阻碍收敛,即在极值点附近会振荡。

  • 学习速率调整(又称学习速率调度,Learning rate schedules)[11]试图在每次更新过程中,改变学习速率,如退火。一般使用某种事先设定的策略或者在每次迭代中衰减一个较小的阈值。无论哪种调整方法,都需要事先进行固定设置,这边便无法自适应每次学习的数据集特点[10]。

  • 模型所有的参数每次更新都是使用相同的学习速率。如果数据特征是稀疏的或者每个特征有着不同的取值统计特征与空间,那么便不能在每次更新中每个参数使用相同的学习速率,那些很少出现的特征应该使用一个相对较大的学习速率。

  • 对于非凸目标函数,容易陷入那些次优的局部极值点中,如在神经网路中。那么如何避免呢。Dauphin[19]指出更严重的问题不是局部极值点,而是鞍点(These saddle points are usually surrounded by a plateau of the same error, which makes it notoriously hard for SGD to escape, as the gradient is close to zero in all dimensions.)。

梯度下降优化算法

   下面将讨论一些在深度学习社区中经常使用用来解决上诉问题的一些梯度优化方法,不过并不包括在高维数据中不可行的算法,如牛顿法。

Momentum

   如果在峡谷地区(某些方向较另一些方向上陡峭得多,常见于局部极值点)[1],SGD会在这些地方附近振荡,从而导致收敛速度慢。这种情况下,动量(Momentum)便可以解决[2]。动量在参数更新项中加上一次更新量(即动量项),即:

νt=γνt1+ηθJ(θ)


θ=θνt



其中动量项超参数 γ<1 一般是小于等于0.9。

其作用如下图所示: 
 
图2 没有动量 
 
图3 加上动量

   加上动量项就像从山顶滚下一个球,求往下滚的时候累积了前面的动量(动量不断增加),因此速度变得越来越快,直到到达终点。同理,在更新模型参数时,对于那些当前的梯度方向与上一次梯度方向相同的参数,那么进行加强,即这些方向上更快了;对于那些当前的梯度方向与上一次梯度方向不同的参数,那么进行削减,即这些方向上减慢了。因此可以获得更快的收敛速度与减少振荡。

NAG[7]

   从山顶往下滚的球会盲目地选择斜坡。更好的方式应该是在遇到倾斜向上之前应该减慢速度。 
   Nesterov accelerated gradient(NAG,涅斯捷罗夫梯度加速)不仅增加了动量项,并且在计算参数的梯度时,在损失函数中减去了动量项,即计算θJ(θγνt1),这种方式预估了下一次参数所在的位置。即:

νt=γνt1+ηθJ(θγνt1)


θ=θνt



如下图所示:



图4 NAG更新

   详细介绍可以参见Ilya Sutskever的PhD论文[9]。假设动量因子参数γ=0.9,首先计算当前梯度项,如上图小蓝色向量,然后加上动量项,这样便得到了大的跳跃,如上图大蓝色的向量。这便是只包含动量项的更新。而NAG首先来一个大的跳跃(动量项),然后加上一个小的使用了动量计算的当前梯度(上图红色向量)进行修正得到上图绿色的向量。这样可以阻止过快更新来提高响应性,如在RNNs中[8]。 
   通过上面的两种方法,可以做到每次学习过程中能够根据损失函数的斜率做到自适应更新来加速SGD的收敛。下一步便需要对每个参数根据参数的重要性进行各自自适应更新。

Adagrad

   Adagrad[3]也是一种基于梯度的优化算法,它能够对每个参数自适应不同的学习速率,对稀疏特征,得到大的学习更新,对非稀疏特征,得到较小的学习更新,因此该优化算法适合处理稀疏特征数据。Dean等[4]发现Adagrad能够很好的提高SGD的鲁棒性,google便用起来训练大规模神经网络(看片识猫:recognize cats in Youtube videos)。Pennington等[5]在GloVe中便使用Adagrad来训练得到词向量(Word Embeddings), 频繁出现的单词赋予较小的更新,不经常出现的单词则赋予较大的更新。 
   在前述中,每个模型参数θi使用相同的学习速率η,而Adagrad在每一个更新步骤中对于每一个模型参数θi使用不同的学习速率ηi,设第t次更新步骤中,目标函数的参数θi梯度为gt,i,即:

gt,i=θJ(θi)



   那么SGD更新方程为:

θt+1,i=θt,iηgt,i



   而Adagrad对每一个参数使用不同的学习速率,其更新方程为:

θt+1,i=θt,iηGt,ii+ϵgt,i



其中, GtRd×d 是一个对角矩阵,其中第 i 行的对角元素 eii 为过去到当前第 i 个参数 θi 的梯度的平方和, epsilon 是一个平滑参数,为了使得分母不为0(通常 ϵ=1e8 ),另外如果分母不开根号,算法性能会很糟糕。

   进一步,将所有 Gt,ii,gt,i 的元素写成向量 Gt,gt ,这样便可以使用向量点乘操作:

θt+1=θtηGt+ϵgt



   Adagrad主要优势在于它能够为每个参数自适应不同的学习速率,而一般的人工都是设定为0.01。同时其缺点在于需要计算参数梯度序列平方和,并且学习速率趋势是不断衰减最终达到一个非常小的值。下文中的Adadelta便是用来解决该问题的。
### Adadelta    Adadelta[[6]](#reference_6)是Adagrad的一种扩展,为了降低Adagrad中学习速率衰减过快问题,其改进了三处,一是使用了窗口 w ;二是对于参数梯度历史窗口序列(不包括当前)不再使用平方和,而是使用均值代替;三是最终的均值是历史窗口序列均值与当前梯度的时间衰减加权平均。即:

E[g2]t=γE[g2]t1+(1γ)g2t

其中 γ 与动量项中的一样,都是

RMSprop

   其实RMSprop是Adadelta的中间形式,也是为了降低Adagrad中学习速率衰减过快问题,即:

E[g2]t=γE[g2]t1+(1γ)g2t


θt+1=θtηE[g2]t+ϵgt



Hinton建议 γ=0.9,η=0.001

Adam

   Adaptive Moment Estimation(Adam) 也是一种不同参数自适应不同学习速率方法,与Adadelta与RMSprop区别在于,它计算历史梯度衰减方式不同,不使用历史平方衰减,其衰减方式类似动量,如下:

mt=β1mt1+(1β1)gt


vt=β2vt1+(1beta2)g2t



   mt vt 分别是梯度的带权平均和带权有偏方差,初始为0向量,Adam的作者发现他们倾向于0向量(接近于0向量),特别是在衰减因子(衰减率) β1 , β2 接近于1时。为了改进这个问题,对 mt vt 进行偏差修正(bias-corrected):

mt^=mt1betat1


vt^=vt1betat2



   最终,Adam的更新方程为:

θt+1=θtηvt^+ϵmt^



论文中建议默认值: β1=0.9β2=0.999ϵ=108 。论文中将Adam与其它的几个自适应学习速率进行了比较,效果均要好。

各优化方法比较

   下面两幅图可视化形象地比较上述各优化方法,详细参见这里,如图: 
 
图5 SGD各优化方法在损失曲面上的表现

   从上图可以看出, Adagrad、Adadelta与RMSprop在损失曲面上能够立即转移到正确的移动方向上达到快速的收敛。而Momentum 与NAG会导致偏离(off-track)。同时NAG能够在偏离之后快速修正其路线,因为其根据梯度修正来提高响应性。 
 
图6 SGD各优化方法在损失曲面鞍点处上的表现

   从上图可以看出,在鞍点(saddle points)处(即某些维度上梯度为零,某些维度上梯度不为零),SGD、Momentum与NAG一直在鞍点梯度为零的方向上振荡,很难打破鞍点位置的对称性;Adagrad、RMSprop与Adadelta能够很快地向梯度不为零的方向上转移。 
   从上面两幅图可以看出,自适应学习速率方法(Adagrad、Adadelta、RMSprop与Adam)在这些场景下具有更好的收敛速度与收敛性。

如何选择SGD优化器

   如果你的数据特征是稀疏的,那么你最好使用自适应学习速率SGD优化方法(Adagrad、Adadelta、RMSprop与Adam),因为你不需要在迭代过程中对学习速率进行人工调整。 
   RMSprop是Adagrad的一种扩展,与Adadelta类似,但是改进版的Adadelta使用RMS去自动更新学习速率,并且不需要设置初始学习速率。而Adam是在RMSprop基础上使用动量与偏差修正。RMSprop、Adadelta与Adam在类似的情形下的表现差不多。Kingma[15]指出收益于偏差修正,Adam略优于RMSprop,因为其在接近收敛时梯度变得更加稀疏。因此,Adam可能是目前最好的SGD优化方法。 
   有趣的是,最近很多论文都是使用原始的SGD梯度下降算法,并且使用简单的学习速率退火调整(无动量项)。现有的已经表明:SGD能够收敛于最小值点,但是相对于其他的SGD,它可能花费的时间更长,并且依赖于鲁棒的初始值以及学习速率退火调整策略,并且容易陷入局部极小值点,甚至鞍点。因此,如果你在意收敛速度或者训练一个深度或者复杂的网络,你应该选择一个自适应学习速率的SGD优化方法。

并行与分布式SGD

   如果你处理的数据集非常大,并且有机器集群可以利用,那么并行或分布式SGD是一个非常好的选择,因为可以大大地提高速度。SGD算法的本质决定其是串行的(step-by-step)。因此如何进行异步处理便是一个问题。虽然串行能够保证收敛,但是如果训练集大,速度便是一个瓶颈。如果进行异步更新,那么可能会导致不收敛。下面将讨论如何进行并行或分布式SGD,并行一般是指在同一机器上进行多核并行,分布式是指集群处理。

  • Hogwild 
       Niu[23]提出了被称为Hogwild的并行SGD方法。该方法在多个CPU时间进行并行。处理器通过共享内存来访问参数,并且这些参数不进行加锁。它为每一个cpu分配不重叠的一部分参数(分配互斥),每个cpu只更新其负责的参数。该方法只适合处理数据特征是稀疏的。该方法几乎可以达到一个最优的收敛速度,因为cpu之间不会进行相同信息重写。

  • Downpour SGD 
       Downpour SGD是Dean[4]提出的在DistBelief(Google TensorFlow的前身)使用的SGD的一个异步变种。它在训练子集上训练同时多个模型副本。这些副本将各自的更新发送到参数服务器(PS,parameter server),每个参数服务器只更新互斥的一部分参数,副本之间不会进行通信。因此可能会导致参数发散而不利于收敛。

  • Delay-tolerant Algorithms for SGD 
       McMahan与Streeter[12]扩展AdaGrad,通过开发延迟容忍算法(delay-tolerant algorithms),该算法不仅自适应过去梯度,并且会更新延迟。该方法已经在实践中表明是有效的。

  • TensorFlow 
       TensorFlow[13]是Google开源的一个大规模机器学习库,它的前身是DistBelief。它已经在大量移动设备上或者大规模分布式集群中使用了,已经经过了实践检验。其分布式实现是基于图计算,它将图分割成多个子图,每个计算实体作为图中的一个计算节点,他们通过Rend/Receive来进行通信。具体参见这里。

  • Elastic Averaging SGD 
       Zhang等[14]提出Elastic Averaging SGD(EASGD),它通过一个elastic force(存储参数的参数服务器中心)来连接每个work来进行参数异步更新。This allows the local variables to fluctuate further from the center variable, which in theory allows for more exploration of the parameter space. They show empirically that this increased capacity for exploration leads to improved performance by finding new local optima. 这句话不太懂,需要去看论文。

更多的SGD优化策略

   接下来介绍更多的SGD优化策略来进一步提高SGD的性能。另外还有众多其它的优化策略,可以参见[22]。

  • Shuffling and Curriculum Learning 
       为了使得学习过程更加无偏,应该在每次迭代中随机打乱训练集中的样本。 
       另一方面,在很多情况下,我们是逐步解决问题的,而将训练集按照某个有意义的顺序排列会提高模型的性能和SGD的收敛性,如何将训练集建立一个有意义的排列被称为Curriculum Learning[16]。 
       Zaremba与Sutskever[17]在使用Curriculum Learning来训练LSTMs以解决一些简单的问题中,表明一个相结合的策略或者混合策略比对训练集按照按照训练难度进行递增排序要好。(表示不懂,衰)

  • Batch normalization 
       为了方便训练,我们通常会对参数按照0均值1方差进行初始化,随着不断训练,参数得到不同程度的更新,这样这些参数会失去0均值1方差的分布属性,这样会降低训练速度和放大参数变化随着网络结构的加深。 
       Batch normalization[18]在每次mini-batch反向传播之后重新对参数进行0均值1方差标准化。这样可以使用更大的学习速率,以及花费更少的精力在参数初始化点上。Batch normalization充当着正则化、减少甚至消除掉Dropout的必要性。

  • Early stopping 
       在验证集上如果连续的多次迭代过程中损失函数不再显著地降低,那么应该提前结束训练,详细参见NIPS 2015 Tutorial slides,或者参见防止过拟合的一些方法。

  • Gradient noise 
       Gradient noise[21]即在每次迭代计算梯度中加上一个高斯分布N(0,σ2t)的随机误差,即

    gt,i=gt,i+N(0,σ2t)

       高斯误差的方差需要进行退火:

    σ2t=η(1+t)γ

       对梯度增加随机误差会增加模型的鲁棒性,即使初始参数值选择地不好,并适合对特别深层次的负责的网络进行训练。其原因在于增加随机噪声会有更多的可能性跳过局部极值点并去寻找一个更好的局部极值点,这种可能性在深层次的网络中更常见。

总结

   在上文中,对梯度下降算法的三种框架进行了介绍,并且mini-batch梯度下降是使用最广泛的。随后,我们重点介绍了SGD的一些优化方法:Momentum、NAG、Adagrad、Adadelta、RMSprop与Adam,以及一些异步SGD方法。最后,介绍了一些提高SGD性能的其它优化建议,如:训练集随机洗牌与课程学习(shuffling and curriculum learning)、batch normalization,、early stopping与Gradient noise。 
   希望这篇文章能给你提供一些关于如何使用不同的梯度优化算法方面的指导。如果还有更多的优化建议或方法还望大家提出来?或者你使用什么技巧和方法来更好地训练SGD可以一起交流?Thanks。

引用

[1] Sutton, R. S. (1986). Two problems with backpropagation and other steepest-descent learning procedures for networks. Proc. 8th Annual Conf. Cognitive Science Society.

[2] Qian, N. (1999). On the momentum term in gradient descent learning algorithms. Neural Networks : The Official Journal of the International Neural Network Society, 12(1), 145–151. http://doi.org/10.1016/S0893-6080(98)00116-6.

[3] Duchi, J., Hazan, E., & Singer, Y. (2011). Adaptive Subgradient Methods for Online Learning and Stochastic Optimization. Journal of Machine Learning Research, 12, 2121–2159. Retrieved from http://jmlr.org/papers/v12/duchi11a.html.

[4] Dean, J., Corrado, G. S., Monga, R., Chen, K., Devin, M., Le, Q. V, … Ng, A. Y. (2012). Large Scale Distributed Deep Networks. NIPS 2012: Neural Information Processing Systems, 1–11. http://doi.org/10.1109/ICDAR.2011.95.

[5] Pennington, J., Socher, R., & Manning, C. D. (2014). Glove: Global Vectors for Word Representation. Proceedings of the 2014 Conference on Empirical Methods in Natural Language Processing, 1532–1543. http://doi.org/10.3115/v1/D14-1162.

[6] Zeiler, M. D. (2012). ADADELTA: An Adaptive Learning Rate Method. Retrieved from http://arxiv.org/abs/1212.5701.

[7] Nesterov, Y. (1983). A method for unconstrained convex minimization problem with the rate of convergence o(1/k2). Doklady ANSSSR (translated as Soviet.Math.Docl.), vol. 269, pp. 543– 547.

[8] Bengio, Y., Boulanger-Lewandowski, N., & Pascanu, R. (2012). Advances in Optimizing Recurrent Networks. Retrieved fromhttp://arxiv.org/abs/1212.0901.

[9] Sutskever, I. (2013). Training Recurrent neural Networks. PhD Thesis.

[10] Darken, C., Chang, J., & Moody, J. (1992). Learning rate schedules for faster stochastic gradient search. Neural Networks for Signal Processing II Proceedings of the 1992 IEEE Workshop, (September), 1–11. http://doi.org/10.1109/NNSP.1992.253713.

[11] H. Robinds and S. Monro, “A stochastic approximation method,” Annals of Mathematical Statistics, vol. 22, pp. 400–407, 1951.

[12] Mcmahan, H. B., & Streeter, M. (2014). Delay-Tolerant Algorithms for Asynchronous Distributed Online Learning. Advances in Neural Information Processing Systems (Proceedings of NIPS), 1–9. Retrieved from http://papers.nips.cc/paper/5242-delay-tolerant-algorithms-for-asynchronous-distributed-online-learning.pdf.

[13] Abadi, M., Agarwal, A., Barham, P., Brevdo, E., Chen, Z., Citro, C., … Zheng, X. (2015). TensorFlow : Large-Scale Machine Learning on Heterogeneous Distributed Systems.

[14] Zhang, S., Choromanska, A., & LeCun, Y. (2015). Deep learning with Elastic Averaging SGD. Neural Information Processing Systems Conference (NIPS 2015), 1–24. Retrieved from http://arxiv.org/abs/1412.6651.

[15] Kingma, D. P., & Ba, J. L. (2015). Adam: a Method for Stochastic Optimization. International Conference on Learning Representations, 1–13

[16] Bengio, Y., Louradour, J., Collobert, R., & Weston, J. (2009). Curriculum learning. Proceedings of the 26th Annual International Conference on Machine Learning, 41–48. http://doi.org/10.1145/1553374.1553380.

[17] Zaremba, W., & Sutskever, I. (2014). Learning to Execute, 1–25. Retrieved from http://arxiv.org/abs/1410.4615.

[18] Ioffe, S., & Szegedy, C. (2015). Batch Normalization : Accelerating Deep Network Training by Reducing Internal Covariate Shift. arXiv Preprint arXiv:1502.03167v3.

[19] Dauphin, Y., Pascanu, R., Gulcehre, C., Cho, K., Ganguli, S., & Bengio, Y. (2014). Identifying and attacking the saddle point problem in high-dimensional non-convex optimization. arXiv, 1–14. Retrieved from http://arxiv.org/abs/1406.2572.

[20] Sutskever, I., & Martens, J. (2013). On the importance of initialization and momentum in deep learning.http://doi.org/10.1109/ICASSP.2013.6639346.

[21] Neelakantan, A., Vilnis, L., Le, Q. V., Sutskever, I., Kaiser, L., Kurach, K., & Martens, J. (2015). Adding Gradient Noise Improves Learning for Very Deep Networks, 1–11. Retrieved from http://arxiv.org/abs/1511.06807.

[22] LeCun, Y., Bottou, L., Orr, G. B., & Müller, K. R. (1998). Efficient BackProp. Neural Networks: Tricks of the Trade, 1524, 9–50.http://doi.org/10.1007/3-540-49430-8_2.

[23] Niu, F., Recht, B., Christopher, R., & Wright, S. J. (2011). Hogwild ! : A Lock-Free Approach to Parallelizing Stochastic Gradient Descent, 1–22.

[24] Duchi et al. [3] give this matrix as an alternative to the full matrix containing the outer products of all previous gradients, as the computation of the matrix square root is infeasible even for a moderate number of parameters dd.

## 机器学习中常见的损失函数    一般来说,我们在进行机器学习任务时,使用的每一个算法都有一个目标函数,算法便是对这个目标函数进行优化,特别是在分类或者回归任务中,便是使用损失函数(Loss Function)作为其目标函数,又称为代价函数(Cost Function)。    损失函数是用来评价模型的预测值Y^=f(X)与真实值Y的不一致程度,它是一个非负实值函数。通常使用L(Y,f(x))来表示,损失函数越小,模型的性能就越好。    设总有N个样本的样本集为(X,Y)=(xi,yi)yi,i[1,N]为样本i的真实值,yi^=f(xi),i[1,N]为样本i的预测值,f为分类或者回归函数。 那么总的损失函数为:

L=i=1N(yi,yi^)

   常见的损失函数(yi,yi^)有以下几种: ### Zero-one Loss Zero-one Loss即0-1损失,它是一种较为简单的损失函数,如果预测值与目标值不相等,那么为1,否则为0,即:

(yi,yi^)={1,0,yiyi^yi=yi^

可以看出上述的定义太过严格,如果真实值为1,预测值为0.999,那么预测应该正确,但是上述定义显然是判定为预测错误,那么可以进行改进为Perceptron Loss。 ### Perceptron Loss Perceptron Loss即为感知损失。即:

(yi,yi^)={1,0,|yiyi^|>t|yiyi^|t

其中t是一个超参数阈值,如在PLA([Perceptron Learning Algorithm,感知机算法](http://kubicode.me/2015/08/06/Machine%20Learning/Perceptron-Learning-Algorithm/))中取t=0.5。 ### Hinge Loss Hinge损失可以用来解决间隔最大化问题,如在SVM中解决几何间隔最大化问题,其定义如下:

(yi,yi^)=max{0,1yiyi^}
yi{1,+1}

更多请参见:[Hinge-loss](https://en.wikipedia.org/wiki/Hinge_loss)。 ### Log Loss 在使用似然函数最大化时,其形式是进行连乘,但是为了便于处理,一般会套上log,这样便可以将连乘转化为求和,由于log函数是单调递增函数,因此不会改变优化结果。因此log类型的损失函数也是一种常见的损失函数,如在LR([Logistic Regression, 逻辑回归](chrome-extension://ikhdkkncnoglghljlkmcimlnlhkeamad/pdf-viewer/web/viewer.html?file=https%3A%2F%2Fpeople.eecs.berkeley.edu%2F~russell%2Fclasses%2Fcs194%2Ff11%2Flectures%2FCS194%2520Fall%25202011%2520Lecture%252006.pdf))中使用交叉熵(Cross Entropy)作为其损失函数。即:

(yi,yi^)=yilogyi^+(1yi)log(1yi^)
yi{0,1}

规定

0log=0

### Square Loss Square Loss即平方误差,常用于回归中。即:

(yi,yi^)=(yiyi^)2
yi,yi^R

### Absolute Loss Absolute Loss即绝对值误差,常用于回归中。即:

(yi,yi^)=|yiyi^|
yi,yi^R

### Exponential Loss Exponential Loss为指数误差,常用于boosting算法中,如[AdaBoost](https://en.wikipedia.org/wiki/AdaBoost)。即:

(yi,yi^)=exp(yiyi^)
yi{1,1}

正则

一般来说,对分类或者回归模型进行评估时,需要使得模型在训练数据上使得损失函数值最小,即使得经验风险函数最小化,但是如果只考虑经验风险(Empirical risk),容易过拟合(详细参见防止过拟合的一些方法),因此还需要考虑模型的泛化能力,一般常用的方法便是在目标函数中加上正则项,由损失项(Loss term)加上正则项(Regularization term)构成结构风险(Structural risk),那么损失函数变为:

L=i=1N(yi,yi^)+λR(ω)

其中λ是正则项超参数,常用的正则方法包括:L1正则与L2正则,详细介绍参见:防止过拟合的一些方法。

各损失函数图形如下:

2

防止过拟合的处理方法

过拟合

  我们都知道,在进行数据挖掘或者机器学习模型建立的时候,因为在统计学习中,假设数据满足独立同分布(i.i.d,independently and identically distributed),即当前已产生的数据可以对未来的数据进行推测与模拟,因此都是使用历史数据建立模型,即使用已经产生的数据去训练,然后使用该模型去拟合未来的数据。但是一般独立同分布的假设往往不成立,即数据的分布可能会发生变化(distribution drift),并且可能当前的数据量过少,不足以对整个数据集进行分布估计,因此往往需要防止模型过拟合,提高模型泛化能力。而为了达到该目的的最常见方法便是:正则化,即在对模型的目标函数(objective function)或代价函数(cost function)加上正则项。 
  在对模型进行训练时,有可能遇到训练数据不够,即训练数据无法对整个数据的分布进行估计的时候,或者在对模型进行过度训练(overtraining)时,常常会导致模型的过拟合(overfitting)。如下图所示: 
 
  通过上图可以看出,随着模型训练的进行,模型的复杂度会增加,此时模型在训练数据集上的训练误差会逐渐减小,但是在模型的复杂度达到一定程度时,模型在验证集上的误差反而随着模型的复杂度增加而增大。此时便发生了过拟合,即模型的复杂度升高,但是该模型在除训练集之外的数据集上却不work。 
  为了防止过拟合,我们需要用到一些方法,如:early stopping、数据集扩增(Data augmentation)、正则化(Regularization)、Dropout等。

Early stopping

  对模型进行训练的过程即是对模型的参数进行学习更新的过程,这个参数学习的过程往往会用到一些迭代方法,如梯度下降(Gradient descent)学习算法。Early stopping便是一种迭代次数截断的方法来防止过拟合的方法,即在模型对训练数据集迭代收敛之前停止迭代来防止过拟合。 
  Early stopping方法的具体做法是,在每一个Epoch结束时(一个Epoch集为对所有的训练数据的一轮遍历)计算validation data的accuracy,当accuracy不再提高时,就停止训练。这种做法很符合直观感受,因为accurary都不再提高了,在继续训练也是无益的,只会提高训练的时间。那么该做法的一个重点便是怎样才认为validation accurary不再提高了呢?并不是说validation accuracy一降下来便认为不再提高了,因为可能经过这个Epoch后,accuracy降低了,但是随后的Epoch又让accuracy又上去了,所以不能根据一两次的连续降低就判断不再提高。一般的做法是,在训练的过程中,记录到目前为止最好的validation accuracy,当连续10次Epoch(或者更多次)没达到最佳accuracy时,则可以认为accuracy不再提高了。此时便可以停止迭代了(Early Stopping)。这种策略也称为“No-improvement-in-n”,n即Epoch的次数,可以根据实际情况取,如10、20、30……

数据集扩增

  在数据挖掘领域流行着这样的一句话,“有时候往往拥有更多的数据胜过一个好的模型”。因为我们在使用训练数据训练模型,通过这个模型对将来的数据进行拟合,而在这之间又一个假设便是,训练数据与将来的数据是独立同分布的。即使用当前的训练数据来对将来的数据进行估计与模拟,而更多的数据往往估计与模拟地更准确。因此,更多的数据有时候更优秀。但是往往条件有限,如人力物力财力的不足,而不能收集到更多的数据,如在进行分类的任务中,需要对数据进行打标,并且很多情况下都是人工得进行打标,因此一旦需要打标的数据量过多,就会导致效率低下以及可能出错的情况。所以,往往在这时候,需要采取一些计算的方式与策略在已有的数据集上进行手脚,以得到更多的数据。 
  通俗得讲,数据机扩增即需要得到更多的符合要求的数据,即和已有的数据是独立同分布的,或者近似独立同分布的。一般有以下方法:

  • 从数据源头采集更多数据
  • 复制原有数据并加上随机噪声
  • 重采样
  • 根据当前数据集估计数据分布参数,使用该分布产生更多数据等

正则化方法

  正则化方法是指在进行目标函数或代价函数优化时,在目标函数或代价函数后面加上一个正则项,一般有L1正则与L2正则等。

  • L1正则 
      L1正则是基于L1范数,即在目标函数后面加上参数的L1范数和项,即参数绝对值和与参数的积项,即:

    C=C0+λnw|w|

    其中C0代表原始的代价函数,n是样本的个数,λ就是正则项系数,权衡正则项与C0项的比重。后面那一项即为L1正则项。 
      在计算梯度时,w的梯度变为:

    Cw=C0w+λnsgn(w)

    其中,sgn是符号函数,那么便使用下式对参数进行更新:

    w:=w+αC0w+βλnsgn(w)

    对于有些模型,如线性回归中(L1正则线性回归即为Lasso回归),常数项b的更新方程不包括正则项,即:

    b:=b+αC0b

    其中,梯度下降算法中,α<0,β<0,而在梯度上升算法中则相反。 
      从上式可以看出,当w为正时,更新后w会变小;当w为负时,更新后w会变大;因此L1正则项是为了使得那些原先处于零(即|w|0)附近的参数w往零移动,使得部分参数为零,从而降低模型的复杂度(模型的复杂度由参数决定),从而防止过拟合,提高模型的泛化能力。 
      其中,L1正则中有个问题,便是L1范数在0处不可导,即|w|在0处不可导,因此在w为0时,使用原来的未经正则化的更新方程来对w进行更新,即令sgn(0)=0,这样即:

    sgn(w)|w>0=1,sgn(w)|w<0=1,sgn(w)|w=0=0
  • L2正则 
      L2正则是基于L2范数,即在目标函数后面加上参数的L2范数和项,即参数的平方和与参数的积项,即:

    C=C0+λ2nww2

    其中C0代表原始的代价函数,n是样本的个数,与L1正则化项前面的参数不同的是,L2项的参数乘了12,是为了便于计算以及公式的美感性,因为平方项求导有个2,λ就是正则项系数,权衡正则项与C0项的比重。后面那一项即为L2正则项。 
      L2正则化中则使用下式对模型参数进行更新:

    w:=w+αC0w+βλnw

    对于有些模型,如线性回归中(L2正则线性回归即为Ridge回归,岭回归),常数项b的更新方程不包括正则项,即:

    b:=b+αC0b

    其中,梯度下降算法中,α<0,β<0,而在梯度上升算法中则相反。 
      从上式可以看出,L2正则项起到使得参数w变小加剧的效果,但是为什么可以防止过拟合呢?一个通俗的理解便是:更小的参数值w意味着模型的复杂度更低,对训练数据的拟合刚刚好(奥卡姆剃刀),不会过分拟合训练数据,从而使得不会过拟合,以提高模型的泛化能力。 
      在这里需要提到的是,在对模型参数进行更新学习的时候,有两种更新方式,mini-batch (部分增量更新)与 full-batch(全增量更新),即在每一次更新学习的过程中(一次迭代,即一次epoch),在mini-batch中进行分批处理,先使用一部分样本进行更新,然后再使用一部分样本进行更新。直到所有样本都使用了,这次epoch的损失函数值则为所有mini batch的平均损失值。设每次mini batch中样本个数为m,那么参数的更新方程中的正则项要改成:

    λmw|w|
    λ2mww2

    而full-batch即每一次epoch中,使用全部的训练样本进行更新,那么每次的损失函数值即为全部样本的误差之和。更新方程不变。

  • 总结 
      正则项是为了降低模型的复杂度,从而避免模型区过分拟合训练数据,包括噪声与异常点(outliers)。从另一个角度上来讲,正则化即是假设模型参数服从先验概率,即为模型参数添加先验,只是不同的正则化方式的先验分布是不一样的。这样就规定了参数的分布,使得模型的复杂度降低(试想一下,限定条件多了,是不是模型的复杂度降低了呢),这样模型对于噪声与异常点的抗干扰性的能力增强,从而提高模型的泛化能力。还有个解释便是,从贝叶斯学派来看:加了先验,在数据少的时候,先验知识可以防止过拟合;从频率学派来看:正则项限定了参数的取值,从而提高了模型的稳定性,而稳定性强的模型不会过拟合,即控制模型空间。 
      另外一个角度,过拟合从直观上理解便是,在对训练数据进行拟合时,需要照顾到每个点,从而使得拟合函数波动性非常大,即方差大。在某些小区间里,函数值的变化性很剧烈,意味着函数在某些小区间里的导数值的绝对值非常大,由于自变量的值在给定的训练数据集中的一定的,因此只有系数足够大,才能保证导数的绝对值足够大。如下图(引用知乎): 
     
      另外一个解释,规则化项的引入,在训练(最小化cost)的过程中,当某一维的特征所对应的权重过大时,而此时模型的预测和真实数据之间距离很小,通过规则化项就可以使整体的cost取较大的值,从而,在训练的过程中避免了去选择那些某一维(或几维)特征的权重过大的情况,即过分依赖某一维(或几维)的特征(引用知乎)。 
      L2与L1的区别在于,L1正则是拉普拉斯先验,而L2正则则是高斯先验。它们都是服从均值为0,协方差为1λ。当λ=0时,即没有先验)没有正则项,则相当于先验分布具有无穷大的协方差,那么这个先验约束则会非常弱,模型为了拟合所有的训练集数据, 参数w可以变得任意大从而使得模型不稳定,即方差大而偏差小。λ越大,标明先验分布协方差越小,偏差越大,模型越稳定。即,加入正则项是在偏差bias与方差variance之间做平衡tradeoff(来自知乎)。下图即为L2与L1正则的区别: 
     
    上图中的模型是线性回归,有两个特征,要优化的参数分别是w1和w2,左图的正则化是L2,右图是L1。蓝色线就是优化过程中遇到的等高线,一圈代表一个目标函数值,圆心就是样本观测值(假设一个样本),半径就是误差值,受限条件就是红色边界(就是正则化那部分),二者相交处,才是最优参数。可见右边的最优参数只可能在坐标轴上,所以就会出现0权重参数,使得模型稀疏。 
      其实拉普拉斯分布与高斯分布是数学家从实验中误差服从什么分布研究中得来的。一般直观上的认识是服从应该服从均值为0的对称分布,并且误差大的频率低,误差小的频率高,因此拉普拉斯使用拉普拉斯分布对误差的分布进行拟合,如下图: 
     
    而拉普拉斯在最高点,即自变量为0处不可导,因为不便于计算,于是高斯在这基础上使用高斯分布对其进行拟合,如下图: 
     
    具体参见:正态分布的前世今生

Dropout

  正则是通过在代价函数后面加上正则项来防止模型过拟合的。而在神经网络中,有一种方法是通过修改神经网络本身结构来实现的,其名为Dropout。该方法是在对网络进行训练时用一种技巧(trick),对于如下所示的三层人工神经网络: 
 
对于上图所示的网络,在训练开始时,随机得删除一些(可以设定为一半,也可以为1/3,1/4等)隐藏层神经元,即认为这些神经元不存在,同时保持输入层与输出层神经元的个数不变,这样便得到如下的ANN: 
 
然后按照BP学习算法对ANN中的参数进行学习更新(虚线连接的单元不更新,因为认为这些神经元被临时删除了)。这样一次迭代更新便完成了。下一次迭代中,同样随机删除一些神经元,与上次不一样,做随机选择。这样一直进行瑕疵,直至训练结束。 
  Dropout方法是通过修改ANN中隐藏层的神经元个数来防止ANN的过拟合。具体可参见这里。

机器学习的若干问题解释相关推荐

  1. 贝叶斯网络结构学习若干问题解释

    题目:贝叶斯网络结构学习若干问题解释 本篇主要为后续讲解具体结构学习算法打基础,共解释以下几个问题: 1.用于贝叶斯网络结构学习的数据集如何存储? 2.学得的贝叶斯网络结构如何存储? 3.什么是节点顺 ...

  2. 机器学习经典算法具体解释及Python实现--K近邻(KNN)算法

    (一)KNN依旧是一种监督学习算法 KNN(K Nearest Neighbors,K近邻 )算法是机器学习全部算法中理论最简单.最好理解的.KNN是一种基于实例的学习,通过计算新数据与训练数据特征值 ...

  3. 【机器学习笔记】可解释机器学习-学习笔记 Interpretable Machine Learning (Deep Learning)

    [机器学习笔记]可解释机器学习-学习笔记 Interpretable Machine Learning (Deep Learning) 目录 [机器学习笔记]可解释机器学习-学习笔记 Interpre ...

  4. 数据分析入门必知:机器学习最通俗的解释?

    有人经常会把数据分析与机器学习给搞混掉,机器学习这个主题已经很普遍了,每个人都在谈论它,但很少有人能够透彻地了解它,今天老李给大家分享一下机器学习的概念. 数据分析和机器学习 如果你认为大数据仅仅是关 ...

  5. R语言机器学习mlr3:模型解释

    获取更多R语言和生信知识,请欢迎关注公众号:医学和生信笔记 医学和生信笔记 公众号主要分享:1.医学小知识.肛肠科小知识:2.R语言和Python相关的数据分析.可视化.机器学习等:3.生物信息学学习 ...

  6. 机器学习中的名词解释(一):监督学习、无监督学习、半监督学习、自监督学习(通俗理解)

    机器学习中有几个带有"监督"二字的名词,易混淆,写篇博客解释一下下~ 1.监督学习(Supervised Learning):是指从标注数据中学习预测模型的机器学习方法,其本质是学 ...

  7. 12月机器学习新书-《可解释机器学习局限性》最新版下载

    本书讲解了当前可解释机器学习方法中存在的局限性.这些方法包括partial dependence plots(PDP).累积局部效应(Accumulated Local Effects,ALE).排列 ...

  8. 论文研读-机器学习可视化-面向可视解释的零样本分类主动学习

    面向可视解释的零样本分类主动学习 1 文章概要 1.1 摘要 1.2 引言 1.2.1 零样本分类 1.1.2 解决方案 1.2.3 文章贡献 1.3 组织结构 2 相关工作 3 用于零样本学习的人机 ...

  9. 【机器学习】SHAP- 机器学习模型解释可视化工具

    SHAP 是机器学习模型解释可视化工具.在此示例中,使用 SHAP 计算使用 Python 和 scikit-learn 的神经网络的特征影响 .对于这个例子,使用 scikit-learn 的 糖尿 ...

最新文章

  1. 【数学和算法】协方差矩阵、方差
  2. verilog中的代码使用
  3. java本地可以发到linux不行,java 使用 ftp 在windows环境下可以正常下载文件,在linux环境下不行...
  4. javascript 将table导出 Excel ,可跨行跨列
  5. 2019 ACOUG年会圆满结束(附PPT和视频下载)
  6. 恶意软件针对中国用户 试图攫取用户账户和密码
  7. 光山二高2021高考成绩查询,光山县第二高级中学2019高考成绩和历年成绩汇总
  8. android epson wifi,epson投影仪无线投屏怎么连接手机、电脑
  9. linux判断网卡能否上网,网卡坏了有什么现象?判断网卡是否坏了的方法
  10. Lync添加自定义菜单
  11. 人工智能时代是什么时代?
  12. 冰河,能不能讲讲如何实现MySQL数据存储的无限扩容?
  13. 利用MATLAB绘制各种表白心形-跳动心形
  14. Spring IOC 和 DI原理 (面试必备)
  15. 团队管理者就是背锅的
  16. 对口升学2018计算机试题,河南省2018年计算机类基础课 对口升学考试题
  17. python怎么掉包_Python实战教程:拒绝调包,如何用python推导线性回归模型
  18. Python创建多线程的三种方法
  19. 白杨SEO:评论推广引流,学会这招,既可锻炼执行力又可拓展思路!
  20. 4年前的最佳小说回顾

热门文章

  1. 对象不支持“abigimage”属性或方法
  2. 状态模式在领域驱动设计中的使用
  3. springMVC 注解 controller层的优化
  4. 谢尔排序/缩减增量排序(C++)
  5. Android实现炫酷的星空变幻效果
  6. 查看linux系统的性能
  7. 【C++】explicit 关键字
  8. ComputeShader中Counter类型的使用
  9. weexapp 开发流程(一)开发环境配置
  10. HTML5 Canvas 绘制佛教万字