你是一名數(shù)據(jù)科學(xué)家/算法工程師,在 Python/R/Spark/MATLAB(業(yè)界有幾個(gè)用?)等環(huán)境下用最愛的機(jī)器學(xué)習(xí)框架訓(xùn)練好了模型,準(zhǔn)確度不錯(cuò)。想就這樣交差?公司當(dāng)初招聘你難道就為了看一個(gè) 98% 的數(shù)字,或者期待你建立新算法好發(fā)表論文?當(dāng)然是要促進(jìn)業(yè)務(wù)。于是問題來了,你并不能保證業(yè)務(wù)平臺(tái)上能原封不動(dòng)部署原本運(yùn)行在個(gè)人電腦上的代碼,簡(jiǎn)單的例子:
非 x86 平臺(tái)對(duì) Python 的 NumPy 庫(kù)支持較為有限——移動(dòng)平臺(tái)最好不要指望直接運(yùn)行或調(diào)用 Python。
iOS 應(yīng)用商店禁止模擬器類 app,包括 Python 解釋器。
嵌入式市場(chǎng)有 MicroPython,但比起原生 C 資源消耗還是太大,且也有兼容性問題。
另一方面,我們一般不想讓之前訓(xùn)練的模型直接報(bào)廢,而在新平臺(tái)上分別用其原生工具重新訓(xùn)練(況且還不是所有平臺(tái)都能這樣做——要是一塊 Cortex-M 微處理器呢?)。所以,一次訓(xùn)練、跨平臺(tái)部署是不少算法工程師必須要跨過的坎。
本文將試圖簡(jiǎn)介在移動(dòng)平臺(tái)等處部署機(jī)器學(xué)習(xí)模型的方法,并闡述個(gè)人體驗(yàn)后所覺之利弊。目前只涉及線下學(xué)習(xí)線上預(yù)測(cè)的簡(jiǎn)單情況,暫不考慮線上學(xué)習(xí)。雖然討論 scikit-learn 所生成模型的部署問題,但希望對(duì)其他庫(kù)和其他環(huán)境也能有舉一反三之效。
如果是 PC 或服務(wù)器等以 x86 架構(gòu)為主的非移動(dòng)平臺(tái),考慮到其本身對(duì) NumPy 支持較好,可以采取直接調(diào)用 Python 代碼的思路,典型的工具包括 Jython(http://www.jython.org/*
"); background-size: cover; background-position: 0px 2px;">* )和 Jep(https://github.com/mrj0/jep*
"); background-size: cover; background-position: 0px 2px;">* )等。
對(duì)于移動(dòng)平臺(tái),由前所述直接調(diào)用 Python 代碼不可行,只能考慮轉(zhuǎn)制,有兩種思路可供選擇:
- 轉(zhuǎn)換成跨平臺(tái)通用格式,典型如 PMML(http://dmg.org/pmml/v4-3/GeneralStructure.html*
"); background-size: cover; background-position: 0px 2px;">* )。例如在 Java 平臺(tái)上,Java PMML API(https://github.com/jpmml*
"); background-size: cover; background-position: 0px 2px;">* )提供了各類接口;在 Android 上由于平臺(tái)對(duì) XML 解析的限制有人提供了 jpmml-android(https://github.com/jpmml/jpmml-android*
"); background-size: cover; background-position: 0px 2px;">* )示例項(xiàng)目,其中包含一個(gè) Maven 插件,將 PMML 文件序列化后編譯為一個(gè)靜態(tài)庫(kù)。簡(jiǎn)單來說,將任何 scikit-learn 模型用 sklearn2pmml(https://github.com/jpmml/sklearn2pmml*
"); background-size: cover; background-position: 0px 2px;">* )導(dǎo)出為 PMML 文件后,放進(jìn) jpmml-android 項(xiàng)目的對(duì)應(yīng)位置,編譯后的 .pmml.ser 文件即可在任意 Android 項(xiàng)目中調(diào)用,方法可參照模板代碼。至于 iOS 則未受支持。目前以上所提及的 PMML 相關(guān)項(xiàng)目均已支持該語言最新標(biāo)準(zhǔn)(4.3),如條件限制只能使用舊標(biāo)準(zhǔn),則需要到 GitHub 相應(yīng)倉(cāng)庫(kù)下載支持舊標(biāo)準(zhǔn)的最后版本。 - 轉(zhuǎn)換成原生代碼,可以通過 sklearn-porter(https://github.com/nok/sklearn-porter*
"); background-size: cover; background-position: 0px 2px;">* )等實(shí)現(xiàn),盡管支持模型種類有限。將模型用 joblib dump 成 pkl 后(假設(shè)其名為 model.pkl,注意模型若為 Pipeline,則所有步驟均需得到 sklearn-porter 支持),命令行中運(yùn)行
python -m sklearn_porter -i model.pkl -l <目標(biāo)語言>
取決于模型大小,等候一段時(shí)間后即可見到原生語言的模型實(shí)現(xiàn),文件名可能為 brain.c 或與之類似。自動(dòng)生成的代碼可能需要手動(dòng)修改后才能編譯運(yùn)行。
以上兩種思路各有利弊。通用格式只需處理一次模型(如包括 Android 則為兩次),之后在各平臺(tái)上分別編寫代碼以調(diào)用,支持算法較多,但并非所有平臺(tái)都受到支持,且解析 PMML 格式效率不算高。原生代碼則需要每種語言編譯一次,自動(dòng)化框架所支持算法較少(剩下的則需要設(shè)法導(dǎo)出參數(shù)后手動(dòng)編寫),但在各自業(yè)務(wù)平臺(tái)上基本不存在兼容性問題,效率也較高。為數(shù)不多的例外,一是自動(dòng)生成的代碼對(duì)嵌入式系統(tǒng)仍不夠最優(yōu),可能需要較多人工編輯或直接手動(dòng)編寫,當(dāng)然這種情況下應(yīng)該在建模時(shí)即優(yōu)先考慮復(fù)雜度;二是 Java 單個(gè)方法字節(jié)碼不能超過 64 KB,但機(jī)器學(xué)習(xí)模型稍大就會(huì)達(dá)到此限制,故 Java 上仍以 jpmml 為佳。
希望能對(duì)讀者有所幫助。歡迎評(píng)論切磋。
轉(zhuǎn)自 https://zhuanlan.zhihu.com/p/27772080