将机器学习模型保存以备将来使用。

23
我正在对一些数据应用一些机器学习算法,如线性回归、逻辑回归和朴素贝叶斯,但我试图避免使用RDD并开始使用DataFrames,因为在pyspark下 RDDs比DataFrames慢(见图1)。

另一个我使用DataFrames的原因是因为ml库有一个非常有用的类可以调整模型,即CrossValidator,这个类在拟合后返回一个模型,显然,这个方法必须测试几种情况,并在此之后返回拟合模型(具有最佳参数组合)。
我使用的集群不是很大,但数据量很大,一些拟合需要数小时,因此我想将这些模型保存以便以后重复使用,但我还没有意识到如何做到这一点,我是否忽略了什么?
注:
  • mllib的模型类有一个save方法(例如NaiveBayes),但mllib没有CrossValidator并且使用RDDs,所以我故意避免使用它。
  • 当前版本为spark 1.5.1。

2
+1 好问题。我和你处在同一位置,正准备从RDDs转变为DataFrames。 我用的是1.6.1,但是我也遇到了相同的问题,因为OneVsRest似乎还没有实现保存功能。https://dev59.com/vJXfa4cB1Zd3GeqPfXZY - Brian
2个回答

25

Spark 2.0.0+

乍一看,所有的TransformersEstimators都实现了MLWritable接口,其接口如下:

def write: MLWriter
def save(path: String): Unit 

以及具有以下接口的MLReadable

def read: MLReader[T]
def load(path: String): T

这意味着您可以使用save方法将模型写入磁盘,例如。
import org.apache.spark.ml.PipelineModel

val model: PipelineModel
model.save("/path/to/model")

并稍后阅读:

val reloadedModel: PipelineModel = PipelineModel.load("/path/to/model")

等价的方法也在 PySpark 中实现,分别使用 MLWritable / JavaMLWritableMLReadable / JavaMLReadable。请注意保留 HTML 标签。
from pyspark.ml import Pipeline, PipelineModel

model = Pipeline(...).fit(df)
model.save("/path/to/model")

reloaded_model = PipelineModel.load("/path/to/model")

SparkR提供write.ml / read.ml 函数,但是现在这些函数与其他支持的语言不兼容 - SPARK-15572
请注意,加载器类必须与存储的PipelineStage类匹配。例如,如果您保存了LogisticRegressionModel,则应使用LogisticRegressionModel.load而不是LogisticRegression.load
如果您使用的是Spark <= 1.6.0并且遇到了一些模型保存问题,建议您切换版本。
此外,除了Spark特定的方法之外,还有越来越多的库专门设计用于使用Spark独立方法保存和加载Spark ML模型。例如,请参阅如何提供Spark MLlib模型服务?

Spark >= 1.6

自Spark 1.6以来,可以使用save方法保存您的模型。因为几乎每个model都实现了MLWritable接口。例如,LinearRegressionModel就有,因此可以使用它将模型保存到所需路径。

Spark < 1.6

我认为你在这里做出了错误的假设。
一些对DataFrames的操作可以进行优化,并且相比于普通的RDDs,可以获得更好的性能。 DataFrames提供高效的缓存,并且SQLish API比RDD API更易于理解。
ML管道非常有用,像交叉验证器或不同的评估器等工具在任何机器学习管道中都是必备的。即使以上内容并不特别难以在低级MLlib API之上实现,但拥有已准备好的、通用的、相对经过良好测试的解决方案要好得多。
到目前为止一切都很好,但存在一些问题:
  • 据我所知,对于像DataFrames这样的简单操作,如selectwithColumn,其性能与其RDD等效项(如map)相似。
  • 在某些情况下,在典型管道中增加列数实际上可能会降低性能,与精心调整的低级转换相比。当然,您可以在途中添加删除列转换器来纠正这种情况。
  • 许多ML算法,包括ml.classification.NaiveBayes仅仅是mllib API的包装器。
  • PySpark ML/MLlib算法将实际处理委托给其Scala同行。
  • 最后但并非最不重要的,RDD仍然存在,即使它被DataFrame API很好地隐藏起来了。

我相信,使用ML而不是MLLib,你得到的东西非常优雅,高级API。您可以做的一件事是将两者结合起来创建自定义的多步骤管道:

  • 使用机器学习加载、清洗和转换数据,
  • 提取所需数据(例如,请参见extractLabeledPoints方法),并传递给MLLib算法,
  • 添加自定义交叉验证/评估,
  • 使用您选择的方法(Spark模型或PMML)保存MLLib模型。

虽然不是最佳解决方案,但在当前API下是我能想到的最好的方案。


5

我认为在PySpark中你可以做类似的事情,即使用pickle进行序列化,但这并不容易。由于PySpark ML主要是Scala API的包装器,因此必须确保Scala模型在序列化/反序列化时正确处理。 - zero323
1
我本可以用Scala来做,但是我需要用Python来完成 :| - Alberto Bonsanto
+1 有没有一种简单的方法(或者任何方法)来持久化一个pyspark.ml模型?我找不到任何相关的文档。 - ajkl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接