大数据下的机器学习

大数据下的机器学习

​ 要想得到一个高效的机器学习系统的最好的方式之一,用一个低偏差的学习算法,然后用很多数据来训练它。早先看到的一个例子是区分易混淆词组的例子,如有:For breakfast I ate (TWO) eggs。只要给算法很多训练的数据,它就能表现得很好(如下图,随着样本数量的增多,精确度会更高)。所以在机器学习领域有一个说法是:一般不是最好的算法胜出而是谁有更多的数据 “It’s not who has the best algorithm that wins. It’s who has the most data”。

![1.jpg](http://wx3.sinaimg.cn/mw690/7b8d2108gy1fi4mxrzulyj209g0990tg.jpg)
​ 但我们用很大的数据集也有它自己的问题,特别是计算量的问题。假设训练集大小m是100,000,000,这对于现代的数据集如人口普查或一个受欢迎的网站的浏览量来说是很常见的,假设我们要训练一个线性回归模型或是逻辑回归模型,根据梯度下降的计算公式(如下),需要一亿个训练样本的总和来计算仅仅一步的梯度下降,可想而知这样的计算量是巨大的。因此,接下来的几节中,我们将设法把这个算法题换掉或者是找一个效率更高的算法,当然在我们训练一个上亿条数据的模型之前,我们还应该问自己为什么不用几千条数据呢?

​ 也许我们可以随机从上亿条的数据集里选个一千条的子集,然后用我们的算法计算在投资精力来训练大数据的模型之前,是否值得扩大数据集的引入。在之前小节中(偏差Vs.方差)我们有一个很好的检查手段,首先随即挑选一个小一些的m等于1000的训练集,然后画出随着训练样本增大下训练集与CV交叉验证集的代价函数曲线。

![2.jpg](http://wx3.sinaimg.cn/mw690/7b8d2108gy1fi4mxsita5j20h605m0t3.jpg)
如果画出的学习曲线如左侧显示的图形一样,此时看起来像高方差的学习算法,那么我们可以增加训练集的大小来提高性能,相比之下,若画的学习曲线是右侧图形一样,这看起来像经典的高偏差学习算法,此时我们继续用m等于1000就很好了,而不是花很多精力去扩大数据集的规模。

1. 随机梯度下降(stochastic gradient descent)

​ 首先以线性回归下的梯度下降为例,一般我们看到的代价函数都是形如下图所示的弓形,画出以θ0和θ1为参数的代价函数J,这就是梯度下降算法在内层循环中需要用反复更新参数θ的值,以使得到达弓形的最底端。

![3.jpg](http://wx1.sinaimg.cn/mw690/7b8d2108gy1fi4mxt74odj20hn07ewg0.jpg)
​ 假设下图中红色箭头指向的点表示了参数的初始位置,这样在运行梯度下降的过程中,多步迭代最终会将参数锁定到全局最小值。迭代的轨迹看起来非常快地收敛到全局最小,而梯度下降法的问题是当m值很大时,计算公式中红色方框内的微分项的计算量变得很大,假如m的值为3亿,美国就有3亿人口,所以如果想要为这么多数据拟合一个线性回归模型的话,就需要对所有这3亿数据进行反复求和,这种梯度下降算法也被称为**批量梯度下降**(batch gradient descent)。所以要让算法收敛绝对需要花很长的时间,下图中到达最低点的过程对于大数据集下是很缓慢的,每迭代一部都需要花费不少的时间。
![4.jpg](http://wx2.sinaimg.cn/mw690/7b8d2108gy1fi4mxtfyebj208r06wwf8.jpg)
​ 相比于批量梯度下降,接着要介绍的方法就完全不同于这种方法,在每一步迭代中不用考虑全部的训练样本,而仅需要考虑一个训练样本,假设函数$h(x^{(i)})$跟实际输出$y^{(i)}$的误差的平方,实际上测量的是在某个样本($x^{(i)}$, $y^{(i)}$)上的表现,总体的代价函数J_train可以被写成下面这样等效的形式。
![5.jpg](http://wx3.sinaimg.cn/mw690/7b8d2108gy1fi4mxu22bij20hn0390sy.jpg)
第一步,将所有数据打乱,将所有m个训练样本重新排列

第二步,
repeat
{
for i=1,...,m
{
\(\theta_j=\theta_j-\alpha(h_\theta(x^{(i)})-y^{(i)})*x_i^{(i)}\)
(for j=0,...,n)
}
}

​ 解释一下:首先是第一组训练样本(x(1),y(1)),对它的代价函数计算一小步的梯度下降,换句话说我们只关注第一个样本,然后把参数θ稍微修改一点,使其对第一个训练样本的拟合变得好一点。完成这个内层循环以后,再转向第二个训练样本,进步一小步也就是稍微把参数修改一点,让它对第二个样本的拟合更好一点,做完第二个再转向第三个训练样本,同样还是修改参数让它更好的拟合第三个训练样本以此类推直到完成所有的训练集。随机梯度下降跟批量梯度下降不同在于随机梯度下降不需要等到对所有m个训练样本求和来得到梯度,而是只需要对单个训练样本(m=1)求出这个梯度。

​ 当使用批量梯度下降的时候,需要同时考虑所有的训练样本数据,批量梯度下降的收敛过程会倾向于一条近似的直线(下图黄色曲线段),一直找到全局最小值。与此不同,在随机梯度下降中每一次迭代都会更快,因为我们不需要对所有训练样本进行求和每一次迭代只需要保证对一个训练样本拟合好就行,如下图,如果我们从红色X点开始执行随机梯度下降,第一次迭代可能会让参数朝着一个方向移动,然后第二次迭代只考虑第二个训练样本可能朝向了一个错误的方向,第三次迭代方向又会重新修正,然后再考虑第四个训练样本、第五第六第七等等。

![6.jpg](http://wx3.sinaimg.cn/mw690/7b8d2108gy1fi4mxujx1vj208006bt9f.jpg)
​ 实际上,随机梯度下降是在某个靠近全局最小值的区域内徘徊,而不是直接逼近全局最小值并停留在那点。但实际上这并没有多大问题,只要参数最终移动到某个非常靠近全局最小值的区域内,这也会得出一个较为不错的假设函数。

​ 最后,在随机梯度下降中我们有一个外层循环,它决定了内层循环的执行次数,所以外层循环执行的次数取决于训练样本的大小,通常1次到10次之间的取值是比较典型的。因此如果我们有非常大量的数据,比如美国普查的人口数据(3亿人口数据)的例子,每次你只需要考虑取1次,这里的i就是从1到3亿,所以可能每次只需要考虑一个训练样本,就能训练出非常好的假设。

随即梯度下降的收敛

​ 如何确保调试过程已经完成并且能正常收敛呢?还有怎样调整随机梯度下降中学习速率α的值?

​ 回到批量梯度下降的算法,我们确定梯度下降已经收敛的一个标准方法是画出最优化的代价函数,关于迭代次数的变化,我们要保证代价函数在每一次迭代中都是下降的,当训练集比较小的时候我们不难完成,因为要计算这个求和\(J_{train}(\theta)=\frac{1}{2m}\Sigma_{i=1}^m(h_\theta(x^{(i)})-y^{(i)})^2\)是比较方便的,但当训练集非常大的时候,我们不能定时地暂停算法来计算一遍这个求和,因为这个求和需要考虑整个的训练集。

​ 因此对于随机梯度下降算法,为了检查算法是否收敛,我们可以进行以下的工作,这里继续沿用之前定义的cost函数,即\(cost(\theta,(x^{(i)},y^{(i)}))=\frac{1}{2}(h_\theta(x^{(i)})-y^{(i)})^2\)
当随机梯度下降法对训练集进行扫描时,即在我们使用某个样本(\(x^{(i)},y^{(i)}\))来更新θ前,先计算出\(cost(\theta,(x^{(i)},y^{(i)}))\)。原因是如果我们用这个样本更新θ以后再计算\(cost(\theta,(x^{(i)},y^{(i)}))\),那么它在这个训练样本上的表现就比实际上变得更好了。

​ 最后为了检查随机梯度下降的收敛性,我们在每1000次迭代运算后,对最后1000个样本的cost值求平均后画出来,通过观察这些画出来的图进一步检查出随机梯度下降是否在收敛。

​ 下图是假如已经画出了最后1000组样本的cost函数的平均值,由于它们都只是1000组样本的平均值,因此它们看起来有一点嘈杂。

![0.jpg](http://wx2.sinaimg.cn/mw690/7b8d2108gy1fi4mxrkp3zj20iy0a1q5v.jpg)
  • 假如得到上图a这样的图像,看起来是有噪声的,因为它是在一小部分样本比如1000组样本中求的平均值,如果得到图a中蓝色曲线,那么可以判断这个算法是在下降的,从某一个点开始变得平缓说明学习算法已经收敛了,图a中红色曲线为使用更小的学习速率\(\alpha\),可以看到算法的学习变得更慢了,因此代价函数的下降也变慢了,但由于使用了更小的学习速率,所以很有可能让算法收敛得更好一点,因随机梯度下降不是直接收敛到全局最小值,而是在局部最小附近反复振荡,所以使用一个更小的学习速率最终的振荡就会更小。
  • 图b中蓝色曲线是运行随机梯度下降然后对1000组样本取cost函数的平均值,看起来已经收敛了,如果把这个数1000提高到5000组样本,此时会得到图b中红色曲线,是一条更平滑的曲线,当然它的缺点就是每5000个样本才能得到一个数据点,因此关于学习算法表现的反馈就显得有一些“延迟”。
  • 图c中的蓝色曲线看起来一直比较平坦并没有下降,如果用更大量的样本进行平均时会观察到红线所示的情况,实际上代价函数是在下降的,只不过蓝线用来平均的样本数量太小了,因此蓝线太嘈杂不易看出代价函数的的下降趋势。所以可能用5000组样本来平均比用1000组样本来平均更能看出趋势。当然如果使用一个较大的样本数量比如我们用5000个样本来平均,可能发现它还是比较平坦,且即使用更多的训练样本,效果依然比较平坦,那可能就更肯定地说明算法确实没怎么学习好,那么就需要调整学习速率或者改变特征变量等等。
  • 对于图d中的曲线实际上是在上升,很明显算法正在发散,那么此时要做的事就是用一个更小一点的学习速率α。

​ 最后关于学习速率的问题,我们已经知道当运行随机梯度下降时,算法会从某个点开始,然后曲折地逼近最小值,但它不会真的收敛,而是一直在最小值附近徘徊。因此最终得到的参数实际上只是接近全局最小值而不是真正的全局最小值,在大多数随机梯度下降法的典型应用中学习速率α一般是保持不变的,此时迭代的过程如下图:

![7.jpg](http://wx3.sinaimg.cn/mw690/7b8d2108gy1fi4mxuwczoj208006eaak.jpg)
​ 如果想随着随机梯度下降,慢慢收敛到全局最小值,我们可以随时间的变化减小学习速率α的值,所以一种典型的方法来设置α的值:$\alpha = \frac{const1}{迭代次数+const2}$。这个公式起作用的原因是随着算法的运行迭代次数会越来越大因此学习速率α会慢慢变小,因此α在每一步都会越来越小直到最终收敛到全局最小值。
![8.jpg](http://wx1.sinaimg.cn/mw690/7b8d2108gy1fi4mxvqmyaj208006fwez.jpg)
​ 但是这个公式中确定这两个常数需要更多的工作量,并且我们通常也对能够很接近全局最小值的参数已经很满意,因此实际上很少采用逐渐减小α的值的方法。

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个样本做一个实际上是梯度下降的更新,\(\theta_j:=\theta_j-\alpha \frac{1}{10}\Sigma_{k=1}^{i+9}(h_\theta(x^{(k)})-y^{(k)})x_j^{(k)}\)。在这之后我们将要把i加10继续处理接下来的10个样本(i:=i+10),然后像这样一直持续更新。

​ 简单地,假设小批量规模b为10和一个大小为1000的训练集,我们接下来要做:


Repeat
{
for i=1,11,21,31,...,991
{
\(\theta_j:=\theta_j-\alpha \frac{1}{10}\Sigma_{k=1}^{i+9}(h_\theta(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;\theta)\)

​ 我们先来考虑逻辑回归:

Repeat forever{
获取关于新用户的标记样本(x,y) ;
利用(x,y)更新\(\theta\)
-->\(\theta_j:=\theta_j-\alpha(h_\theta(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;\theta)\) 。其实也称作点击率(Click Through Rate-CTR)预估。

​ 所以这就是在线学习机制,这个算法与随机梯度下降算法非常类似,唯一的区别的是我们不会使用一个固定的数据集,而是获取一个用户样本从那个样本中学习,接着丢弃那个样本并继续下去。因此在线学习对于有一个连续的数据流的问题是非常值得考虑的,当然在线学习还有的优点就是对于尝试预测的事情在缓慢变化,就像用户的品味在缓慢变化时,在线学习算法可以慢慢地调试所学习到的假设将其调节更新到最新的用户行为。

4.映射约减(map-reduce)

​ 有些机器学习问题太大,它涉及的数据量非常巨大以至于不论使用何种算法都不希望只使用一台计算机来处理这些数据。源于Jeffrey Dean和Sanjay Ghemawat这两位研究者的映射约减(map-reduce) 是进行大规模机器学习的有效方法。

​ 假设我们要拟合一个线性回归模型,为了使分析更加简单和清晰我们假定只有400个样本,即m=400这样一来梯度下降学习算法公式为:\(\theta_j:=\theta_j-\alpha\frac{1}{100}\Sigma_{j=1}^{100}(h_\theta(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个样本,它们只用完成四分之一的工作量,也许可以将运算速度提高到原来的四倍。

![1.jpg](http://wx4.sinaimg.cn/mw690/7b8d2108gy1fi5hbfbbqaj20i207btcb.jpg)
​ 最后,把这些临时变量收集到一起,如上图右侧,将它们送到一个中心计算服务器,这台服务器会将这些临时变量合并起来,具体地,根据红圈中的公式来更新参数θj。

​ 总结一下,如下图:有一些训练样本,如果我们希望使用4台计算机并行的运行机器学习算法,那么可以将训练样本尽量均匀地等分成4份,后将这4个训练样本的子集送给4台不同的计算机,每一台计算机对四分之一的训练数据进行求和运算,最后这4个求和结果被送到一台中心计算服务器,将结果进行汇总。

![2.jpg](http://wx3.sinaimg.cn/mw690/7b8d2108gy1fi5hbfomuvj20db07fq3p.jpg)
​ 特别地,如果没有网络延时也不考虑通过网络来回传输数据所消耗的时间,那么可能得到4倍的加速,当然在实际工作中因为网络延时、数据汇总额外消耗时间以及其他的一些因素,能得到的加速总是略小于4倍,但是不管怎么说这种映射化简算法确实让我们能够处理无法处理的大规模数据。

​ 如果现在打算将映射约减技术用于加速某个机器学习算法,那么需要问自己一个很关键的问题,自己的机器学习算法是否可以表示为训练样本的某种求和。事实证明很多机器学习算法的确可以表示为关于训练样本的函数求和,那么当然可以考虑使用映射化简技术。

​ 看一个例子,假设我们想使用逻辑回归算法(当然可以对于其他高级优化算法如:LBFGS算法或者共轭梯度算法等等),它的代价函数为下式,可以表示为训练样本上的求和。因此,如果想在10台计算机上并行计算,那么需要将训练样本分给这10台计算机,让每台计算机计算10份之一训练数据。对于逻辑回归的偏导数计算同样可以表示为训练数据的求和。因此,和之前一样,让每台计算机只计算部分训练数据上的和,最后当这些求和计算完成之后,将结果发送到一台中心计算服务器上,这台服务器将对结果进行再次求和,得到了总的代价函数值以及总的偏导数值。

![3.jpg](http://wx2.sinaimg.cn/mw690/7b8d2108gy1fi5hbfy9udj20e303iq32.jpg)
​ 更广义的讲,通过将机器学习算法表示为求和的形式,或者是训练数据的函数求和形式,就可以运用映射化简技术来将算法并行化以便处理大规模数据。
![4.jpg](http://wx1.sinaimg.cn/mw690/7b8d2108gy1fi5hbgltluj20d607baat.jpg)
​ 当然对于只有一台计算机,我们也可以运用这种技术,具体来说,现在的许多计算机都是多核的,那么可以使用一台四核的计算机,将训练样本分成几份,然后让每一个核处理其中一份子样本,这样在单台计算机或者单个服务器上也可以利用映射约减技术来划分计算任务,此外还多了一个优势,如不需要担心网络延时问题。当然这个前提是我们有一台多核计算机并且使用了某个线性代数函数库,某些线性代数函数库也会自动利用多个核并行地完成线性代数运算。
posted @ 2017-08-01 23:25  SrtFrmGNU  阅读(625)  评论(0编辑  收藏  举报