梯度降低
算法是
机器学习中使用很是普遍的优化算法,也是众多机器学习算法中最经常使用的优化方法。几乎当前每个先进的(state-of-the-art)机器学习库或者
深度学习库都会包括梯度降低算法的不一样变种实现。可是,它们就像一个黑盒优化器,很可贵到它们优缺点的实际解释。这篇文章旨在提供梯度降低算法中的不一样变种的介绍,帮助使用者根据具体须要进行使用。
这篇文章首先介绍梯度降低算法的三种框架,而后介绍它们所存在的问题与挑战,接着介绍一些如何进行改进来解决这些问题,随后,介绍如何在并行环境中或者分布式环境中使用梯度降低算法。最后,指出一些有利于梯度降低的策略。
目录
三种梯度降低优化框架
批量梯度降低
随机梯度降低
小批量梯度降低
问题与挑战
梯度降低优化算法
Momentum
Nesterov accelerated gradient
Adagrad
Adadelta
RMSprop
Adam
算法的可视化
选择哪一种优化算法?
并行与分布式SDG
Hogwild!
Downpour SGD
Delay-tolerant Algorithms for SGD
TensorFlow
Elastic Averaging SGD
更多的SDG优化策略
训练集随机洗牌与课程学习
批规范化
Early Stopping
Gradient noise
总结
引用
三种梯度降低优化框架
梯度降低算法是经过沿着目标函数J(θ)参数θ∈R的梯度(一阶导数)相反方向−∇θJ(θ)来不断更新模型参数来到达目标函数的极小值点(收敛),更新步长为η。
有三种梯度降低算法框架,它们不一样之处在于每次学习(更新模型参数)使用的样本个数,每次更新使用不一样的样本会致使每次学习的准确性和学习时间不一样。
批量梯度降低(Batch gradient descent)
每次使用全量的训练集样原本更新模型参数,即: θ=θ−η⋅∇θJ(θ)
其代码以下:
epochs 是用户输入的最大迭代次数。经过上诉代码能够看出,每次使用所有训练集样本计算损失函数 loss_function 的梯度 params_grad,而后使用学习速率 learning_rate 朝着梯度相反方向去更新模型的每一个参数params。通常各现有的一些机器学习库都提供了梯度计算api。若是想本身亲手写代码计算,那么须要在程序调试过程当中验证梯度计算是否正确。
批量梯度降低每次学习都使用整个训练集,所以其优势在于每次更新都会朝着正确的方向进行,最后可以保证收敛于极值点(凸函数收敛于全局极值点,非凸函数可能会收敛于局部极值点),可是其缺点在于每次学习时间过长,而且若是训练集很大以致于须要消耗大量的内存,而且全量梯度降低不能进行在线模型参数更新。
随机梯度降低(Stochastic gradient descent)
随机梯度降低算法每次从训练集中随机选择一个样原本进行学习,即: θ=θ−η⋅∇θJ(θ;xi;yi)
批量梯度降低算法每次都会使用所有训练样本,所以这些计算是冗余的,由于每次都使用彻底相同的样本集。而随机梯度降低算法每次只随机选择一个样原本更新模型参数,所以每次的学习是很是快速的,而且能够进行在线更新。
其代码以下:
随机梯度降低最大的缺点在于每次更新可能并不会按照正确的方向进行,所以能够带来优化波动(扰动),以下图:
图1 SGD扰动
不过从另外一个方面来看,随机梯度降低所带来的波动有个好处就是,对于相似盆地区域(即不少局部极小值点)那么这个波动的特色可能会使得优化的方向从当前的局部极小值点跳到另外一个更好的局部极小值点,这样即可能对于非凸函数,最终收敛于一个较好的局部极值点,甚至全局极值点。
因为波动,所以会使得迭代次数(学习次数)增多,即收敛速度变慢。不过最终其会和全量梯度降低算法同样,具备相同的收敛性,即凸函数收敛于全局极值点,非凸损失函数收敛于局部极值点。
小批量梯度降低(Mini-batch gradient descent)
Mini-batch 梯度降低综合了 batch 梯度降低与 stochastic 梯度降低,在每次更新速度与更新次数中间取得一个平衡,其每次更新从训练集中随机选择 m,m<n 个样本进行学习,即:
θ=θ−η⋅∇θJ(θ;xi:i+m;yi:i+m)
其代码以下:
相对于随机梯度降低,Mini-batch梯度降低下降了收敛波动性,即下降了参数更新的方差,使得更新更加稳定。相对于全量梯度降低,其提升了每次学习的速度。而且其不用担忧内存瓶颈从而能够利用矩阵运算进行高效计算。通常而言每次更新随机选择[50,256]个样本进行学习,可是也要根据具体问题而选择,实践中能够进行屡次试验,选择一个更新速度与更次次数都较适合的样本数。mini-batch梯度降低能够保证收敛性,经常使用于
神经网络中。
问题与挑战
虽然梯度降低算法效果很好,而且普遍使用,但同时其也存在一些挑战与问题须要解决:
选择一个合理的学习速率很难。若是学习速率太小,则会致使收敛速度很慢。若是学习速率过大,那么其会阻碍收敛,即在极值点附近会振荡。
学习速率调整(又称学习速率调度,Learning rate schedules)[11]试图在每次更新过程当中,改变学习速率,如退火。通常使用某种事先设定的策略或者在每次迭代中衰减一个较小的阈值。不管哪一种调整方法,都须要事先进行固定设置,这边便没法自适应每次学习的数据集特色[10]。
模型全部的参数每次更新都是使用相同的学习速率。若是数据特征是稀疏的或者每一个特征有着不一样的取值统计特征与空间,那么便不能在每次更新中每一个参数使用相同的学习速率,那些不多出现的特征应该使用一个相对较大的学习速率。
对于非凸目标函数,容易陷入那些次优的局部极值点中,如在神经网路中。那么如何避免呢。Dauphin[19]指出更严重的问题不是局部极值点,而是鞍点。
梯度降低优化算法
下面将讨论一些在深度学习社区中常用用来解决上诉问题的一些梯度优化方法,不过并不包括在高维数据中不可行的算法,如牛顿法。
Momentum
若是在峡谷地区(某些方向较另外一些方向上陡峭得多,常见于局部极值点)[1],SGD会在这些地方附近振荡,从而致使收敛速度慢。这种状况下,动量(Momentum)即可以解决[2]。
动量在参数更新项中加上一次更新量(即动量项),即: νt=γνt−1+η ∇θJ(θ),θ=θ−νt
其中动量项超参数γ<1通常是小于等于0.9。
其做用以下图所示:
图2 没有动量
图3 加上动量
加上动量项就像从山顶滚下一个球,求往下滚的时候累积了前面的动量(动量不断增长),所以速度变得愈来愈快,直到到达终点。同理,在更新模型参数时,对于那些当前的梯度方向与上一次梯度方向相同的参数,那么进行增强,即这些方向上更快了;对于那些当前的梯度方向与上一次梯度方向不一样的参数,那么进行削减,即这些方向上减慢了。所以能够得到更快的收敛速度与减小振荡。
Nesterov accelerated gradient(NAG)
从山顶往下滚的球会盲目地选择斜坡。更好的方式应该是在遇到倾斜向上以前应该减慢速度。
Nesterov accelerated gradient(NAG,涅斯捷罗夫梯度加速)不只增长了动量项,而且在计算参数的梯度时,在损失函数中减去了动量项,即计算∇θJ(θ−γνt−1),这种方式预估了下一次参数所在的位置。即:
νt=γνt−1+η⋅∇θJ(θ−γνt−1),θ=θ−ν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), 频繁出现的单词赋予较小的更新,不常常出现的单词则赋予较大的更新。
Adagrad主要优点在于它可以为每一个参数自适应不一样的学习速率,而通常的人工都是设定为0.01。同时其缺点在于须要计算参数梯度序列平方和,而且学习速率趋势是不断衰减最终达到一个很是小的值。下文中的Adadelta即是用来解决该问题的。
Adam
Adaptive Moment Estimation (Adam) 也是一种不一样参数自适应不一样学习速率方法,与Adadelta与RMSprop区别在于,它计算历史梯度衰减方式不一样,不使用历史平方衰减,其衰减方式相似动量,以下:
mt=β1mt−1+(1−β1)gt
vt=β2vt−1+(1−beta2)g2t
mt与vt分别是梯度的带权平均和带权有偏方差,初始为0向量,Adam的做者发现他们倾向于0向量(接近于0向量),特别是在衰减因子(衰减率)β1,β2接近于1时。为了改进这个问题,
对mt与vt进行误差修正(bias-corrected):
mt^=mt1−betat1
vt^=vt1−betat2
最终,Adam的更新方程为:
θt+1=θt−ηvt^−−√+ϵmt^
论文中建议默认值:β1=0.9,β2=0.999,ϵ=10−8。论文中将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来进行参数异步更新。
更多的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。
|