大数据下的机器学习
要想得到一个高效的机器学习系统的最好的方式之一,用一个低偏差的学习算法,然后用很多数据来训练它。早先看到的一个例子是区分易混淆词组的例子,如有:For breakfast I ate (TWO) eggs。只要给算法很多训练的数据,它就能表现得很好(如下图,随着样本数量的增多,精确度会更高)。所以在机器学习领域有一个说法是:一般不是最好的算法胜出而是谁有更多的数据 “It’s not who has the best algorithm that wins. It’s who has the most data”。
也许我们可以随机从上亿条的数据集里选个一千条的子集,然后用我们的算法计算在投资精力来训练大数据的模型之前,是否值得扩大数据集的引入。在之前小节中(偏差Vs.方差)我们有一个很好的检查手段,首先随即挑选一个小一些的m等于1000的训练集,然后画出随着训练样本增大下训练集与CV交叉验证集的代价函数曲线。
1. 随机梯度下降(stochastic gradient descent)
首先以线性回归下的梯度下降为例,一般我们看到的代价函数都是形如下图所示的弓形,画出以θ0和θ1为参数的代价函数J,这就是梯度下降算法在内层循环中需要用反复更新参数θ的值,以使得到达弓形的最底端。
第二步,
repeat
{
for i=1,...,m
{
( heta_j= heta_j-alpha(h_ heta(x^{(i)})-y^{(i)})*x_i^{(i)})
(for j=0,...,n)
}
}
解释一下:首先是第一组训练样本(x(1),y(1)),对它的代价函数计算一小步的梯度下降,换句话说我们只关注第一个样本,然后把参数θ稍微修改一点,使其对第一个训练样本的拟合变得好一点。完成这个内层循环以后,再转向第二个训练样本,进步一小步也就是稍微把参数修改一点,让它对第二个样本的拟合更好一点,做完第二个再转向第三个训练样本,同样还是修改参数让它更好的拟合第三个训练样本以此类推直到完成所有的训练集。随机梯度下降跟批量梯度下降不同在于随机梯度下降不需要等到对所有m个训练样本求和来得到梯度,而是只需要对单个训练样本(m=1)求出这个梯度。
当使用批量梯度下降的时候,需要同时考虑所有的训练样本数据,批量梯度下降的收敛过程会倾向于一条近似的直线(下图黄色曲线段),一直找到全局最小值。与此不同,在随机梯度下降中每一次迭代都会更快,因为我们不需要对所有训练样本进行求和每一次迭代只需要保证对一个训练样本拟合好就行,如下图,如果我们从红色X点开始执行随机梯度下降,第一次迭代可能会让参数朝着一个方向移动,然后第二次迭代只考虑第二个训练样本可能朝向了一个错误的方向,第三次迭代方向又会重新修正,然后再考虑第四个训练样本、第五第六第七等等。
最后,在随机梯度下降中我们有一个外层循环,它决定了内层循环的执行次数,所以外层循环执行的次数取决于训练样本的大小,通常1次到10次之间的取值是比较典型的。因此如果我们有非常大量的数据,比如美国普查的人口数据(3亿人口数据)的例子,每次你只需要考虑取1次,这里的i就是从1到3亿,所以可能每次只需要考虑一个训练样本,就能训练出非常好的假设。
随即梯度下降的收敛
如何确保调试过程已经完成并且能正常收敛呢?还有怎样调整随机梯度下降中学习速率α的值?
回到批量梯度下降的算法,我们确定梯度下降已经收敛的一个标准方法是画出最优化的代价函数,关于迭代次数的变化,我们要保证代价函数在每一次迭代中都是下降的,当训练集比较小的时候我们不难完成,因为要计算这个求和(J_{train}( heta)=frac{1}{2m}Sigma_{i=1}^m(h_ heta(x^{(i)})-y^{(i)})^2)是比较方便的,但当训练集非常大的时候,我们不能定时地暂停算法来计算一遍这个求和,因为这个求和需要考虑整个的训练集。
因此对于随机梯度下降算法,为了检查算法是否收敛,我们可以进行以下的工作,这里继续沿用之前定义的cost函数,即(cost( heta,(x^{(i)},y^{(i)}))=frac{1}{2}(h_ heta(x^{(i)})-y^{(i)})^2),
当随机梯度下降法对训练集进行扫描时,即在我们使用某个样本((x^{(i)},y^{(i)}))来更新θ前,先计算出(cost( heta,(x^{(i)},y^{(i)})))。原因是如果我们用这个样本更新θ以后再计算(cost( heta,(x^{(i)},y^{(i)}))),那么它在这个训练样本上的表现就比实际上变得更好了。
最后为了检查随机梯度下降的收敛性,我们在每1000次迭代运算后,对最后1000个样本的cost值求平均后画出来,通过观察这些画出来的图进一步检查出随机梯度下降是否在收敛。
下图是假如已经画出了最后1000组样本的cost函数的平均值,由于它们都只是1000组样本的平均值,因此它们看起来有一点嘈杂。
- 假如得到上图a这样的图像,看起来是有噪声的,因为它是在一小部分样本比如1000组样本中求的平均值,如果得到图a中蓝色曲线,那么可以判断这个算法是在下降的,从某一个点开始变得平缓说明学习算法已经收敛了,图a中红色曲线为使用更小的学习速率(alpha),可以看到算法的学习变得更慢了,因此代价函数的下降也变慢了,但由于使用了更小的学习速率,所以很有可能让算法收敛得更好一点,因随机梯度下降不是直接收敛到全局最小值,而是在局部最小附近反复振荡,所以使用一个更小的学习速率最终的振荡就会更小。
- 图b中蓝色曲线是运行随机梯度下降然后对1000组样本取cost函数的平均值,看起来已经收敛了,如果把这个数1000提高到5000组样本,此时会得到图b中红色曲线,是一条更平滑的曲线,当然它的缺点就是每5000个样本才能得到一个数据点,因此关于学习算法表现的反馈就显得有一些“延迟”。
- 图c中的蓝色曲线看起来一直比较平坦并没有下降,如果用更大量的样本进行平均时会观察到红线所示的情况,实际上代价函数是在下降的,只不过蓝线用来平均的样本数量太小了,因此蓝线太嘈杂不易看出代价函数的的下降趋势。所以可能用5000组样本来平均比用1000组样本来平均更能看出趋势。当然如果使用一个较大的样本数量比如我们用5000个样本来平均,可能发现它还是比较平坦,且即使用更多的训练样本,效果依然比较平坦,那可能就更肯定地说明算法确实没怎么学习好,那么就需要调整学习速率或者改变特征变量等等。
- 对于图d中的曲线实际上是在上升,很明显算法正在发散,那么此时要做的事就是用一个更小一点的学习速率α。
最后关于学习速率的问题,我们已经知道当运行随机梯度下降时,算法会从某个点开始,然后曲折地逼近最小值,但它不会真的收敛,而是一直在最小值附近徘徊。因此最终得到的参数实际上只是接近全局最小值而不是真正的全局最小值,在大多数随机梯度下降法的典型应用中学习速率α一般是保持不变的,此时迭代的过程如下图:
2.小批量梯度下降(Mini-batch gradient descent)
总结一下,在批量梯度下降中每次迭代我们都要用所有的m个样本,而在随机梯度下降中,每次迭代我们只用一个样本,小批量梯度下降做的介于它们之间,准确地说每次迭代使用b个样本,b是一个叫做"小批量规模"的参数。所以小批量梯度算法介于随机梯度下降和批量梯度下降之间, b的一个标准的取值可能是2到100之间的任何一个数,这是小批量梯度算法的一个典型的取值区间。
算法思想是我们每次用b个样本而不是每次用1个或者m个,所以正式地,假设b的取值是10,所以首先从训练集中取出10个样本,假设训练集是样本((x^{(i)},y^{(i)}))的集合,所以10个样本最多索引值达到((x^{(i+9)},y^{(i+9)}))。现在我们要用这10个样本做一个实际上是梯度下降的更新,( heta_j:= heta_j-alpha frac{1}{10}Sigma_{k=1}^{i+9}(h_ heta(x^{(k)})-y^{(k)})x_j^{(k)})。在这之后我们将要把i加10继续处理接下来的10个样本(i:=i+10),然后像这样一直持续更新。
简单地,假设小批量规模b为10和一个大小为1000的训练集,我们接下来要做:
Repeat
{
for i=1,11,21,31,...,991
{
( heta_j:= heta_j-alpha frac{1}{10}Sigma_{k=1}^{i+9}(h_ heta(x^{(k)})-y^{(k)})x_j^{(k)})
}
}
一般来说小批量梯度下降可能比随机梯度下降好的原因更可能是:拥有好的向量化计算库,此时小批量b=10个样本求和可以用一种更向量化的方法实现,即允许部分并行计算10个样本的和,换句话说,使用好的数值代数库来部分地并行计算b个样本。
小批量梯度下降的一个缺点是有一个额外的参数b,所以需要花费时间调试b的大小。通常b的取值在2到100之间的任何一个数都可能是合理的。因此我们选择b的值如果在有一个好的向量化实现条件下,有时它可以比随机梯度下降和批量梯度下降更快。
3.在线学习(online learning)
传统中狭义的machine learning技术,是利用一批已有的数据,学习到一个固化的模型。该模型的泛化能力,不仅依赖于精心设计的模型,更需要一次性灌注海量数据来保证。而online learning则不需要启动数据,或只需少量启动数据,通过探索,反馈,修正来逐渐学习。相比之下,online learning对数据的使用更加灵活,由此带来的好处,不仅是能够减轻更新模型时的计算负担,更可以提高模型的时效性,这更加符合人的学习方式。链接
假定有一个提供运输服务的公司,为用户将包裹从A地运到B地,假定有一个网站让用户可多次登陆,用户会在网站上说明想从哪里寄出包裹,以及包裹要寄到哪里去,即出发地与目的地,然后网站需要开出运输包裹的的服务价格,根据开给用户的这个价格,我们设定正样样为:用户接受这个运输服务(y=1),负样本为:用户拒绝(y=0)。
所以我们想要一个学习算法来帮助我们优化给用户开出的价格,现在假定我们找到了一些获取用户特点的方法,比如包裹的起始地、目的地以及我们提供给他们的运送包裹的价格,我们要学习在给出的价格下他们将会选择运输包裹的几率(p(y=1|x; heta))。
我们先来考虑逻辑回归:
Repeat forever{
获取关于新用户的标记样本(x,y) ;
利用(x,y)更新( heta):
-->( heta_j:= heta_j-alpha(h_ heta(x)-y)x_j)
}
注意:首先式中"一直重复"代表着网站会一直继续保持在线学习,其次这里样本不再是((x^{(i)},y^{(i)})),而是(x,y),因为在线学习机制中我们实际上丢弃了获取一个固定的数据集这样的概念,取而代之的是当我们获取一个样本,然后利用那个样本获取信息学习,接着会丢弃这个样本即永远不会再使用它,这就是为什么我们在一个时间点只会处理一个样本的原因。
而且如果真的运行一个大型网站,在这个网站里有一个连续的用户流登陆网站,那么这种在线学习算法是一种非常合理的算法,因为数据本质上是自由的,如果有如此多的数据,而数据本质上是无限的,那么没必要重复处理一个样本。当然如果只有少量的用户,那么我们最好保存好所有的数据,存放在一个固定的数据集里,然后对这个数据集使用某种算法。
还有一个对于产品搜索上的例子:
我们想要使用一种学习机制来学习如何反馈给用户好的搜索列表,比如有一个在线售卖手机的店铺,web上有一个用户界面可以让用户登陆店铺网站并且键入一个搜索条目,例如“安卓手机 1080p 摄像头”,那么1080p是指对应于摄像头的手机参数,假定我们的商铺中有一百部电话,且出于我们的网站设计,当一个用户键入一个关键词,我们会找到关于关键词的十部不同手机的列表,现在我们想要做的是拥有一个在线学习机制以帮助我们找到在这100部手机中哪十部手机是真正值得反馈给用户的。
接下来要说的是一种解决问题的思路:对于每部手机以及一个给定的用户搜索词,我们可以构建一个特征矢量x,那么这个特征矢量x可能会抓取手机的各种特点,我们还需获取这个用户搜索关键词中有多少个词可以与这部手机的名字或名字相匹配,所以特征矢量x获取手机的特点而且它会获取这部手机与搜索关键词之间的结果在各个方面的匹配程度。
我们想要估测一个概率,具体指用户将会点进某一个特定的手机的链接,所以我们定义y=1时,指用户点击了手机的链接,而y=0是指用户没有点击链接。我们想要做的就是学习到用户将会点击某一个给出的特定的手机的概率(p(y=1|x; heta)) 。其实也称作点击率(Click Through Rate-CTR)预估。
所以这就是在线学习机制,这个算法与随机梯度下降算法非常类似,唯一的区别的是我们不会使用一个固定的数据集,而是获取一个用户样本从那个样本中学习,接着丢弃那个样本并继续下去。因此在线学习对于有一个连续的数据流的问题是非常值得考虑的,当然在线学习还有的优点就是对于尝试预测的事情在缓慢变化,就像用户的品味在缓慢变化时,在线学习算法可以慢慢地调试所学习到的假设将其调节更新到最新的用户行为。
4.映射约减(map-reduce)
有些机器学习问题太大,它涉及的数据量非常巨大以至于不论使用何种算法都不希望只使用一台计算机来处理这些数据。源于Jeffrey Dean和Sanjay Ghemawat这两位研究者的映射约减(map-reduce) 是进行大规模机器学习的有效方法。
假设我们要拟合一个线性回归模型,为了使分析更加简单和清晰我们假定只有400个样本,即m=400这样一来梯度下降学习算法公式为:( heta_j:= heta_j-alphafrac{1}{100}Sigma_{j=1}^{100}(h_ heta(x^{(i)})-y^{(i)})x_j^{(i)}),公式中的求和是i从1取到400,如果m很大那么这一步的计算量将会很大。
这里我们可以采用映射约减,假设我们有一个训练样本我们将它表示为下图方框中的一系列x~y数据对,从((x^{(1)},y^{(1)}))开始涵盖所有的400个样本,根据映射化简的思想一种解决方案是将训练集划分成几个不同的子集:图中假定有4台计算机来并行的处理训练数据,因此将数据划分成4份,分给这4台计算机。第一台将处理前100个训练样本,计算临时变量(temp_j^{(1)}),这里的上标(1)表示第一台计算机,其下标为j为从1到100的求和,相似的还有机2、3、4分别计算(temp_j^{(2)})、(temp_j^{(3)})、(temp_j^{(4)})。这样现在每台计算机不用处理400个样本,而只处理100个样本,它们只用完成四分之一的工作量,也许可以将运算速度提高到原来的四倍。
总结一下,如下图:有一些训练样本,如果我们希望使用4台计算机并行的运行机器学习算法,那么可以将训练样本尽量均匀地等分成4份,后将这4个训练样本的子集送给4台不同的计算机,每一台计算机对四分之一的训练数据进行求和运算,最后这4个求和结果被送到一台中心计算服务器,将结果进行汇总。
如果现在打算将映射约减技术用于加速某个机器学习算法,那么需要问自己一个很关键的问题,自己的机器学习算法是否可以表示为训练样本的某种求和。事实证明很多机器学习算法的确可以表示为关于训练样本的函数求和,那么当然可以考虑使用映射化简技术。
看一个例子,假设我们想使用逻辑回归算法(当然可以对于其他高级优化算法如:LBFGS算法或者共轭梯度算法等等),它的代价函数为下式,可以表示为训练样本上的求和。因此,如果想在10台计算机上并行计算,那么需要将训练样本分给这10台计算机,让每台计算机计算10份之一训练数据。对于逻辑回归的偏导数计算同样可以表示为训练数据的求和。因此,和之前一样,让每台计算机只计算部分训练数据上的和,最后当这些求和计算完成之后,将结果发送到一台中心计算服务器上,这台服务器将对结果进行再次求和,得到了总的代价函数值以及总的偏导数值。