[C12] 大规模机器学习(Large Scale Machine Learning)
大规模机器学习(Large Scale Machine Learning)
大型数据集的学习(Learning With Large Datasets)
如果你回顾一下最近5年或10年的机器学习历史。学习算法现在比5年前更好地工作的原因之一就是我们现在拥有了大量的数据,可以用来训练我们的算法。那么为什么要使用这么大的数据集呢?我们已经看到,获得高性能机器学习系统的最佳方法之一就是采用低偏差的学习算法,并且用大量的数据进行训练。
因此,如上图中,我们已经看到过的一个早期的在可混淆的单词之间进行分类的例子。早餐时,我吃了(两个)鸡蛋
,如你所知,只要给算法提供大量的数据,它似乎做得很好。因此,这种结果导致机器学习中的说法往往不是谁拥有最好的算法获胜,而是取决于谁拥有最多的训练数据。
但是,使用大型数据集进行学习会带来其独特的问题,特别是计算问题。假设你的训练集大小为 m = 100,000,000。对于许多现代数据集而言,这实际上是非常现实的。如果你查看美国人口普查数据集,如果你知道美国有 3 亿人,你通常可以获得数亿条记录。如果你查看热门网站获得的流量,你也可以轻松获得比数亿个样本大得多的训练集。并且假设你想要训练线性回归模型,或者可能是逻辑回归模型,在这种情况下,如下面的梯度下降规则:
\(\theta_j := \theta_j - \alpha\frac{1}{m}\sum\limits_{i = 1}^{m}\biggl(h_\theta(x^{(i)}) - y^{(i)}\biggl)\cdot x_j^{(i)}\)
当 \(m\) 是一亿时,需要进行一亿次以上的求和,以便计算导数项,并且还只是计算每一次更新中的一个 \(\theta\) 值。
接下来我们会谈论如何找到更有效的方法来应对大数据集训练。
当然,在我们应用大数据集训练模型之前,也该问问自己,为什么不用 1000 个样本训练呢? 也许可以从 1 亿样本中随机抽取 1000 个样本,然后在这 1000 个样本上训练我们的算法。
如之前所讲过的,在投入大量精力进行实际开发之前,我们可以使用有效的方法(学习曲线)来检查使用小的训练集是否也可以做的很好。
如果你的训练集学习曲线 \(J_{train}(\theta)\) 以及交叉验证集学习曲线 \(J_{cv}(\theta)\) 如上左图所示,那么这看起来像一个处于高方差状态的学习算法,我们可以很自信的增加额外的训练样本来提高其性能。相反,如果你画出的学习曲线如上面右图所示,那么这看起来像一个标准的处于高偏差状态的学习算法。此种情况,如你所知,即使增加样本数量,而且即使增加到 1 亿个样本,也未必能对算法的性能有所提升。真正要做的就是添加额外的特征,比如说在神经网络算法中添加额外的隐藏单元之类的等等,如果你这样做了,最终你可能会得到一个更接近于上边左图中的情况(由高偏差过度到了过拟合),而此时,或许你可以考虑再添加额外的训练样本(\(m > 1000\))来提升算法性能。
综上,在大规模机器学习中,我们更喜欢用 计算上合理
或 计算上有效
的方式来处理非常大的数据集。
随机梯度下降法(Stochastic Gradient Descent)
Batch Gradient Descent : use all examples in each iteration
Stochastic Gradient Descent : use 1 example in each iteration
Mini-batch Gradient Descent : use \(b\) examples in each iteration ($ 2 \leq b \leq 100$)
随机梯度下降中,定义 Cost 为一个单一的训练样本的代价:
\(cost\Big( \theta, \left( {x}^{(i)} , {y}^{(i)} \right) \Big) = \frac{1}{2}\Big( {h}_{\theta}\left({x}^{(i)}\right)-{y}^{{(i)}} \Big)^{2}\)
-
Randomly shuffle (reorder) training examples
-
Repeat (usually anywhere between 1 - 10 times){
for \(i = 1:m\){
\(\quad\)for \(j = 0:n\){
\(\quad\quad\)\(\theta:={\theta}_{j}-\alpha\Big( {h}_{\theta}\left({x}^{(i)}\right)-{y}^{(i)} \Big){{x}_{j}}^{(i)}\)
\(\quad\)}
}
随机梯度下降算法在每一次计算之后便更新参数 \({{\theta }}\) ,而不需要首先将所有的训练集求和,在梯度下降算法还没有完成一次迭代时,随机梯度下降算法便已经走出了很远。但是这样的算法存在的问题是,不是每一步都是朝着”正确”的方向迈出的。因此算法虽然会逐渐走向全局最小值的位置,但是可能无法站到那个最小值的那一点,而是在最小值点附近徘徊。
小批量梯度下降(Mini-Batch Gradient Descent)
Mini-Batch 梯度下降算法是介于 Batch 梯度下降 和 随机梯度下降算法之间的算法,每次迭代使用 \(b\) 个样本。
Repeat {
\(\quad\)for \(i = 1:m\){
\(\quad\quad\)for \(j = 0:n\){
\(\quad\quad\quad \theta:={\theta}_{j}-\alpha\frac{1}{b}\sum_\limits{k=i}^{i+b-1}\left( {h}_{\theta}\left({x}^{(k)}\right)-{y}^{(k)} \right){{x}_{j}}^{(k)}\)
\(\quad\quad\)}
$\quad\quad i +=10 $
\(\quad\)}
}
通常我们会令 \(b\) 在 2-100 之间。如果使用的线性代数函数库有比较好的向量化实现,那么算法总体表现可能会优于随机梯度下降。
随机梯度下降收敛(Stochastic Gradient Descent Convergence)
Checking for convergence
Batch gradient descent:
\(\quad\)Plot \(J_{train}(\theta)\) as a function of the number of iterations of gradient descent.
\(\quad\)\(J_{train}(\theta)=\frac{1}{2m}\sum\limits_{i=1}^{m}\big(h_{\theta}(x^{(i)})-y^{(i)}\big)^2\)
Stochastic gradient descent:
\(\quad\)\(cost(\theta,(x^{(i)},y^{(i)}))=\frac{1}{2}\big(h_{\theta}(x^{(i)})-y^{(i)}\big)^2\)
\(\quad\)During learning, compute \(cost(\theta,(x^{(i)},y^{(i)}))\) before updating \(\theta\) using \((x^{(i)},y^{(i)})\).
\(\quad\)Every 1000 iterations (say), plot \(cost(\theta,(x^{(i)},y^{(i)}))\) averaged over the last 1000 examples processed by algorithm.
下面列举几种情况:
Plot \(cost(\theta,(x^{(i)},y^{(i)}))\) averaged over the last 1000 (say) examples
-
图1,蓝色线为每 1000 个样本计算 cost 平均值,如果减小 \(\alpha\),则会得到类似红色的曲线,波动范围更小,而且可能最终会获得更小的 cost。
-
图2,蓝色线为每 1000 个样本计算 cost 平均值,如果每 5000 个样本计算一次 cost 平均值,则会得到类似红色的曲线,更加的平滑。
-
图3,蓝色线为每 1000 个样本计算 cost 平均值,但是蓝色线噪声大,波动大,不容易观测到 cost 的下降情况。如果每 5000 个样本计算一次 cost 平均值,得到红色线,说明 cost 还是下降的,如果得到的是洋红色的线,可以看到几乎是平的,说明梯度下降可能存在问题。
-
图4,蓝色线上升,梯度下降算法处于发散状态,此时可以减小 \(\alpha\) 的值。
当 \(\alpha\) 是恒定不变的变量时,最优解可能会在最低点附近徘徊。如下图:
Learing rate \(\alpha\) is typically held constant.
Can slowly decrease \(\alpha\) over time if we want \(\theta\) to converge.
(E.g. \(\alpha = \frac{\mathrm{const1}}{\mathrm{iterationNumber + const2}}\))
如下图:当随着迭代次数的增加,\(\alpha\) 逐渐减小趋近于 0,那么最终的解也会强行向全局最小逼近。
但很多时候实际上人们并不喜欢这么做,因为它会额外多出两个参数 常量1
和 常量2
,需要更多额外的工作。而且通常情况得到的参数值,已经很接近全局最小值的程度了,已经足够令我们满意了。因此我们很少使用这种逐渐减小 \(\alpha\) 值得方法,而是让学习率 \(\alpha\) 保持一个常数。不过两种方法都有人在用。
在线学习(Online Learning)
在线学习环境允许我们对连续不断的数据流进行建模,我们希望算法可以从中学习。 今天,有许多大型的网站或网络公司使用不同版本的在线学习算法,从大量的用户那里学习。 具体来说,如果你有连续的用户来到你的网站,从而产生连续的数据流,那么你可以使用在线学习算法从数据流中学习用户偏好,然后使用这些信息来优化一些关于网站的决策。
假定你有一个提供运输服务的公司,用户们来向你询问把包裹从 A 地运到 B 地的服务,同时假定你有一个网站,让用户们可多次登陆,然后他们告诉你,他们想从哪里寄出包裹,以及包裹要寄到哪里去,也就是出发地与目的地,然后你的网站开出运输包裹的的服务价格。比如,我会收取 50 来运输你的包裹,我会收取 20 之类的,然后根据你开给用户的这个价格,用户有时会接受这个运输服务,那么这就是个正样本,有时他们会走掉,然后他们拒绝购买你的运输服务,所以,让我们假定我们想要一个学习算法来帮助我们,优化我们想给用户开出的价格,提高成交的概率。
在线学习环境,实际上是放弃了固定训练集的概念。许多在线网站都有持续不断的用户流,对于每一个用户,网站希望能不将数据存储到数据库中,也可以顺利地进行算法学习。
假使我们正在经营一家物流公司,每当一个用户询问从地点 A 至地点 B 的快递费用时,我们给用户一个报价,该用户可能选择接受(\(y=1\))或不接受(\(y=0\))。
现在,我们希望构建一个模型,来预测用户接受报价使用我们的物流服务的可能性。因此报价是我们的一个特征,其他特征为距离,起始地点,目标地点以及特定的用户数据。模型的输出是:\(p(y=1)\)。
在线学习的算法与随机梯度下降算法有些类似,我们对单一的实例进行学习,而非对一个提前定义的训练集进行循环。
Repeat forever (as long as the website is running) {
\(\quad\)Get \(\left(x,y\right)\) corresponding to the current user
\(\quad\quad\)\(\theta_j :={\theta}_{j}-\alpha\left( {h}_{\theta}\left({x}\right)-{y} \right){{x}_{j}}\)
\(\quad\quad\)(for \(j=0:n\))
}
一旦对一个数据的学习完成了,我们便可以丢弃该数据,不需要再存储它了。这种方式的好处在于,我们的算法可以很好的适应用户的倾向性,算法可以针对用户的当前行为不断地更新模型以适应该用户。
每次交互事件并不只产生一个数据集,例如,我们一次给用户提供 3 个物流选项,用户选择 2 项,我们实际上可以获得 3 个新的训练实例,因而我们的算法可以一次从 3 个实例中学习并更新模型。
这些问题中的任何一个都可以被归类到标准的,拥有一个固定样本集的机器学习问题中。或许,你可以运行一个你自己的网站,尝试运行几天,并保存一个固定的数据集,然后对其运行一个学习算法。但实际情况下,你看到了大公司获取了如此多的数据,源源不断,所以真的没有必要来保存一个固定的数据集,取而代之的是你可以使用一个在线学习算法来连续的学习,从这些用户不断产生的数据中来学习,这就是在线学习机制。另外,这个算法与 随机梯度下降算法
非常类似,唯一的区别是,不再使用一个固定的数据集,我们会做的是获取一个用户样本,从那个样本中学习,然后丢弃那个样本并继续下去,而且如果你的某一种应用有一个连续的数据流,那么在线学习算法可能会非常值得考虑。当然,在线学习的一个优点就是,如果你有一个变化的用户群,又或者你在尝试预测的事情,在缓慢变化,就像你的用户的品味在缓慢变化一样,这个在线学习算法,可以慢慢地调节你所学习到的假设,将其调节更新到适应最新的用户行为。
映射化简和数据并行(Map Reduce and Data Parallelism)
m 个样本,n 个特征,Batch 梯度下降需要计算求和。可把 m 分成四份,并分别发送到四台机器上分别计算,最后再把结果发送到中心服务器上面汇总。完成对一个 \(\theta\) 的梯度计算,n 个特征,需要进行 n 次这样的操作。在忽略网络以及中心服务器计算的时间,可以直观的理解为计算速度提高了 4 倍。
同样原理,如果单个机器有多核,也可以进行 MapReduce,原理是分配到多个核心上分别计算,最后在汇总。很多线性代数库已经优化了向量化计算,并实现了并行计算。