1. 程式人生 > 其它 >機器學習演算法線上部署方法

機器學習演算法線上部署方法

我們經常會碰到一個問題:用了複雜的GBDT或者xgboost大大提升了模型效果,可是在上線的時候又犯難了,工程師說這個模型太複雜了,我沒法上線,滿足不了工程的要求,你幫我轉換成LR吧,直接套用一個公式就好了,速度飛速,肯定滿足工程要求。這個時候你又屁顛屁顛用回了LR,重新訓練了一下模型,心裡默罵千百遍:工程能力真弱。

這些疑問,我們以前碰到過,通過不斷的摸索,試驗出了不同的複雜機器學習的上線方法,來滿足不同場景的需求。在這裡把實踐經驗整理分享,希望對大家有所幫助。(我們的實踐經驗更多是傾向於業務模型的上線流程,廣告和推薦級別的部署請自行繞道)。

首先在訓練模型的工具上,一般三個模型訓練工具,Spark、R、Python。這三種工具各有千秋,以後有時間,我寫一下三種工具的使用心得。針對不同的模型使用場景,為了滿足不同的線上應用的要求,會用不同的上線方法。

一、總結來說,大體會區分這三種場景,請大家對號入座,酌情使用

  • 如果是實時的、小資料量的預測應用,則採用的SOA呼叫Rserve或者python-httpserve來進行應用;這種應用方式有個缺點是需要啟用服務來進行預測,也就是需要跨環境,從Java跨到R或者Python環境。對於效能,基本上我們用Rserver方式,針對一次1000條或者更少請求的預測,可以控制95%的結果在100ms內返回結果,100ms可以滿足工程上的實踐要求。更大的資料量,比如10000/次,100000/次的預測,我們目前評估下來滿足不了100ms的要求,建議分批進行呼叫或者採用多執行緒請求的方式來實現。
  • 如果是實時、大資料量的預測應用,則會採用SOA,訓練好的模型轉換成PMML(關於如何轉換,我在下面會詳細描述),然後把模型封裝成一個類,用Java呼叫這個類來預測。用這種方式的好處是SOA不依賴於任何環境,任何計算和開銷都是在Java內部裡面消耗掉了,所以這種工程級別應用速度很快、很穩定。用此種方法也是要提供兩個東西,模型檔案和預測主類;
  • 如果是Offline(離線)預測的,D+1天的預測,則可以不用考慮第1、2中方式,可以簡單的使用Rscript x.R或者python x.py的方式來進行預測。使用這種方式需要一個排程工具,如果公司沒有統一的排程工具,你用shell的crontab做定時呼叫就可以了。

以上三種做法,都會用SOA裡面進行資料處理和變換,只有部分變換會在提供的Function或者類進行處理,一般性都建議在SOA裡面處理好,否則效能會變慢。

大概場景羅列完畢,簡要介紹一下各不同工具的線上應用的實現方式。

二、如何轉換PMML,並封裝PMML

大部分模型都可以用PMML的方式實現,PMML的使用方法呼叫範例見:

  • 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等模型的轉換,用起來非常方便。

三、接下來說一下各個演算法工具的工程實踐

1.python模型上線:我們目前使用了模型轉換成PMML上線方法。

  • python-sklearn裡面的模型都支援,也支援xgboost,並且PCA,歸一化可以封裝成preprocess轉換成PMML,所以呼叫起來很方便;
  • 特別需要注意的是:缺失值的處理會影響到預測結果,大家可以可以看一下;
  • 用PMML方式預測,模型預測一條記錄速度是1ms,可以用這個預測來預估一下根據你的資料量,整體的速度有多少。

2.R模型上線-這塊我們用的多,可以用R model轉換PMML的方式來實現。

這裡我介紹另一種的上線方式: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 engineeringscore <- predict(modelname, data, type = 'prob')return(list(score))
}

3.Spark模型上線-好處是脫離了環境,速度快。

Spark模型的上線就相對簡單一些,我們用scala訓練好模型(一般性我們都用xgboost訓練模型)然後寫一個Java Class,直接在JAVA中先獲取資料,資料處理,把處理好的資料存成一個數組,然後呼叫模型Class進行預測。模型檔案也會提前load在記憶體裡面,存在一個程序裡面,然後我們去呼叫這個程序來進行預測。所以速度蠻快的。

  • Spark模型上線,放在spark叢集,不脫離spark環境,方便,需要自己打jar包;
  • 我們這裡目前還沒有嘗試過,有一篇部落格寫到了如果把spark模型匯出PMML,然後提交到spark叢集上來呼叫,大家可以參考一下:Spark載入PMML進行預測。

四、只用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

五、說完了部署上線,說一下模型資料流轉的注意事項

  1. 區分offline和realtime資料,不管哪種資料,我們根據key和不同的更新頻次,把資料放在redis裡面去,設定不同的key和不同的過期時間;
  2. 大部分redis資料都會存放兩個批次的資料,用來預防無法取到最新的資料,則用上一批次的資料來進行填充;
  3. 針對offline資料,用排程工具做好依賴,每天跑資料,並生成訊號檔案讓redis來進行讀取;
  4. 針對realtime資料,我們區分兩種型別,一種是歷史+實時,比如最近30天的累計訂單量,則我們會做兩步,第一部分是D+1之前的資料,存成A表,今天產生的實時資料,儲存B表,A和B表表結構相同,時效性不同;我們分別把A表和B表的資料放在Redis上去,然後在SOA裡面對這兩部分資料實時進行計算;
  5. 模型的輸入輸出資料進行埋點,進行資料跟蹤,一是用來校驗資料,二來是用來監控API介面的穩定性,一般性我們會用ES來進行log的檢視和效能方面的監控;
  6. 任何介面都需要有容災機制,如果介面超時,前端需要進行容災,立即放棄介面呼叫資料,返回一個預設安全的數值,這點對於工程上非常重要。