【问题标题】:Is Apache Spark less accurate than Scikit Learn?Apache Spark 是否不如 Scikit Learn 准确?
【发布时间】:2015-03-20 12:06:31
【问题描述】:

我最近一直在尝试了解 Apache Spark 作为 Scikit Learn 的替代品,但在我看来,即使在简单的情况下,Scikit 收敛到准确模型的速度也比 Spark 快得多。 例如,我使用以下脚本为一个非常简单的线性函数 (z=x+y) 生成了 1000 个数据点:

from random import random

def func(in_vals):
    '''result = x (+y+z+w....)'''
    result = 0
    for v in in_vals:
        result += v
    return result

if __name__ == "__main__":
    entry_count = 1000
    dim_count = 2
    in_vals = [0]*dim_count
    with open("data_yequalsx.csv", "w") as out_file:
        for entry in range(entry_count):
            for i in range(dim_count):
                in_vals[i] = random()
            out_val = func(in_vals)
            out_file.write(','.join([str(x) for x in in_vals]))
            out_file.write(",%s\n" % str(out_val))

然后我运行了以下 Scikit 脚本:

import sklearn
from sklearn import linear_model

import numpy as np

data = []
target = []
with open("data_yequalsx.csv") as inFile:
    for row in inFile:
        vals = row.split(",")
        data.append([float(x) for x in vals[:-1]])
        target.append(float(vals[-1]))

test_samples= len(data)/10

train_data = [0]*(len(data) - test_samples)
train_target = [0]*(len(data) - test_samples)
test_data = [0]*(test_samples)
test_target = [0]*(test_samples)
train_index = 0
test_index = 0
for j in range(len(data)):
    if j >= test_samples:
        train_data[train_index] = data[j]
        train_target[train_index] = target[j]
        train_index += 1
    else:
        test_data[test_index] = data[j]
        test_target[test_index] = target[j]
        test_index += 1

model = linear_model.SGDRegressor(n_iter=100, learning_rate="invscaling", eta0=0.0001, power_t=0.5, penalty="l2", alpha=0.0001, loss="squared_loss")
model.fit(train_data, train_target)
print(model.coef_)
print(model.intercept_)

result = model.predict(test_data)
mse = np.mean((result - test_target) ** 2)
print("Mean Squared Error = %s" % str(mse))

然后是这个 Spark 脚本:(使用 spark-submit ,没有其他参数)

from pyspark.mllib.regression import LinearRegressionWithSGD, LabeledPoint
from pyspark import SparkContext

sc = SparkContext (appName="mllib_simple_accuracy")

raw_data = sc.textFile ("data_yequalsx.csv", minPartitions=10) #MinPartitions doesnt guarantee that you get that many partitions, just that you wont have fewer than that many partitions
data = raw_data.map(lambda line: [float(x) for x in line.split (",")]).map(lambda entry: LabeledPoint (entry[-1], entry[:-1])).zipWithIndex()
test_samples= data.count()/10

training_data = data.filter(lambda (entry, index): index >= test_samples).map(lambda (lp,index): lp)
test_data = data.filter(lambda (entry, index): index < test_samples).map(lambda (lp,index): lp)

model = LinearRegressionWithSGD.train(training_data, step=0.01, iterations=100, regType="l2", regParam=0.0001, intercept=True)
print(model._coeff)
print(model._intercept)

mse = (test_data.map(lambda lp: (lp.label - model.predict(lp.features))**2 ).reduce(lambda x,y: x+y))/test_samples;
print("Mean Squared Error: %s" % str(mse))

sc.stop ()

奇怪的是,尽管这两个模型具有几乎相同的设置(据我所知),但 spark 给出的误差比 Scikit 给出的误差大一个数量级(分别为 0.185 和 0.045) 我知道这是使用很少迭代的 SGD,因此结果可能会有所不同,但我不会想到它会接近如此大的差异或如此大的错误,尤其是考虑到非常简单的数据。


我对 Spark 有什么误解吗?是不是配置不正确?当然我应该得到比这更小的错误?

【问题讨论】:

  • 我建议您通过使用不同的随机种子多次重复实验来提供错误界限,并检查您是否得到相同的结果; 1000 个数据点和 100 次迭代并不多。此外,sklearn 和 mllib 是否对 SGD 使用相同的学习率计划?您对 sklearn 使用了 invscaling,但 mllib 使用的是相同的吗?

标签: apache-spark machine-learning scikit-learn linear-regression


【解决方案1】:

SGD,代表 Stochastic Gradient Descent,是一种在线凸优化算法,因此很难并行化,因为它每次迭代都会更新一次(有更智能的变体,例如带有小批量的 SGD,但仍然不是很适合并行环境。

另一方面,批处理算法,例如 L-BFGS,我建议您与 Spark (LogigisticRegressionWithLBFGS) 一起使用,可以轻松并行化,因为它在每个 epoch 进行迭代(它需要查看所有数据点,计算每个点的损失函数的值和梯度,然后进行聚合计算全梯度)。

Python 在单台机器上运行,因此 SGD 表现良好。

顺便说一下,如果你查看 MLlib 代码,scikit learn 的 lambda 等价物是数据集的 lambda/size(mllib 优化 1/n*sum(l_i(x_i,f(y_i)) + lambda 而 scikit learn 优化 sum(l_i(x_i,f(y_i)) + lambda

【讨论】:

    【解决方案2】:

    因为 Spark 是并行化的,所以每个节点都需要能够在计算进行时独立于其他节点工作,以避免节点之间 [时间-] 昂贵的 shuffle。因此,它使用称为随机梯度下降的过程来接近最小值,该过程遵循局部梯度向下。

    解决 [简单的最小二乘] 回归问题的“精确”方法涉及求解矩阵方程。这可能是 Scikit-Learn 正在做的事情,所以在这种情况下会更准确。

    权衡的是,对于大小为 N 的方阵,求解矩阵方程通常按 N^3 缩放,这对于大型数据集很快变得不可行。 Spark 用计算能力交换准确性。与任何机器学习过程一样,您应该在整个算法中构建大量健全性检查,以确保上一步的结果有意义。

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-20
      • 2015-08-24
      • 2017-05-18
      • 2014-04-14
      • 2022-12-17
      • 2021-09-14
      • 2016-10-12
      • 1970-01-01
      相关资源
      最近更新 更多