-dist的开源sk-dist框架。这是一个用于分发scikit-learn元估计器的Spark通用框架,它结合了Spark和scikit-learn的元素,可将sklearn训练速度提高100倍以上。在Ibotta,我们训练了许多机器学习模型。这些模型为我们的推荐系统、搜索引擎、定价优化引擎、数据质量等提供支持,在与我们的移动应用程序交互时为数百万用户做出预测。虽然我们使用Spark进行大量数据处理,但我们首选的机器学习框架是scikit-learn。随着计算成本的降低和机器学习解决方案的上市时间变得更加重要,我们已经朝着加速模型训练迈出了一步。解决方案之一是将Spark和scikit-learn中的元素组合到我们自己的融合解决方案中。项目地址:https://github.com/Ibotta/sk-dist什么是sk-dist我们很高兴推出我们的开源项目sk-dist。该项目的目标是为分发scikit-learn元估计器提供一个Spark通用框架。元估计器的应用包括决策树的集成(随机森林和额外随机树)、超参数调整(网格搜索和随机搜索)和多类技术(一对一和一对一)。我们的主要目标是填补传统机器学习模型分布选择空间的空白。在神经网络和深度学习的空间之外,我们发现训练模型的大部分计算时间并没有花在在单个数据集上训练单个模型上,而是花在使用元估计器(例如网格搜索或集成)上在集合的多次迭代中训练模型的多次迭代。示例以手写数字数据集为例。我们对手写数字的图像进行编码以便于分类。我们可以在不到一秒的时间内用一台机器在1797条记录的数据集上快速训练支持向量机。然而,超参数调整需要对训练数据的不同子集进行大量训练。如下图所示,我们构建了一个参数网格,总共需要1050个训练项。在100+核心的Spark集群上使用sk-dist只需3.4秒。这项工作的总任务时间为7.2分钟,这意味着在没有并行化的机器上训练需要那么长时间。importtimefromsklearnimportdatasets,svmfromskdist.distribute.searchimportDistGridSearchCVfrompyspark.sqlimportSparkSession#instantiatesparksessionspark=(SparkSession.builder.getOrCreate())sc=spark.sparkContext#thedigitsdatasetdigits=datasets.load_digits()X=数字[“数据”]y=数字[“目标”]#createaclassifier:asupportvectorclassifierclassifier=svm.SVC()param_grid={"C":[0.01,0.01,0.1,1.0,10.0,20.0,50.0],"gamma":["scale","auto",0.001,0.01,0.1],"kernel":["rbf","poly","sigmoid"]}scoring="f1_weighted"cv=10#hyperparameteroptimizationstart=time.time()model=DistGridSearchCV(分类器,param_grid,sc=sc,cv=cv,scoring=scoring,verbose=True)model.fit(X,y)print("Traintime:{0}".format(time.time()-start))print("Bestscore:{0}".format(model.best_score_))----------------------------Sparkcontextfound;runningwithsparkFitting10foldsforeachof105名候选人,总共1050次拟合Traintime:3.380601406097412Bestscore:0.981450024203508此示例说明了一种常见情况,其中将数据拟合到内存中并训练单个分类器并不重要,但超参数调整所需的拟合数迅速增加以下是其机制运行网格搜索问题,如上例中的sk-dist:Gridsearchwithsk-dist对于Ibotta传统机器学习的实际应用,我们经常发现自己处于类似情况:中小型数据(100k到1M记录),其中包括具有多次迭代的简单分类器,适用于超参数调整、集成和多类解决方案。现有解决方案对于传统的机器学习元估计训练,现有解决方案是分布式的。第一个是最简单的:scikit-learn使用joblib的内置元估计器的并行化。这与sk-dist非常相似,除了一个主要的限制因素:性能有限。即使对于具有数百个内核的理论上的单机,Spark仍然具有诸如执行程序的内存调整规范、容错和成本控制选项(例如将Spot实例用于工作节点)等优势。另一个现有的解决方案是SparkML。这是Spark的原生机器学习库,它支持许多与scikit-learn相同的算法来解决分类和回归问题。它还具有元估计器,如树集成和网格搜索,以及对多类问题的支持。虽然这听起来像是分布式scikit-learn-mode机器学习工作负载的优秀解决方案,但它的分布式训练并没有解决我们感兴趣的并行性问题。跨维度分布如上所示,SparkML将在分布式数据上训练单个模型跨多个执行者。当数据很大并且无法容纳在一台机器上的内存中时,这非常有用。但是,当数据较小时,它在单台计算机上的性能可能不如scikit-learn。此外,在训练随机森林时,SparkML会按顺序训练每个决策树。无论分配给任务的资源如何,该任务的等待时间都将与决策树的数量成线性比例关系。对于网格搜索,SparkML确实实现了一个并行参数,它将并行训练各个模型。然而,每个单独的模型仍在接受跨执行者分布的数据的训练。如果沿着模型而不是数据的维度分布,则任务的总并行度可能只是它的一小部分。最终,我们希望将我们的训练分布在与SparkML不同的维度上。在处理中小型数据时,将数据装入内存不是问题。对于随机森林的例子,我们希望将训练数据整体广播给每个执行器,在每个执行器上拟合一棵独立的决策树,并将这些拟合的决策树返回给驱动程序来构建随机森林。沿着这个维度分布比连续分布数据和训练决策树快几个数量级。这种行为类似于其他元估计技术,例如网格搜索和多类。特征鉴于我们的问题空间中这些现有解决方案的局限性,我们决定在内部开发sk-dist。最重要的是我们要“分发模型,而不是数据”。sk-dist的重点是元估计器的分布式训练,还包括使用Spark对scikit-learn模型进行分布式预测的模块、用于多个不带Spark的预处理/后处理的scikit-learn转换器,以及带/不带Spark的灵活特征编码器.分布式训练:使用Spark进行分布式元估计器训练。支持以下算法:超参数调整(网格搜索和随机搜索)、决策树集成(随机森林、额外随机树和随机树嵌入)和多类技术(一对多和一对一)。分布式预测:一种使用SparkDataFrames分布拟合scikit-learn估计器的预测方法。可以使用可与或不与Spark一起使用的便携式scikit-learn估计器来实现大规模分布式预测。特征编码:使用称为Encoderizer的灵活特征转换器分发特征编码。它可以与或不与Spark并行化一起使用。它将推断数据类型和形状,自动应用默认特征转换器作为标准特征编码技术的最佳预测实现。它还可作为完全可定制的功能联合编码器使用,并具有与Spark的分布式变压器一起使用的额外优势。UseCases以下是判断sk-dist是否适合您的机器学习问题空间的一些指南:传统机器学习:广义线性模型、随机梯度下降、最近邻算法、决策树和朴素贝叶斯都适合sk-dist。这些都是在scikit-learn中实现的,可以直接使用sk-dist元估计器实现。中小型数据:大数据不适合sk-dist。请记住,训练分布的维度随模型而不是数据而变化。数据不仅需要适合每个执行者的内存,而且要小到可以广播。根据Spark配置,最大广播大小可能会受到限制。Spark定位和访问:sk-dist的核心功能需要运行Spark。对于个人或小型数据科学团队而言,这并不总是可行的。此外,还需要进行一些Spark调优和配置,以便以最具成本效益的方式使用sk-dist,这需要一些Spark基础知识培训。这里需要注意的是,虽然神经网络和深度学习在技术上可以与sk-dist一起使用,但这些技术需要大量的训练数据,有时还需要专门的基础设施才能有效。深度学习不是sk-dist的预期用例,因为它违反了上面的(1)和(2)。在Ibotta,我们一直在使用这些技术,即AmazonSageMaker,我们发现它对于这些工作负载的计算效率比使用Spark更高。
