保存 ML 模型以供将来使用
Posted
技术标签:
【中文标题】保存 ML 模型以供将来使用【英文标题】:Save ML model for future usage 【发布时间】:2016-01-06 18:47:00 【问题描述】:我对一些数据应用了一些机器学习算法,如线性回归、逻辑回归和朴素贝叶斯,但我试图避免使用 RDD 并开始使用 DataFrames,因为 RDDs are slower 比 pyspark 下的 Dataframes (见图 1) .
我使用 DataFrames 的另一个原因是因为 ml 库有一个对调整模型非常有用的类 CrossValidator 这个类在拟合后返回一个模型,显然这个方法必须测试几个场景,然后返回一个fitted model(具有最佳参数组合)。
我使用的集群不是很大,数据也很大,有些拟合需要几个小时,所以我想保存这些模型以供以后重复使用,但我还没有意识到如何,有什么我忽略了吗?
注意事项:
mllib 的模型类有一个保存方法(即NaiveBayes),但 mllib 没有 CrossValidator 并且使用 RDD,所以我有预谋地避免使用它。 当前版本是 spark 1.5.1。【问题讨论】:
+1 好问题。我和我刚刚从RDDs
切换到DataFrames
的位置相同。我在1.6.1
,但我遇到了同样的问题,因为OneVsRest
似乎还没有实现保存功能***.com/questions/36243455/…
【参考方案1】:
火花 2.0.0+
乍一看,所有Transformers
和Estimators
都使用以下接口实现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
/ JavaMLWritable
和 MLReadable
/ JavaMLReadable
:
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
除了 Spark 特定方法之外,还有越来越多的库旨在使用 Spark 独立方法保存和加载 Spark ML 模型。参见例如How to serve a Spark MLlib model?。
火花 >= 1.6
从 Spark 1.6 开始,可以使用save
方法保存您的模型。因为几乎每个model
都实现了MLWritable 接口。例如,LinearRegressionModel 有它,因此可以使用它将您的模型保存到所需的路径。
火花
我相信你在这里做出了错误的假设。
DataFrames
上的某些操作可以进行优化,与普通的RDDs
相比,它可以转化为更高的性能。 DataFrames
提供高效的缓存,SQLish API 可以说比 RDD API 更容易理解。
ML 流水线非常有用,像交叉验证器或不同的评估器这样的工具在任何机器流水线中都是必不可少的,即使上述任何一个都不是特别难在低级 MLlib API 之上实现,它也更好已准备好使用、通用且经过相对良好测试的解决方案。
到目前为止一切顺利,但还有一些问题:
据我所知,DataFrames
上的简单操作(例如 select
或 withColumn
)显示的性能与其 RDD 等效项(例如 map
)相似,
在某些情况下,与经过良好调整的低级别转换相比,增加典型管道中的列数实际上会降低性能。您当然可以在纠正该问题的过程中添加 drop-column-transformers,
许多 ML 算法,包括 ml.classification.NaiveBayes
are simply wrappers 围绕其 mllib
API,
PySpark ML/MLlib 算法将实际处理委托给其 Scala 对应算法,
最后但并非最不重要的一点是,RDD 仍然存在,即使隐藏在 DataFrame API 后面
我相信,最终通过使用 ML 而不是 MLLib 获得的是相当优雅的高级 API。您可以做的一件事是将两者结合起来创建一个自定义的多步骤管道:
使用 ML 加载、清理和转换数据, 提取所需数据(例如参见extractLabeledPoints 方法)并传递给MLLib
算法,
添加自定义交叉验证/评估
使用您选择的方法(Spark 模型或 PMML)保存 MLLib
模型
这不是最佳解决方案,但在给定当前 API 的情况下,它是我能想到的最佳解决方案。
【讨论】:
【参考方案2】:目前看来保存模型的 API 功能尚未实现(请参阅Spark issue tracker SPARK-6725)。
发布了一个替代方案 (How to save models from ML Pipeline to S3 or HDFS?),它涉及简单地序列化模型,但它是一种 Java 方法。我希望在 PySpark 中您可以做类似的事情,即腌制模型以写入磁盘。
【讨论】:
我希望在 PySpark 中你可以做类似的事情,即 pickle - 也许吧,但这并不容易。由于 PySpark ML 主要是 Scala API 的包装器,因此必须确保 Scala 模型同时正确序列化/反序列化。 我可以用 scala 来做,但我需要在 python 上做:| +1 有没有一种简单的方法(或任何方法)来持久化 pyspark.ml 模型?找不到任何文档以上是关于保存 ML 模型以供将来使用的主要内容,如果未能解决你的问题,请参考以下文章
保存并使用 TFIDF 矢量化器以供将来的示例使用,然后导致尺寸错误