本文来源于谭旭对【深度学习分布式训练中大batchsize与学习率的关系如何理解?】的回答。问题详情:在深度学习中进行分布式训练时,经常使用同步数据并行,即使用大batchsize进行训练,但是大batch的性能普遍比smallbaselinebatchsize差。如何理解debuglearningrate能否让largebatch达到和smallbatch一样的收敛精度和速度?答:最近在进行多GPU分布式训练的时候,也遇到了大batch和学习率的理解和调试问题。对比baseline的batchsize,multi-machineSynchronousparallelism(之前的回答是介绍同步并行通信框架NCCL(谭旭:如何理解Nvidia的Multi-GPU多卡通信框架NCCL?),如果你是有兴趣的可以去看看)相当于增加了batchsize,如果不进行finedesign,大batch的收敛效果往往比baseline的小batchsize差。因此,我把自己的理解和实验总结如下,主要分为三个方面:(1)理解SGD、minibatch-SGD和GD,(2)largebatch和learningrate的debug关系,(3)我们的实验。(1)理解SGD、minibatch-SGD和GD在机器学习优化算法中,GD(梯度下降)是最常用的方法之一。简单的说就是计算整个训练集中的当前梯度,选择一个步长进行renew。GD的优点是基于整个数据集得到的梯度,梯度估计比较准确,更新过程也比较准确。但也有几个缺点。一是当训练集很大时,GD的梯度计算比较耗时。二是现代深度学习网络的损失函数往往是非凸的,基于凸优化理论的优化算法只能收敛到局部极小值,因此使用GD训练深度神经网络,最终的收敛点容易落在初始点附近的局部极小值上,不易获得较好的收敛性能。另一个极端是SGD(随机梯度下降),它每次计算梯度只使用一个样本。这样做的优点是计算速度快,非常适合在线学习数据流到达的场景,缺点是单个样本产生的梯度估计。它往往非常不准确,因此必须使用非常小的学习率,并且由于现代计算框架CPU/GPU的多线程工作,单个样本往往很难完全占据CPU/GPU使用率,造成计算资源的浪费。折衷的解决方案是小批量。batchsize样本用于一次估计梯度,因此梯度估计比SGD更准确。同时batchsize可以占用CPU/GPU的计算资源,不像GD那样计算整个训练集。.同时,由于mini-batch可以有适当的梯度噪声[8],在一定程度上可以缓解GD直接陷入初始点附近的局部极小点导致收敛性差的缺点,因此mini-batch方法也是最常用的。关于增加batchsize对梯度估计精度的影响,分析如下:假设batchsize为m,对于一个minibatch,loss为:gradient整个minibatch的梯度方差为:由于每个样本从训练样本集sample中随机得到,满足i.i.d.假设,所以样本梯度的方差相等,相当于SGD的梯度方差。可以看出,将batchsize增加m倍,相当于将梯度的方差减小m倍,所以梯度更准确。如果要保持方差和原来的SGD一样,相当于给定这么大的方差带宽容量,那么可以增加lr,充分利用这个方差容量,在上面的公式中加上lr,用方差变化公式得到相等因此,该公式可以将lr增加sqrt(m)倍,以提高训练速度。这也是很多人在线性缩放规则[4]之前用来增加lr的方式。下一小节将详细介绍增加lr的问题。(2)大批量和学习率在分布式训练中,批量大小随着数据并行工作者的增加而增加。假设baseline的batchsize为B,学习率为lr,训练epoch数为N。如果保持baseline的学习率,一般不会有更好的收敛速度和准确率。原因如下:对于收敛速度,假设k个worker,每次通过的样本数为kB,所以一个epoch下的更新次数为baseline的1/k,每次更新的lr不变,所以要达到相同的基线更新次数需要增加epochs的数量,需要增加k*N个epochs,所以收敛加速因子会比k低很多。对于收敛精度,由于增加了batchsize,梯度估计比badeline的梯度更准确,噪声降低,更容易收敛到附近的局部极小值,类似于GD的效果。为了解决这个问题,一种方法是增加lr,因为batch越大梯度估计越准确,应该比baseline的梯度更可靠,所以增加lr,使用更准确的梯度去多一点,提高收敛速度。同时增加lr,使每次游走的范围尽可能大。如果遇到sharplocalminima[8](sharpminima还是有争议的,暂且引用这个说法),有可能逃逸并收敛到更好的地方。但是无法抑制lr的增加,原因如下。深度神经网络的损失面往往是高维和高度非线性的。可以理解为损耗面表面凹凸不平,坑坑洼洼。它不像y=x^2曲线那样平滑。因此,基于当前权重计算的梯度向前更新,当学习率很大时,沿着损失面的切线走了一大步,可能会大大偏离原来的损失面。示例如下图(a)所示。虚线是当前梯度的方向,也就是当前损失面的切线方向,如果学习率太大,那么这一步会沿着切线方向迈一大步。如果继续这样下去,很可能会导致错误的损失面,如图(b)所示。如果是小学习率,每次只沿着切线方向走一小步。虽然有一些偏差,但还是可以大致沿着losssurface的最速下降曲线下降,最后收敛到一个好的局部极小点,如图(c)所示。同时根据凸收敛理论[2]也可以得到lr的上界:lr<1/L,L为损失曲面梯度曲线的Lipschitz因子,L可以理解为损失梯度变化范围的上限。如果变化幅度越大,L越大,lr就会越小。如果变化幅度小,L小,lr可以大。这与上面的分析是一致的。那么,如何确定largebatch和learningrate的关系呢?比较baseline和largebatchkworkers[7]的更新公式,如下:这是baseline(batchsizeB)和largebatch(batchsizekB)的更新公式中,数据量在(4)中的largebatchstep相当于(3)中baselinek步的数据量,loss和gradient根据找到的数据量进行平均。因此,为了保证相同的数据利用率,式(4)中的学习率应该是基线的k倍,这是学习率的线性比例规则。线性比例规则有几个约束条件,其中之一是对权重的约束。式(3)中,每一步更新所依据的权重是上一步更新后的权重,所以相当于采取小步,每一步都是根据当前真实的权重计算梯度进行更新,而大的公式(4)的step(相当于相对于baseline的k步)根据t时刻的权重进行更新。如果在这k步内,W(t+j)~W(t),两者的逼近没有太大问题,即线性比例尺规则问题不大,但是当权值快速变化时,会有问题,尤其是模型刚开始训练的时候,loss很快,权重变化很快,W(t+j)~W(t)不满足。因此,在初始训练阶段,一般不会直接将lr增加到k倍,而是从基线lr慢慢预热到k倍,这样就不会那么明显地违反线性比例规则。这也是Facebook的一小时imagenet训练实践[7]。第二个约束是lr不能完全放大。根据上面的分析,lr太大,沿着损失正切跑得太远,造成收敛问题。同时,有文献[5]指出,当batchsize变大时,lr允许得到好的测试结果的范围变小,也就是说当batchsize小时,更容易找到asuitablelrtoachieveagood结果,当batchsize变大的时候,可能需要仔细寻找一个合适的lr才能达到更好的效果,这也给实际的大batch分布式训练带来困难。(3)我们的实验最近正在考虑与NLP相关的深度模型的分布式训练问题。实验细节如下。由于部分工作暂时不便透露,仅提供简要的实验细节:模型基线参数为batchsize32,lr0.25,最终精度为BLEUscore:28.35。现在用于分布式扩展到多卡并行。实验一:只增加parallelworker的数量(相当于增加batchsize),lr为baselinelr0不变。可以看出,随着batch变大,如果lr不变,模型的准确率会逐渐下降。也符合上述分析。实验二:增加batchsize,lr相应增加。可以看出,通过将lr增加到5*lr0(理论上lr应该增加到8倍,但是实际效果并不好,所以只增加了5倍),通过warmuplr,达到同样的效果Bleu效应作为基线。最终收敛速度约为5倍,即8张卡可以达到5倍的收敛加速(不考虑系统通信同步消耗的时间,即不考虑系统加速比)。深度学习的并行训练可以提高模型训练的速度,但是在实际使用过程中会面临一系列的问题,包括系统级的架构设计、算法级的参数调试等,欢迎有兴趣的朋友多多讨论。
