談?wù)剻C(jī)器學(xué)習(xí)模型的部署

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

上圖的過程是一個(gè)數(shù)據(jù)科學(xué)項(xiàng)目所要經(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é)家們不同的選擇,同時(shí)也給模型的部署帶來了不同的挑戰(zhàn)坯墨。

我們先來簡(jiǎn)單的看一看機(jī)器學(xué)習(xí)的模型是如何部署寂汇,它又會(huì)遇到那些挑戰(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ù)序列化并存為文件。

要加載模型也很簡(jiǎn)單钧排,只要調(diào)用joblib.load()就好了敦腔。

Sklearn對(duì)Pickle做了一下封裝和優(yōu)化,但這并不能解決Pickle本身的一些限制恨溜,例如:

版本兼容問題符衔,不同的Python,Pickle糟袁,Sklearn的版本柏腻,生成的序列化文件并不兼容

安全性問題,例如序列化的文件中被人注入惡意代碼

擴(kuò)展問題系吭,你自己寫了一個(gè)擴(kuò)展類,無法序列化颗品,或者你在Python中調(diào)用了C函數(shù)

模型的管理肯尺,如果我生成了不同版本的模型沃缘,該如何管理

Spark

Spark的Pipeline和Model都支持Save到文件,然后可以很方便的在另一個(gè)Context中加載则吟。

訓(xùn)練的代碼如下:

模型加載的代碼如下:

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


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

我們可以看到,它包含了元數(shù)據(jù)Pipeline的五個(gè)階段的數(shù)據(jù)氓仲,這里的文件都是二進(jìn)制的數(shù)據(jù)水慨,只有Spark自己可以加載。

Tensorflow

最后我們來看一下Tensorflow敬扛。Tensorflow提供了tf.train.Saver來導(dǎo)出他的模型到元圖(MetaGraph)晰洒。

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

其中checkpoint是元數(shù)據(jù),包含其它文件的路徑信息啥箭。還包含了一個(gè)Pickle文件和其它幾個(gè)checkpiont文件谍珊。可以看出急侥,Tensorflow也利用了Python的Pickle機(jī)制來存儲(chǔ)模型砌滞,并在這之外加入了額外的元數(shù)據(jù)。

模型加載的代碼如下:

這里要注意的是坏怪,RandomForest不是tensforflow的核心包贝润,所以在模型加載的時(shí)候必須tensorflow.contrib.tensor_forest.python.tensor_forest, 否則模型是無法成功加載的。因?yàn)椴患虞d的話tensor_forest中定義的一些屬性會(huì)缺失铝宵。

另外就是Tensorflow也可以存儲(chǔ)計(jì)算圖打掘,調(diào)用tf.train.write_graph()方法可以把圖定義存儲(chǔ)下來。當(dāng)然也可以在TesnsorBoard中展示該圖捉超。

好了胧卤,我們看到,Sklearn拼岳,Spark和Tensorflow都提供了自己的模型持久化的方法枝誊,那么簡(jiǎn)單來說,只要使用一個(gè)web服務(wù)器例如Flask惜纸,加一些模型加載和管理的方法叶撒,然后暴露REST API就可以提供預(yù)測(cè)服務(wù)了,是不是很簡(jiǎn)單呢耐版?

其實(shí)要在生產(chǎn)環(huán)境下提供服務(wù)祠够,還需要面對(duì)很多其它的挑戰(zhàn),例如:

在云上如何擴(kuò)展和伸縮

如何進(jìn)行性能調(diào)優(yōu)

如何管理模型的版本

安全性

如何持續(xù)集成和持續(xù)部署

如何支持AB測(cè)試

為了解決模型部署的挑戰(zhàn)粪牲,不同的組織開發(fā)了一些開源的工具古瓤,例如:ClipperSeldonMFlow落君,MLeap穿香,Oracle GraphpipeMXnet model server?等等绎速,我們就選其中幾個(gè)看個(gè)究竟皮获。

Clipper

Clipper是由UC BerkeleyRISE Lab開發(fā)的, 在用戶應(yīng)用和機(jī)器學(xué)習(xí)模型之間的一個(gè)提供預(yù)測(cè)服務(wù)的系統(tǒng)纹冤,通過解耦合用戶應(yīng)用和機(jī)器學(xué)習(xí)系統(tǒng)的方式洒宝,簡(jiǎn)化部署流程。

它有以下功能:

利用簡(jiǎn)單標(biāo)準(zhǔn)化的REST接口來簡(jiǎn)化機(jī)器學(xué)習(xí)系統(tǒng)的集成萌京,支持主要的機(jī)器學(xué)習(xí)框架雁歌。

使用開發(fā)模型相同的庫(kù)和環(huán)境簡(jiǎn)化模型部署

利用可適配的Batching,緩存等技術(shù)改善吞吐量

通過智能選擇和合并模型來改善預(yù)測(cè)的準(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模型部署的基本過程如下较坛,大家可以參考我的這個(gè)notebook

創(chuàng)建Clipper集群(使用K8s或者本地Docker)

創(chuàng)建一個(gè)應(yīng)用

訓(xùn)練模型

調(diào)用Clipper提供的模型部署方法部署模型,這里不同的工具需要調(diào)用不同的部署方法扒最。部署時(shí)丑勤,會(huì)把訓(xùn)練好的Estimator利用CloudPickle之久化,本地構(gòu)建一個(gè)容器鏡像吧趣,部署到Docker或者K8s法竞。

把模型和應(yīng)用關(guān)聯(lián)到一起,相當(dāng)于發(fā)布模型强挫。然后就可以調(diào)用對(duì)應(yīng)的REST API來做預(yù)測(cè)了岔霸。

我試著把之前的三種工具的RomdomForest的例子用Clipper發(fā)布到我的Kubernetes集群,踩到了以下的坑坑:

我本地的Cloudpickle的版本太新俯渤,導(dǎo)致模型不能反序列化呆细,參考這個(gè)Issue

Tensorflow在Pickle的時(shí)候失敗,應(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)辦于倫敦的公司柜蜈,致力于提供對(duì)于基于開源軟件的機(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)行時(shí)模型容器,并注冊(cè)到容器注冊(cè)表

編寫你的運(yùn)行圖瑰排,并提交到K8s來部署你的模型

Seldon支持基于四種基本單元贯要,Model,Transformer椭住, Router崇渗, Combiner來構(gòu)建你的運(yùn)行圖,并按照該圖在K8s創(chuàng)建對(duì)應(yīng)的資源和實(shí)例京郑,來獲得AB測(cè)試宅广,模型ensemble的功能。

例如下圖的幾個(gè)例子:

AB 測(cè)試

模型ensemble

復(fù)雜圖

圖模式是Seldon最大的亮點(diǎn)些举,可以訓(xùn)練不同的模型跟狱,然后利用圖來組合出不同的運(yùn)行時(shí),非常方便户魏。

筆者嘗試在K8S上利用Seldon部署之前提到的三種工具生成的模型驶臊,都獲得了成功(代碼在這里)。這里分享一下遇到的幾個(gè)問題:

Seldon支持Java的Python叼丑,然而用運(yùn)行PySpark关翎,這兩個(gè)都需要,所以我不得不自己構(gòu)建了一個(gè)鏡像鸠信,手工在Python鏡像上安裝Java纵寝。

因?yàn)槭褂肅DR的原因,我沒有找到有效改變?nèi)萜鞯膌iveness和readiness的設(shè)置症副,因?yàn)镾park初始化模型在Hadoop上店雅,加載模型需要時(shí)間,總是readiness超時(shí)導(dǎo)致容器無法正常啟動(dòng)贞铣,K8s不斷的重啟容器闹啦。所以我只好修改代碼,讓模型加載變成Lazy Load辕坝,但是這樣第一次REST Call會(huì)比較耗時(shí)窍奋,但是容器和服務(wù)總算是能夠正常啟動(dòng)。

MLflow

MLflow是Databricks開發(fā)的開源系統(tǒng),用于管理機(jī)器學(xué)習(xí)的端到端的生命周期琳袄。

MLflow提供跟蹤江场,項(xiàng)目管理和模型管理的功能。使用MLFlow來提供一個(gè)基于Sklearn的模型服務(wù)非常簡(jiǎn)單窖逗,

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

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

使用 mlflow sklearn serve -m model 就可以很方便的提供基于sklearn的模型服務(wù)了碎紊。

雖然MLFlow也號(hào)稱支持Spark和Tensorflow佑附,但是他們都是基于Python來做,我嘗試使用仗考,但是文檔和例子比較少音同,所以沒能成功。但原理上都是使用Pickle?元數(shù)據(jù)的方式秃嗜。大家有興趣的可以嘗試一下权均。

關(guān)于部署功能,MLFlow的一個(gè)亮點(diǎn)是和Sagemaker锅锨,AzureML的支持叽赊。

MLeap

MLeap的目標(biāo)是提供一個(gè)在Spark和Sklearn之間可移植的模型格式,和運(yùn)行引擎橡类。它包含:

????基于JSON的序列化

????運(yùn)行引擎

????Benchmark

MLeap的架構(gòu)如下圖:

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

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

這個(gè)是randonforest的模型json

我們可以看出MLeap把模型完全序列化成與代碼無關(guān)的JSON文件蛇尚,這樣就可以在不同的運(yùn)行時(shí)工具Spark/Sklearn之間做到可移植。

MLeap對(duì)模型提供服務(wù)顾画,不需要依賴任何Sklearn或者Spark的代碼取劫。只要啟動(dòng)MLeap的Server,然后提交模型就好了研侣。

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

導(dǎo)出的模型和之前的Sklearn具有相同的格式庶诡。

MLeap的問題在于要支持所有的算法惦银,對(duì)于每一個(gè)算法都要實(shí)現(xiàn)對(duì)應(yīng)的序列化,這也使得它的需要很多的開發(fā)來支持客戶自定義的算法

總結(jié)

Seldon Core和K8S結(jié)合的很好末誓,它提供的運(yùn)行圖的方式非常強(qiáng)大扯俱,它也是我實(shí)驗(yàn)中唯一一個(gè)能夠成功部署Sklearn,Spark和Tensorflow三種模型的工具喇澡,非常推薦迅栅!

Clipper提供基于K8s和Docker的模型部署,它的模型版本管理做得不錯(cuò)晴玖,但是代碼不太穩(wěn)定读存,小問題不少为流,基于CloudPickle也有不少的限制,只能支持Python也是個(gè)問題让簿。推薦給數(shù)據(jù)科學(xué)家有比較多的本地交互的情況敬察。

MLFlow能夠提供很方便的基于Python的模型服務(wù),但是缺乏和容器的結(jié)合尔当。但是它能夠支持和Sagemaker莲祸,AzureML等云的支持。推薦給已經(jīng)在使用這些云的玩家椭迎。

MLeap的特色是支持模型的可交互性虫给,也就是說我可以把sklearn訓(xùn)練的模型導(dǎo)出在Spark上運(yùn)行,這的功能很有吸引力侠碧,但是要支持全部的算法,它還有很長(zhǎng)的路要走缠黍。關(guān)于機(jī)器學(xué)習(xí)模型標(biāo)準(zhǔn)化的問題弄兜,大家也可以關(guān)注PMML。現(xiàn)階段各個(gè)工具對(duì)PMML的支持比較有限瓷式,隨著深度學(xué)習(xí)的廣泛應(yīng)用替饿,PMML何去何從還未可知。

下表是對(duì)以上幾個(gè)工具的簡(jiǎn)單總結(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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末视卢,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子廊驼,更是在濱河造成了極大的恐慌据过,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,185評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妒挎,死亡現(xiàn)場(chǎng)離奇詭異绳锅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)酝掩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,445評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門鳞芙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人期虾,你說我怎么就攤上這事原朝。” “怎么了镶苞?”我有些...
    開封第一講書人閱讀 157,684評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵喳坠,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我宾尚,道長(zhǎng)丙笋,這世上最難降的妖魔是什么谢澈? 我笑而不...
    開封第一講書人閱讀 56,564評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮御板,結(jié)果婚禮上锥忿,老公的妹妹穿的比我還像新娘。我一直安慰自己怠肋,他們只是感情好敬鬓,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,681評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著笙各,像睡著了一般钉答。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上杈抢,一...
    開封第一講書人閱讀 49,874評(píng)論 1 290
  • 那天壳快,我揣著相機(jī)與錄音,去河邊找鬼蠕搜。 笑死滔以,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的歼捐。 我是一名探鬼主播何陆,決...
    沈念sama閱讀 39,025評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼豹储!你這毒婦竟也來了贷盲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,761評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤剥扣,失蹤者是張志新(化名)和其女友劉穎巩剖,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體朦乏,經(jīng)...
    沈念sama閱讀 44,217評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡球及,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,545評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了呻疹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吃引。...
    茶點(diǎn)故事閱讀 38,694評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖刽锤,靈堂內(nèi)的尸體忽然破棺而出镊尺,到底是詐尸還是另有隱情,我是刑警寧澤并思,帶...
    沈念sama閱讀 34,351評(píng)論 4 332
  • 正文 年R本政府宣布庐氮,位于F島的核電站,受9級(jí)特大地震影響宋彼,放射性物質(zhì)發(fā)生泄漏弄砍。R本人自食惡果不足惜仙畦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,988評(píng)論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望音婶。 院中可真熱鬧慨畸,春花似錦、人聲如沸衣式。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,778評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)碴卧。三九已至弱卡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間住册,已是汗流浹背婶博。 一陣腳步聲響...
    開封第一講書人閱讀 32,007評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留荧飞,地道東北人凡蜻。 一個(gè)月前我還...
    沈念sama閱讀 46,427評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像垢箕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子兑巾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,580評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容