第十三讲. 大规模机器学习——Large Scale Machine Learning
=============================
(一)、为什么要大规模机器学习?
(二)、Stochastic和Batch梯度下降
(三)、Mini-Batch梯度下降
(四)、在线学习(Online Learning)
(五)、MapReduce和并行计算原理
=====================================
(一)、为什么要大规模机器学习?
一、为什么需要大数据?
"We have already seen that, one of the best ways to get a high performance machine learning system is, if you take a low bias learning algorithm and train that on a lot data."
也就是说,"得到一个性能好的机器学习系统的最好方法之一,是确定一个低偏差的学习方法,然后用很多数据来训练它"。
这么说是因为,我们在前面的章节(见Rachel Zhang博客)探讨过一个好的学习算法需要同时具备低偏差(bias)和低方差(variance)两个特点。所以,当我们的学习算法是一个低偏差的方法时,这时我们只需要增加数据尽可能地降低模型的方差,就可以了。
因此,在机器学习领域有这样一种说法:It‘s not who has the best algorithm that wins. It‘s who has the most data.
二、怎么确定是时候增加数据量来提高模型性能了?
数据量也并不是一味地增加就好了。
首先,数据量增加,计算量就会随之增大,这非常影响训练的效率。
其次,我们需要判断当前的算法本身、数据特征等因素是否具备增大数据集可以继续提高算法性能的条件。这在之前章节也有过说明,增大数据集并不是在任何时候都具有提高模型性能的作用。举例说明如下图:
当数据量m=1000时,如果损失函数的曲线如左图所示,说明当前的模型具有high variance,右图则说明是high bias。
当处于右图high bias的情况时,继续增大数据量并没有多大帮助,相反这时候应该增加特征维度、增加神经网络隐藏单元等等,这可能会使曲线从右图变成左图的样子。
然后,当处于左图high variance情况时,就适合增加数据量来提高模型性能了。
二、对比二者算法
如上图所示,二者的主要区别在于,Batch是对所有样本的损失函数和值求相对模型参数的偏导,而Stochastic则是对某个样本的损失函数求相对模型参数的偏导,每求一个样本的偏导更新一次模型参数。
三、对比二者收敛方式
如上图的右图所示,红色表示Batch Gradient Descent的收敛曲线(即损失函数值的变化趋势),粉色则表示Stochastic Gradient Descent的。红色曲线可以保证每次迭代损失函数值都会减小,直至global minimum;粉色曲线则比较“曲折”,它并不能保证每次迭代都使损失函数值减小,但可以保证整体呈减小的趋势,最后收敛至global minimum附近,而非精确的global minimum。
有一个不常被用到但make sense的做法,可以让算法在global minimum附近更接近global minimum,即使学习率alpha动态变化而非固定常数,使alpha值随着迭代次数而递减,如alpha = A / ( iterationNumber + B )。当模型参数接近global minimum的时候,减小学习率(步子迈小点),可以避免在最优值附近跳变,慢慢收敛至最优值。之所以这个策略不常被用到,是因为它引入了另外两个参数变量,所以不推荐。
需要额外说明的一点是,Stochastic Gradient Descent的第一步是Randomly shuffle dataset,这样做是因为Stochastic Gradient Descent是通过逐一计算某个单一样本的损失函数的导数值来更新模型参数的,且并非每个样本的计算都会使整体损失函数值J减小,那么当选取的第一个样本或样本的遍历顺序不同时,结果都有可能是不同的。为了使优化结果和这些因素无关,最好计算前先打乱一下数据。
四、如何判断随机梯度下降算法的损失函数何时收敛?
如上图所示,
Batch Gradient Descent:通过画损失函数J关于迭代次数的曲线,来判断J的值是否在不断下降,判断算法是否在收敛,或判断当前是处于high variance还是high bias。
Stochastic Gradient Descent:每1000次迭代(即 The algorithm has seen 1000 new examples)以后,计算这1000个样本平均的损失函数值;再经过1000次迭代,再计算一次平均值,以此类推,然后将此平均值描绘成曲线,观察1000个样本的平均损失函数值是否在递减。
下面画几个例子,阐述一下怎么通过上述曲线来分析Stochastic Gradient Descent目标函数的收敛性。如下图所示,逐一分析:
右上:蓝色曲线表示每1000次迭代描一个点,红色表示5000。这个对比说明,由于Stochastic Gradient Descent并不能保证每次迭代都下降,所以也就不能保证每1000或5000次迭代的平均损失值都下降,所以曲线不会像Batch Gradient Descent的J曲线那样平滑,但5000的红色曲线要比1000的更平滑一些,1000的毛刺更多,这个很好理解(样本越多,方差自然越小)。
左上:红色曲线比蓝色曲线对应的学习率要小。这个对比表明,学习率较小时,Stochastic Gradient Descent更容易收敛至最优解。这是因为下降得慢时,该算法更容易在global minimum附近缓慢逼近global minimum。简单理解,步子小一点,到达目的地的误差就较小。
左下:蓝色1000,粉色和红色都是5000,表示两种可能性。这个图表明,当我们画的1000的结果看起来并不收敛时,画出来的5000的结果有可能收敛有可能不收敛。粉色表示不收敛,这种情况就说明算法确实有问题,可能需要改变数据特征、减小学习率等措施。红色表示依旧收敛,只是1000个样本太少,画的曲线体现不出来下降的趋势而已。
右下:蓝色曲线表示算法是发散的,应该采取减小学习率等措施。
=====================================
(三)、Mini-Batch梯度下降
一、概念
Batch Gradient Descent:每次迭代用所有的m个样本
Stochastic Gradient Descent:每次迭代仅用1个样本
Mini-Batch Gradient Descent:每次迭代用b个样本,1 < b < m
二、算法
算法如下图,与上面两种梯度下降法对比着看就很清晰了,这里不再做过多阐述。
三、优点
主要是Vectorization,即可进行矩阵向量运算,实现并行运算。而Stochastic Gradient Descent每次迭代只有一个样本计算,向量化不向量化都一样,无法实现多个样本并行计算。所以如果Mini-Batch Gradient Descent算法的向量化或并行运算做得好,会比Stochastic Gradient Descent效率更高。
四、缺点
又多了个参数b,不过这个用经验值2~100即可
=====================================
(四)、在线学习(Online Learning)
当你的数据集很大且在不断增加时,在线学习算法可以只用新增的数据对已有的模型进行微调,而不必考虑以前已经参加过模型训练的旧数据,新模型可以更好地适应新数据。举个实际的例子:
当新数据(x, y)来到时,我们用类似Stochastic Gradient Descent的方法,对模型参数进行一次迭代,更新模型。
这种在线学习方法的优势在于,can adapt to changing user preference。比如说上面的例子,经济好时人们愿意花更多的运费;反之则不然。随着经济好坏,user preference is changing,那么根据新数据的变化,我们的模型通过在线学习算法便可以捕捉到这种变化。
=====================================
(五)、MapReduce和并行计算原理
一、MapReduce原理
对于大规模机器学习,很多人认为MapReduce甚至比梯度下降法的理论知识更重要,这是因为数据多的时候运算量就很大,运算效率就成为了大规模机器学习的瓶颈。而MapReduce就是解决这个瓶颈的一个有效方法。
如下图所示,当数据量m=4亿,可以将其平均分为4个数据集,在4台机器上同时计算(即所谓的并行运算),最后在另一台机器上combine起来,这样计算效率可以优化3/4,一般不到3/4,因为数据在不同的机器间的传输耗时也是不可忽略的。类似的思路,也可以在同一台机器上,将数据集平均分配给多个CPU核进行处理,这种方式就省去了数据传输时间。
二、MapReduce的适用条件
when a learning algorithm can be expressed as computing sums of functions over the training set(一般都满足)
也就是说,当目标函数或其相对参数的偏导数又或者参数更新公式,可以写做关于样本数据的求和运算时,就可以将数据分配到多个机器或者多个core做并行运算了。