MLlib是Spark的机器学习(ML)库。它的目标是使机器学习的实际应用变得容易和可扩展。在较高层次上,它提供了以下工具:
- ML算法:常见的学习算法,如分类、回归、聚类和协作过滤
- 特征化:特征提取、转换、降维和筛选
- 工作流(Pipelines):构建、评估和调整ML工作流的工具
- 持久性:保存和加载算法、模型和工作流
- 实用程序:线性代数、统计学、数据处理等。
注:基于DataFrame的API是主API
基于MLlib RDD的API当前处于维护模式。
从Spark 2.0开始,Spark.mllib包中基于RDD (http://spark.apache.org/docs/latest/rdd-programming-guide.html#resilient-distributed-datasets-rdds) 的API已经进入维护模式。Spark的主要机器学习API现在是Spark.ml包中基于DataFrame (http://spark.apache.org/docs/latest/sql-programming-guide.html) 的API。
这意味着什么?
- MLlib仍然支持spark.MLlib中基于RDD的API,并修复了错误。
- MLlib不会向基于RDD的API添加新特性。
- 在Spark 2.x版本中,MLlib将向基于DataFrame 的API添加特性,与基于RDD的API的特性达到对等。
- 在达到特性对等(初步估计是在Spark 2.3,当前最新的已经是2.4.5)之后,将不推荐使用基于RDD的API。
- 基于RDD的API将在Spark 3.0中被删除。
为什么MLlib要切换到基于DataFrame 的API?
- DataFrame 提供了比rdd更友好的API。DataFrame的许多优点包括Spark数据源、SQL/DataFrame查询、Tungsten and Catalyst优化以及跨语言的统一api。
- 基于DataFrame的MLlib API提供了跨ML算法和跨多种语言的统一API。
- DataFrame更适合实用的ML工作流,特别是特性转换。详细信息请参见工作流指南(http://spark.apache.org/docs/latest/ml-pipeline.html)。
什么是“Spark ML”?
- “Spark ML”不是一个官方名称,偶尔用于表示MLlib这个基于DataFrame 的API。这主要是因为基于DataFrame的API使用了org.apache.spark.ml 这个Scala包名,另外,最初我们用 “Spark ML Pipelines”这个术语只是为了强调工作流(Pipelines)的概念。
MLlib被弃用了吗?
- 没有,MLlib包括基于RDD的API和基于DataFrame的API。基于RDD的API现在处于维护模式。但无论是API还是MLlib都没有被弃用。
依赖关系
MLlib使用线性代数库Breeze(http://www.scalanlp.org/),它依赖于netlib-java(https://github.com/fommil/netlib-java)来优化数值处理。如果本地库在运行时不可用,您将看到一条警告消息,并且会用纯JVM的实现来替代。
由于运行时专有二进制文件的许可问题,默认情况下我们未使用netlib-java的本地代理。如果需要将netlib-java/Breeze配置为使用系统优化的二进制文件,请将com.github.fommil.netlib:all:1.1.2(或使用-Pnetlib-lgpl来构建Spark)作为工程(project)的依赖项,并引入netlib-java的文档作为平台的附加安装说明。
最流行的本地基本线性代数子程序(Basic Linear Algebra Subprograms,BLAS),如Intel MKL、OpenBLAS,可以在一个操作中使用多个线程,这可能与Spark的执行模型相冲突。
将这些BLAS的实现配置为单线程在计算中使用,将很有可能提高性能(请参阅SPARK-21305(https://issues.apache.org/jira/browse/SPARK-21305))。通常,将其与每个Spark任务配置的核心数相匹配才是最佳的,默认情况下为1,通常保留为1。
想了解如何配置这些BLAS实现使用的线程数,请参阅以下参考资料: Intel MKL and OpenBLAS。
要在Python中使用MLlib,您需要NumPy 1.4或更高版本(http://www.numpy.org/)。
Spark 2.3的亮点
以下列表重点介绍了Spark 2.3中添加到MLlib的一些新优化和功能:
- 增加了读入图像为DataFrame 的内置支持(SPARK-21866)。
- 增加了
OneHotEncoderEstimator,建议用它代替现有的onehotecoder转换器(transformer)。这个新的估计器支持多列转换。 - QuantileDiscretizer和Bucketizer(SPARK-22397和SPARK-20542)也增加了多列支持
- 增加了新的FeatureHasher转换器(SPARK-13969)。
- 在使用TrainValidationSplit或CrossValidator执行交叉验证时,增加了并行评估多个模型的支持(SPARK-19357)。
- 改进了对Python中自定义工作流组件的支持(参见SPARK-21633和SPARK-21542)。
- 增加了向量列描述性摘要统计的DataFrame 函数(SPARK-19634)。
- 具有Huber损失函数的鲁棒(Robust)线性回归(SPARK-3181)。
迁移指南
MLlib正在积极开发中。标记为Experimental/DeveloperApi的api在未来的版本中可能会发生变化,下面的迁移指南将解释版本之间的所有变化。
从2.2到2.3
重大变化
- 对logistic回归模型摘要的类和特征层次结构进行了修改,使之更清晰,更好地适应多类摘要的添加。对于用户代码来说,这是一个重大的变化,它将LogisticRegressionTrainingSummary强制转换为BinaryLogisticRegressionTrainingSummary。用户应该改为使用model.binarySummary方法。更多细节见SPARK-17139(注意这是一个实验性的API)。这不会影响Python的summary方法,该方法仍然适用于多类和二分类的情况。
弃用和其他变化
弃用
- OneHotEncoder已被弃用,将在3.0中删除。它已经被新的OneHotEncoderEstimator所取代(见SPARK-13030)。注:在3.0中,OneHotEncoderEstimator将重命名为OneHotEncoder(但OneHotEncoderEstimator会保留为别名)。
其他变化
- SPARK-21027: OneVsRest中使用的默认并行度现在设置为1(即串行)。在2.2和更早版本中,并行级别设置为默认的Scala线程池大小。
- SPARK-22156: 当numIterations设置为大于1时,Word2Vec的学习率更新不正确。这将导致2.3和早期版本的训练结果不同。
- SPARK-21681:修正了多项式logistic回归中的一个边界bug,当某些特征的方差为零时,该错误会导致系数不正确。
- SPARK-16957: 树算法现在使用中间点分割值。这可能会改变模型训练的结果。
- SPARK-14657:修正了RFormula在没有截获的情况下生成的特征与R中的输出不一致的问题。这可能会改变这个场景中模型训练的结果。
以前的Spark版本
以前的迁移指南存档在此页上(http://spark.apache.org/docs/latest/ml-migration-guides.html)。
注:想要进一步了解系统本地优化的好处和背景,您可以观看Sam Halliday的, 关于“Scala中高性能线性代数”的ScalaX演讲(http://fommil.github.io/scalax14/#/)。