隨著機(jī)器學(xué)習(xí)的廣泛應(yīng)用,如何高效的把訓(xùn)練好的機(jī)器學(xué)習(xí)的模型部署到生產(chǎn)環(huán)境,正在被越來越多的工具所支持。我們今天就來看一看不同的工具是如何解決這個問題的。

上圖的過程是一個數(shù)據(jù)科學(xué)項目所要經(jīng)歷的典型的過程。從數(shù)據(jù)采集開始,經(jīng)歷數(shù)據(jù)分析,數(shù)據(jù)變形,數(shù)據(jù)驗(yàn)證,數(shù)據(jù)拆分,訓(xùn)練,模型創(chuàng)建,模型驗(yàn)證,大規(guī)模訓(xùn)練,模型發(fā)布,到提供服務(wù),監(jiān)控和日志。諸多的機(jī)器學(xué)習(xí)工具如Scikt-Learn,Spark, Tensorflow, MXnet, PyTorch提供給數(shù)據(jù)科學(xué)家們不同的選擇,同時也給模型的部署帶來了不同的挑戰(zhàn)。
我們先來簡單的看一看機(jī)器學(xué)習(xí)的模型是如何部署,它又會遇到那些挑戰(zhàn)。
模型持久化
模型部署一般就是把訓(xùn)練的模型持久化,然后運(yùn)行服務(wù)器加載模型,并提供REST或其它形式的服務(wù)接口。我們以RandomForestClassification為例,看一下Sklearn,Spark和Tensorflow是如何持久化模型。
Sklearn
我們使用Iris數(shù)據(jù)集,利用RandomForestClassifier分類。

訓(xùn)練的代碼如上。這里模型導(dǎo)出的代碼在最后一句。joblib.dump(),參考這里。Sklearn的模型到處本質(zhì)上是利用Python的Pickle機(jī)制。Python的函數(shù)進(jìn)行序列化,也就是說把訓(xùn)練好的Transformer函數(shù)序列化并存為文件。
要加載模型也很簡單,只要調(diào)用joblib.load()就好了。

Sklearn對Pickle做了一下封裝和優(yōu)化,但這并不能解決Pickle本身的一些限制,例如:
版本兼容問題,不同的Python,Pickle,Sklearn的版本,生成的序列化文件并不兼容
安全性問題,例如序列化的文件中被人注入惡意代碼
擴(kuò)展問題,你自己寫了一個擴(kuò)展類,無法序列化,或者你在Python中調(diào)用了C函數(shù)
模型的管理,如果我生成了不同版本的模型,該如何管理
Spark
Spark的Pipeline和Model都支持Save到文件,然后可以很方便的在另一個Context中加載。
訓(xùn)練的代碼如下:


模型加載的代碼如下:

調(diào)用model的toDebugString方法可以看到分類器的內(nèi)部細(xì)節(jié)。






下圖是Spark存儲的Piple模型的目錄結(jié)構(gòu):

我們可以看到,它包含了元數(shù)據(jù)Pipeline的五個階段的數(shù)據(jù),這里的文件都是二進(jìn)制的數(shù)據(jù),只有Spark自己可以加載。
Tensorflow
最后我們來看一下Tensorflow。Tensorflow提供了tf.train.Saver來導(dǎo)出他的模型到元圖(MetaGraph)。

導(dǎo)出的模型會包含以下文件:

其中checkpoint是元數(shù)據(jù),包含其它文件的路徑信息。還包含了一個Pickle文件和其它幾個checkpiont文件??梢钥闯?,Tensorflow也利用了Python的Pickle機(jī)制來存儲模型,并在這之外加入了額外的元數(shù)據(jù)。
模型加載的代碼如下:

這里要注意的是,RandomForest不是tensforflow的核心包,所以在模型加載的時候必須tensorflow.contrib.tensor_forest.python.tensor_forest, 否則模型是無法成功加載的。因?yàn)椴患虞d的話tensor_forest中定義的一些屬性會缺失。
另外就是Tensorflow也可以存儲計算圖,調(diào)用tf.train.write_graph()方法可以把圖定義存儲下來。當(dāng)然也可以在TesnsorBoard中展示該圖。

好了,我們看到,Sklearn,Spark和Tensorflow都提供了自己的模型持久化的方法,那么簡單來說,只要使用一個web服務(wù)器例如Flask,加一些模型加載和管理的方法,然后暴露REST API就可以提供預(yù)測服務(wù)了,是不是很簡單呢?
其實(shí)要在生產(chǎn)環(huán)境下提供服務(wù),還需要面對很多其它的挑戰(zhàn),例如:
在云上如何擴(kuò)展和伸縮
如何進(jìn)行性能調(diào)優(yōu)
如何管理模型的版本
安全性
如何持續(xù)集成和持續(xù)部署
如何支持AB測試
為了解決模型部署的挑戰(zhàn),不同的組織開發(fā)了一些開源的工具,例如:Clipper,Seldon,MFlow,MLeap,Oracle Graphpipe,MXnet model server?等等,我們就選其中幾個看個究竟。
Clipper
Clipper是由UC BerkeleyRISE Lab開發(fā)的, 在用戶應(yīng)用和機(jī)器學(xué)習(xí)模型之間的一個提供預(yù)測服務(wù)的系統(tǒng),通過解耦合用戶應(yīng)用和機(jī)器學(xué)習(xí)系統(tǒng)的方式,簡化部署流程。
它有以下功能:
利用簡單標(biāo)準(zhǔn)化的REST接口來簡化機(jī)器學(xué)習(xí)系統(tǒng)的集成,支持主要的機(jī)器學(xué)習(xí)框架。
使用開發(fā)模型相同的庫和環(huán)境簡化模型部署
利用可適配的Batching,緩存等技術(shù)改善吞吐量
通過智能選擇和合并模型來改善預(yù)測的準(zhǔn)確率
Clipper的架構(gòu)如下圖:

Clipper使用了容器和微服務(wù)技術(shù)來構(gòu)架架構(gòu)。使用Redis來管理配置,Prometheus來進(jìn)行監(jiān)控。Clipper支持使用Kubernetes或者本地的Docker來管理容器。
Clipper支持以下幾種模型:
純Python函數(shù)
PyShark
PyTorch
Tensorflow
MXnet
自定義
Clipper模型部署的基本過程如下,大家可以參考我的這個notebook
創(chuàng)建Clipper集群(使用K8s或者本地Docker)
創(chuàng)建一個應(yīng)用
訓(xùn)練模型
調(diào)用Clipper提供的模型部署方法部署模型,這里不同的工具需要調(diào)用不同的部署方法。部署時,會把訓(xùn)練好的Estimator利用CloudPickle之久化,本地構(gòu)建一個容器鏡像,部署到Docker或者K8s。
把模型和應(yīng)用關(guān)聯(lián)到一起,相當(dāng)于發(fā)布模型。然后就可以調(diào)用對應(yīng)的REST API來做預(yù)測了。
我試著把之前的三種工具的RomdomForest的例子用Clipper發(fā)布到我的Kubernetes集群,踩到了以下的坑坑:
我本地的Cloudpickle的版本太新,導(dǎo)致模型不能反序列化,參考這個Issue
Tensorflow在Pickle的時候失敗,應(yīng)該是調(diào)用了C的code
我的K8s運(yùn)行在AWS上,我在K8S上使用內(nèi)部IP失敗,clipper連接一直在使用外部的域名,導(dǎo)致無法部署PySpark的模型。
總之,除了Sklearn成功部署之外,Tensorflow和Spark都失敗了。
Seldon
Seldon是一家創(chuàng)辦于倫敦的公司,致力于提供對于基于開源軟件的機(jī)器學(xué)習(xí)系統(tǒng)的控制。Seldon Core是該公司開源的提供在Kubernetes上部署機(jī)器學(xué)習(xí)模型的工具。它擁有以下功能:
Python/Spark/H2O/R 的模型支持
REST API和gRPC接口
部署基于Model/Routers/Combiner/Transformers的圖的微服務(wù)
利用K8S來提供擴(kuò)展,安全性,監(jiān)控等等DevOps的功能

Seldon的使用過程如上圖,
首先在K8s上安裝Seldon Core,Seldon利用ksonnet,以CRD的形式安裝seldon core
利用S2i(s2i是openshift開源的一款工具,用于把代碼構(gòu)建成容器鏡像),構(gòu)建運(yùn)行時模型容器,并注冊到容器注冊表
編寫你的運(yùn)行圖,并提交到K8s來部署你的模型
Seldon支持基于四種基本單元,Model,Transformer, Router, Combiner來構(gòu)建你的運(yùn)行圖,并按照該圖在K8s創(chuàng)建對應(yīng)的資源和實(shí)例,來獲得AB測試,模型ensemble的功能。
例如下圖的幾個例子:
AB 測試

模型ensemble

復(fù)雜圖

圖模式是Seldon最大的亮點(diǎn),可以訓(xùn)練不同的模型,然后利用圖來組合出不同的運(yùn)行時,非常方便。
筆者嘗試在K8S上利用Seldon部署之前提到的三種工具生成的模型,都獲得了成功(代碼在這里)。這里分享一下遇到的幾個問題:
Seldon支持Java的Python,然而用運(yùn)行PySpark,這兩個都需要,所以我不得不自己構(gòu)建了一個鏡像,手工在Python鏡像上安裝Java。
因?yàn)槭褂肅DR的原因,我沒有找到有效改變?nèi)萜鞯膌iveness和readiness的設(shè)置,因?yàn)镾park初始化模型在Hadoop上,加載模型需要時間,總是readiness超時導(dǎo)致容器無法正常啟動,K8s不斷的重啟容器。所以我只好修改代碼,讓模型加載變成Lazy Load,但是這樣第一次REST Call會比較耗時,但是容器和服務(wù)總算是能夠正常啟動。
MLflow
MLflow是Databricks開發(fā)的開源系統(tǒng),用于管理機(jī)器學(xué)習(xí)的端到端的生命周期。
MLflow提供跟蹤,項目管理和模型管理的功能。使用MLFlow來提供一個基于Sklearn的模型服務(wù)非常簡單,

調(diào)用mlflow.sklearn.log_model(), MLflow創(chuàng)建以下的目錄來管理模型:

我們看到在artifacts目錄下有Python的pickle文件和另一個元數(shù)據(jù)文件,MLModel。

使用 mlflow sklearn serve -m model 就可以很方便的提供基于sklearn的模型服務(wù)了。
雖然MLFlow也號稱支持Spark和Tensorflow,但是他們都是基于Python來做,我嘗試使用,但是文檔和例子比較少,所以沒能成功。但原理上都是使用Pickle?元數(shù)據(jù)的方式。大家有興趣的可以嘗試一下。
關(guān)于部署功能,MLFlow的一個亮點(diǎn)是和Sagemaker,AzureML的支持。
MLeap
MLeap的目標(biāo)是提供一個在Spark和Sklearn之間可移植的模型格式,和運(yùn)行引擎。它包含:
????基于JSON的序列化
????運(yùn)行引擎
????Benchmark
MLeap的架構(gòu)如下圖:

這是一個使用MLeap導(dǎo)出Sklearn模型的例子:

導(dǎo)出的模型結(jié)構(gòu)如下圖所示:

這個是randonforest的模型json

我們可以看出MLeap把模型完全序列化成與代碼無關(guān)的JSON文件,這樣就可以在不同的運(yùn)行時工具Spark/Sklearn之間做到可移植。
MLeap對模型提供服務(wù),不需要依賴任何Sklearn或者Spark的代碼。只要啟動MLeap的Server,然后提交模型就好了。

下面的代碼用Scala在Spark 上訓(xùn)練一個同樣的Randonforest分類模型,并利用MLeap持久化模型。


導(dǎo)出的模型和之前的Sklearn具有相同的格式。
MLeap的問題在于要支持所有的算法,對于每一個算法都要實(shí)現(xiàn)對應(yīng)的序列化,這也使得它的需要很多的開發(fā)來支持客戶自定義的算法
總結(jié)
Seldon Core和K8S結(jié)合的很好,它提供的運(yùn)行圖的方式非常強(qiáng)大,它也是我實(shí)驗(yàn)中唯一一個能夠成功部署Sklearn,Spark和Tensorflow三種模型的工具,非常推薦!
Clipper提供基于K8s和Docker的模型部署,它的模型版本管理做得不錯,但是代碼不太穩(wěn)定,小問題不少,基于CloudPickle也有不少的限制,只能支持Python也是個問題。推薦給數(shù)據(jù)科學(xué)家有比較多的本地交互的情況。
MLFlow能夠提供很方便的基于Python的模型服務(wù),但是缺乏和容器的結(jié)合。但是它能夠支持和Sagemaker,AzureML等云的支持。推薦給已經(jīng)在使用這些云的玩家。
MLeap的特色是支持模型的可交互性,也就是說我可以把sklearn訓(xùn)練的模型導(dǎo)出在Spark上運(yùn)行,這的功能很有吸引力,但是要支持全部的算法,它還有很長的路要走。關(guān)于機(jī)器學(xué)習(xí)模型標(biāo)準(zhǔn)化的問題,大家也可以關(guān)注PMML?,F(xiàn)階段各個工具對PMML的支持比較有限,隨著深度學(xué)習(xí)的廣泛應(yīng)用,PMML何去何從還未可知。
下表是對以上幾個工具的簡單總結(jié),供大家參考
?Model PersistentML ToolsKubernetest IntegrationVersionLicenseImplementation
Seldon CoreS2i + PickleTensorflow, SKlearn, Keras, R, H2O, Nodejs, PMMLYes0.3.2ApacheDocker + K8s CRD
ClipperPicklePython, PySpark, PyTorch, Tensorflow, MXnet, Customer ContainerYes0.3.0ApacheCPP / Python
MLFlowDirectory + MetadataPython, H2O, Kera, MLeap, PyTorch, Sklearn, Spark, Tensorflow, RNoAlphaApachePython
MLeap?JSONSpark,Sklearn, TensorflowNo0.12.0ApacheScala/Java