Apache Spark 2.0前瞻:为机器学习模型注入持久性
e鸿619
8年前
<h2>简介</h2> <p>研究机器学习用例:</p> <ul> <li>数据科学家建立了一个ML模型,并交给了一个工程团队在生产环境部署。</li> <li>数据工程师将使用Python的模型训练工作流和Java模型服务工作流整合。</li> <li>数据科学家专门设立岗位来训练后期需要被保存和评估的ML模型。</li> </ul> <p>在所有的这些例子中,如果有了模型的持久性,那么保存和加载模型的问题将变得更容易解决。在即将到来的2.0版本中,通过基于DataFrame的API,Spark机器学习库MLlib将实现几乎完整的ML持久性支持。本文将提前透露有关代码示例,以及MLlib API持久性的一些细节。</p> <p>ML持久性的关键特性包括:</p> <ul> <li>Spark支持所有语言的API:Scala、Java、Python和R</li> <li>基于DataFram的API几乎支持所有的ML算法</li> <li>支持单一模型和完整的Pipelines,不管是训练或者未训练的</li> <li>使用可互换的格式来实现分布式存储</li> </ul> <p>感谢所有为MLlib带来巨大发展的社区贡献者们!在JIRAs中可以看到为Scala,Java, Python和R做出贡献的完整人员名单。</p> <h2>了解API</h2> <p>在Apache Spark 2.0里,对于MLlib来说基于DataFrame的API在关于Spark的ML中占据了首要位置。该API模仿被人们所熟知的Spark Data Source API,提供保存和加载模型的功能。</p> <p>下面将采用流行的MNIST数据集进行手写体数字识别,并在几种语言上演示保存和加载模型的功能(LeCun等著,1998;可从LIBSVM数据页面获取)。这个数据集包含了手写数字0-9,以及地面实况标签。这里有些例子:</p> <p><img src="https://simg.open-open.com/show/ccfc5303d69ea38df1f28cfba353af95.jpg"></p> <p>我们的最终目的是为了拍摄新的手写数字图像并进行数字识别。在下面的笔记中就完整地演示了数据载入,以及模型训练、保存和加载的代码。</p> <h2>保存和加载单一模型</h2> <p>首先将展示如何保存和加载单一模型以促进语言共享,例子中首先会通过Python来训练一个Random Forest Classifier并保存下来,然后再利用Scala加载相同的模型。</p> <pre> training = sqlContext.read... # data: features, label rf = RandomForestClassifier(numTrees=20) model = rf.fit(training)</pre> <p>为了简化,这里将保存模型称为save方法,把加载模型称为load方法:</p> <pre> model.save("myModelPath") sameModel = RandomForestClassificationModel.load("myModelPath")</pre> <p>我们还可以将同样的模型(已保存在Python的)加载到一个Scala或者Java应用程序中:</p> <pre> // Load the model in Scala val sameModel = RandomForestClassificationModel.load("myModelPath")</pre> <p>这个方法既可以用于小型的本地模型例如K-Means模型(为了集群),也可以用于大型的分布式模型例如ALS模型(为了推荐)。因为加载的模型具有相同的参数设置和数据,所以即使加载的是一个完全不同的Spark部署,它也会给出相同的预测。</p> <h2>保存和加载完整Pipelines</h2> <p>到目前为止只演示了单一ML模型的保存和加载,但在实际过程中,ML的工作流其实包含着许多阶段,从特征的提取和转换到模型的训练和调优都在其中。MLlib还提供了Pipelines来帮助用户更好地构建这些工作流。</p> <p>同时,MLlib还允许用户保存和加载整个Pipelines。下面通过一个Pipeline案例看一下它是采用了哪些步骤实现的:</p> <ul> <li>特征提取:使用Binarizer将图像转换成黑白色</li> <li>模型训练:使用Random Forest Classifier拍摄图像和预测数字0–9</li> <li>调优:使用交叉验证(Cross-Validation)来优化森林中树的深度</li> </ul> <p>下面是建立Pipeline的一个片段:</p> <pre> // Construct the Pipeline: Binarizer + Random Forest val pipeline = new Pipeline().setStages(Array(binarizer, rf)) // Wrap the Pipeline in CrossValidator to do model tuning. val cv = new CrossValidator().setEstimator(pipeline) ...</pre> <p>在管道训练之前,我们会演示将整个工作流保存下来的过程(训练前)。而且这个工作流可以在另一个数据集上,或者是在另一个Spark集群上等地方加载运行。</p> <pre> cv.save("myCVPath") val sameCV = CrossValidator.load("myCVPath")</pre> <p>最后,我们就可以进行Pipeline训练,再将其保存和加载。这不仅可以节省特征提取的步骤,还可以省去使用Cross-Validation调整Random Forest模型以及从模型调优中提取数据的过程。</p> <pre> val cvModel = cv.fit(training) cvModel.save("myCVModelPath") val sameCVModel = CrossValidatorModel.load("myCVModelPath")</pre> <h2>了解细节</h2> <p>Python调优</p> <p>很遗憾,Python调优将缺席Spark 2.0版本。就目前情况来看,Python还不支持保存和加载用于优化hyperparameters模型的CrossValidator和TrainValidationSplit;这个问题也正是Spark 2.1版本需要解决的。但是,它仍然有可能被用来保存Python中的CrossValidator和TrainValidationSplit结果。例如,使用Cross-Validation来调整Random Forest并将调整过程中发现的最好模型保存起来。</p> <pre> # Define the workflow rf = RandomForestClassifier() cv = CrossValidator(estimator=rf, ...) # Fit the model, running Cross-Validation cvModel = cv.fit(trainingData) # Extract the results, i.e., the best Random Forest model bestModel = cvModel.bestModel # Save the RandomForest model bestModel.save("rfModelPath")</pre> <p>可交换的存储格式</p> <p>在内部,我们可以把模型的元数据和参数保存为JSON,把数据保存为Parquet。这些存储格式是可交换的,还可以使用其他库读取。Parquet不仅可以存储小的模型(例如Naive Bayes for classification),还可以存储大型的分布式模型(例如ALS for recommendation)。任何被Dataset/DataFrame支持的URI 都可以保存和加载存储路径,包括S3路径、本地存储等等。</p> <p>语言的跨平台兼容性</p> <p>利用Scala、Java和Python可以很容易地保存和加载模型,但是R却有两个局限性。一方面,R并不是支持所有的MLlib模型,其他语言所训练的模型也不是都可以被加载到R。另一方面,目前的R模型格式需要存储一些配合R使用的数据,这样给其他语言加载R所训练和存储的模型增加了困难。相信更好的跨语言支持R会在不久的将来被补足。</p> <p>结论</p> <p>随着2.0版本的即将发布,DataFrame-based MLlib API将几乎完全覆盖持久化的模型和Pipelines。对于团队间共享模型、多语言ML工作流创建以及将模型用于生产这些,持久性发挥着至关重要的作用。这个特性也将会推动MLlib API(DataFrame-based)最终转变为Apache Spark机器学习的重要API。</p> <p>接下来呢?</p> <p>未来的话,更高优先级的项目将会包括完整的持久性覆盖、Python模型优化算法以及R和其他语言API之间的兼容性改进。</p> <p> </p> <p>来自: <a href="/misc/goto?guid=4959674155849209524" rel="nofollow">http://www.lupaworld.com/article-258760-1.html</a></p> <p> </p>