1. 程式人生 > >Apache Spark 2.0前瞻:為機器學習模型注入永續性

Apache Spark 2.0前瞻:為機器學習模型注入永續性

簡介

研究機器學習用例:

  • 資料科學家建立了一個ML模型,並交給了一個工程團隊在生產環境部署。
  • 資料工程師將使用Python的模型訓練工作流和Java模型服務工作流整合。
  • 資料科學家專門設立崗位來訓練後期需要被儲存和評估的ML模型。

在所有的這些例子中,如果有了模型的永續性,那麼儲存和載入模型的問題將變得更容易解決。在即將到來的2.0版本中,通過基於DataFrame的API,Spark機器學習庫MLlib將實現幾乎完整的ML永續性支援。本文將提前透露有關程式碼示例,以及MLlib API永續性的一些細節。

ML永續性的關鍵特性包括:

  • Spark支援所有語言的API:Scala、Java、Python和R
  • 基於DataFram的API幾乎支援所有的ML演算法
  • 支援單一模型和完整的Pipelines,不管是訓練或者未訓練的
  • 使用可互換的格式來實現分散式儲存

感謝所有為MLlib帶來巨大發展的社群貢獻者們!在JIRAs中可以看到為Scala,Java, Python和R做出貢獻的完整人員名單。

瞭解API

在Apache Spark 2.0裡,對於MLlib來說基於DataFrame的API在關於Spark的ML中佔據了首要位置。該API模仿被人們所熟知的Spark Data Source API,提供儲存和載入模型的功能。

下面將採用流行的MNIST資料集進行手寫體數字識別,並在幾種語言上演示儲存和載入模型的功能(LeCun等著,1998;可從LIBSVM資料頁面獲取)。這個資料集包含了手寫數字0-9,以及地面實況標籤。這裡有些例子:

圖片描述

我們的最終目的是為了拍攝新的手寫數字影象並進行數字識別。在下面的筆記中就完整地演示了資料載入,以及模型訓練、儲存和載入的程式碼。

儲存和載入單一模型

首先將展示如何儲存和載入單一模型以促進語言共享,例子中首先會通過Python來訓練一個Random Forest Classifier並儲存下來,然後再利用Scala載入相同的模型。

training = sqlContext.read...  # data: features, label
rf = RandomForestClassifier(numTrees=20)
model = rf.fit(training)

為了簡化,這裡將儲存模型稱為save方法,把載入模型稱為load方法:

model.save("myModelPath")
sameModel = RandomForestClassificationModel.load("myModelPath")

我們還可以將同樣的模型(已儲存在Python的)載入到一個Scala或者Java應用程式中:

// Load the model in Scala
val sameModel = RandomForestClassificationModel.load("myModelPath")

這個方法既可以用於小型的本地模型例如K-Means模型(為了叢集),也可以用於大型的分散式模型例如ALS模型(為了推薦)。因為載入的模型具有相同的引數設定和資料,所以即使載入的是一個完全不同的Spark部署,它也會給出相同的預測。

儲存和載入完整Pipelines

到目前為止只演示了單一ML模型的儲存和載入,但在實際過程中,ML的工作流其實包含著許多階段,從特徵的提取和轉換到模型的訓練和調優都在其中。MLlib還提供了Pipelines來幫助使用者更好地構建這些工作流。

同時,MLlib還允許使用者儲存和載入整個Pipelines。下面通過一個Pipeline案例看一下它是採用了哪些步驟實現的:

  • 特徵提取:使用Binarizer將影象轉換成黑白色
  • 模型訓練:使用Random Forest Classifier拍攝影象和預測數字0–9
  • 調優:使用交叉驗證(Cross-Validation)來優化森林中樹的深度

下面是建立Pipeline的一個片段:

// 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) ...

在管道訓練之前,我們會演示將整個工作流儲存下來的過程(訓練前)。而且這個工作流可以在另一個數據集上,或者是在另一個Spark叢集上等地方載入執行。

cv.save("myCVPath")
val sameCV = CrossValidator.load("myCVPath")

最後,我們就可以進行Pipeline訓練,再將其儲存和載入。這不僅可以節省特徵提取的步驟,還可以省去使用Cross-Validation調整Random Forest模型以及從模型調優中提取資料的過程。

val cvModel = cv.fit(training)
cvModel.save("myCVModelPath")
val sameCVModel = CrossValidatorModel.load("myCVModelPath")

瞭解細節

Python調優

很遺憾,Python調優將缺席Spark 2.0版本。就目前情況來看,Python還不支援儲存和載入用於優化hyperparameters模型的CrossValidator和TrainValidationSplit;這個問題也正是Spark 2.1版本需要解決的。但是,它仍然有可能被用來儲存Python中的CrossValidator和TrainValidationSplit結果。例如,使用Cross-Validation來調整Random Forest並將調整過程中發現的最好模型儲存起來。

# 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")

可交換的儲存格式

在內部,我們可以把模型的元資料和引數儲存為JSON,把資料儲存為Parquet。這些儲存格式是可交換的,還可以使用其他庫讀取。Parquet不僅可以儲存小的模型(例如Naive Bayes for classification),還可以儲存大型的分散式模型(例如ALS for recommendation)。任何被Dataset/DataFrame支援的URI 都可以儲存和載入儲存路徑,包括S3路徑、本地儲存等等。

語言的跨平臺相容性

利用Scala、Java和Python可以很容易地儲存和載入模型,但是R卻有兩個侷限性。一方面,R並不是支援所有的MLlib模型,其他語言所訓練的模型也不是都可以被載入到R。另一方面,目前的R模型格式需要儲存一些配合R使用的資料,這樣給其他語言載入R所訓練和儲存的模型增加了困難。相信更好的跨語言支援R會在不久的將來被補足。

結論

隨著2.0版本的即將釋出,DataFrame-based MLlib API將幾乎完全覆蓋持久化的模型和Pipelines。對於團隊間共享模型、多語言ML工作流建立以及將模型用於生產這些,持久性發揮著至關重要的作用。這個特性也將會推動MLlib API(DataFrame-based)最終轉變為Apache Spark機器學習的重要API。

接下來呢?

未來的話,更高優先順序的專案將會包括完整的永續性覆蓋、Python模型優化演算法以及R和其他語言API之間的相容性改進。