本文由攜程技術中心投遞,ID:ctriptech。做者:潘鵬舉,攜程酒店研發BI經理,負責酒店服務相關的業務建模工做,主要研究方向是用機器學習實現業務流程自動化、系統智能化、效率最優化,專一於算法實踐和應用。html
咱們常常會碰到一個問題:用了複雜的GBDT或者xgboost大大提高了模型效果,但是在上線的時候又犯難了,工程師說這個模型太複雜了,我無法上線,知足不了工程的要求,你幫我轉換成LR吧,直接套用一個公式就行了,速度飛速,確定知足工程要求。這個時候你又屁顛屁顛用回了LR,從新訓練了一下模型,內心默罵千百遍:工程能力真弱。前端
這些疑問,咱們之前碰到過,經過不斷的摸索,試驗出了不一樣的複雜機器學習的上線方法,來知足不一樣場景的需求。在這裏把實踐經驗整理分享,但願對你們有所幫助。(咱們的實踐經驗更可能是傾向於業務模型的上線流程,廣告和推薦級別的部署請自行繞道)。java
首先在訓練模型的工具上,通常三個模型訓練工具,Spark、R、Python。這三種工具各有千秋,之後有時間,我寫一下三種工具的使用心得。針對不一樣的模型使用場景,爲了知足不一樣的線上應用的要求,會用不一樣的上線方法。
.
.
.python
若是是實時的、小數據量的預測應用,則採用的SOA調用Rserve或者python-httpserve來進行應用;這種應用方式有個缺點是須要啓用服務來進行預測,也就是須要跨環境,從Java跨到R或者Python環境。對於性能,基本上咱們用Rserver方式,針對一次1000條或者更少請求的預測,能夠控制95%的結果在100ms內返回結果,100ms能夠知足工程上的實踐要求。更大的數據量,好比10000/次,100000/次的預測,咱們目前評估下來知足不了100ms的要求,建議分批進行調用或者採用多線程請求的方式來實現。linux
若是是實時、大數據量的預測應用,則會採用SOA,訓練好的模型轉換成PMML(關於如何轉換,我在下面會詳細描述),而後把模型封裝成一個類,用Java調用這個類來預測。用這種方式的好處是SOA不依賴於任何環境,任何計算和開銷都是在Java內部裏面消耗掉了,因此這種工程級別應用速度很快、很穩定。用此種方法也是要提供兩個東西,模型文件和預測主類;git
若是是Offline(離線)預測的,D+1天的預測,則能夠不用考慮第一、2中方式,能夠簡單的使用Rscript x.R或者python x.py的方式來進行預測。使用這種方式須要一個調度工具,若是公司沒有統一的調度工具,你用shell的crontab作定時調用就能夠了。github
以上三種作法,都會用SOA裏面進行數據處理和變換,只有部分變換會在提供的Function或者類進行處理,通常性都建議在SOA裏面處理好,不然性能會變慢。redis
大概場景羅列完畢,簡要介紹一下各不一樣工具的線上應用的實現方式。
.
.
.算法
大部分模型均可以用PMML的方式實現,PMML的使用方法調用範例見:shell
jpmml的說明文檔:GitHub - jpmml/jpmml-evaluator: Java Evaluator API for PMML;
Java調用PMML的範例(PPJUtils/java/pmml at master · pjpan/PPJUtils · GitHub),此案例是咱們的工程師寫的範例,你們能夠根據此案例進行修改便可;
Jpmml支持的轉換語言,主流的機器學習語言都支持了,深度學習類除外;
從下圖能夠看到,它支持R、python和spark、xgboost等模型的轉換,用起來很是方便。
.
.
.
python-sklearn裏面的模型都支持,也支持xgboost,而且PCA,歸一化能夠封裝成preprocess轉換成PMML,因此調用起來很方便;
特別須要注意的是:缺失值的處理會影響到預測結果,你們能夠能夠看一下;
用PMML方式預測,模型預測一條記錄速度是1ms,能夠用這個預測來預估一下根據你的數據量,總體的速度有多少。
.
這裏我介紹另外一種的上線方式:Rserve。具體實現方式是:用SOA調用Rserve的方式去實現,咱們會在服務器上部署好R環境和安裝好Rserve,而後用JAVA寫好SOA接口,調用Rserve來進行預測;
java調用Rserve方式見網頁連接:Rserve - Binary R server;
centos的Rserve搭建方法見:centos -Rserve的搭建,這裏詳細描述了Rserve的搭建方式。
Rserve方式能夠批量預測,跟PMML的單個預測方式相比,在少數據量的時候,PMML速度更快,可是若是是1000一次一批的效率上看,Rserve的方式會更快;用Rserve上線的文件只須要提供兩個:
模型結果文件(XX.Rdata);
預測函數(Pred.R)。
Rserve_1啓動把模型結果(XX.Rdata)常駐內存。預測須要的輸入Feature都在Java裏定義好不一樣的變量,而後你用Java訪問Rserve_1,調用Pred.R進行預測,獲取返回的List應用在線上。最後把相關的輸入輸出存成log進行數據覈對。
Pred.R <- function(x1,x2,x3){ data <- cbind(x1,x2,x3) # feature engineering score <- predict(modelname, data, type = 'prob') return(list(score)) }
.
Spark模型的上線就相對簡單一些,咱們用Scala訓練好模型(通常性咱們都用xgboost訓練模型)而後寫一個Java Class,直接在JAVA中先獲取數據,數據處理,把處理好的數據存成一個數組,而後調用模型Class進行預測。模型文件也會提早load在內存裏面,存在一個進程裏面,而後咱們去調用這個進程來進行預測。因此速度蠻快的。
Spark模型上線,放在spark集羣,不脫離spark環境,方便,須要本身打jar包;
咱們這裏目前尚未嘗試過,有一篇博客寫到了若是把spark模型導出PMML,而後提交到spark集羣上來調用,你們能夠參考一下:Spark加載PMML進行預測。
4、只用Linux的Shell來調度模型的實現方法-簡單粗暴
由於有些算法工程師想快速迭代,把模型模擬線上線看一下效果,因此針對離線預測的模型形式,還有一種最簡單粗暴的方法,這種方法開發快速方便,具體作法以下:
寫一下R的預測腳本,好比predict.R,是你的主預測的模型;
而後用shell封裝成xx.sh,好比predict.sh,shell裏面調用模型,存儲數據;
predict.sh的寫法以下:
# 數據導出 data_filename = xxx file_date = xxx result = xxx updatedt = xxx cd path hive -e "USE tmp_xxxdb;SELECT * FROM db.table1;" > ${data_filname}; # R腳本預測 Rscript path/predict.R $file_date if [ $? -ne 0 ] then echo "Running RScript Failure" fi # R預測的結果導入Hive表 list1="use tmp_htlbidb; load data local inpath 'path/$result' overwrite into table table2 partition(dt='${updatedt}');" hive -e "$list1"
最後用Crontab來進行調度,很簡單,如何設置crontab,度娘一下就行了。
>crontab -e ------------------------- ### 天天5點進行預測模型; 0 5 * * * sh predict.sh
.
.
.
區分offline和realtime數據,無論哪一種數據,咱們根據key和不一樣的更新頻次,把數據放在Redis裏面去,設置不一樣的key和不一樣的過時時間; 大部分redis數據都會存放兩個批次的數據,用來預防沒法取到最新的數據,則用上一批次的數據來進行填充; 針對offline數據,用調度工具作好依賴,天天跑數據,並生成信號文件讓redis來進行讀取; 針對realtime數據,咱們區分兩種類型,一種是歷史+實時,好比最近30天的累計訂單量,則咱們會作兩步,第一部分是D+1以前的數據,存成A表,今天產生的實時數據,存儲B表,A和B表表結構相同,時效性不一樣;咱們分別把A表和B表的數據放在Redis上去,而後在SOA裏面對這兩部分數據實時進行計算; 模型的輸入輸出數據進行埋點,進行數據跟蹤,一是用來校驗數據,二來是用來監控API接口的穩定性,通常性咱們會用ES來進行log的查看和性能方面的監控; 任何接口都須要有容災機制,若是接口超時,前端須要進行容災,當即放棄接口調用數據,返回一個默認安全的數值,這點對於工程上很是重要。 以上就是咱們在模型部署的經驗分享,歡迎你們來找我一塊兒探討相關工程上的最佳實踐。