PMML部署演算法模型
標籤:模型部署
PMML
對於演算法工程師來說,如何將訓練好的模型成功部署上線也是工作的重要環節之一。當然,對於python訓練的模型,在python環境下部署是個很自然的想法,但是在我本人大部分的實際專案中,都是需要實現模型的跨平臺(比如java環境)部署,而PMML(Predictive Model Markup Language, 預測模型標記語言)就是解決跨平臺部署的一種方式。
1. PMML是什麼? 🤔
PMML是一套基於XML標準,與平臺和環境無關的模型表示語言。它主要是通過了XML schema定義和儲存了一個演算法模型的核心元素:
- 資料字典:描述輸入資料
- 資料轉換:定義了原始資料資料預處理的方式,比如標準化、缺失值處理、啞變數的生成等
- 模型定義:模型的型別及引數,比如樹模型的分裂節點等
- 模型輸出:模型的輸出結果
不難看出,通過定義PMML中的所有核心元素,可以完成資料探勘的所有流程,即後端開發人員部署時,只需要將資料讀取後,呼叫PMML檔案,然後就能得到輸出資料,而不用關注資料轉化、模型引數等問題,加快了模型的部署效率。
2. Python怎麼實現PMML檔案打包? 💻
本文采用Iris
鳶尾花資料集作為例子,通過Pipeline的方式訓練一個XGBoost分類器,然後將其打包輸出PMML檔案。Pipeline的方式是指,將許多不同的資料預處理步驟和一個或者多個模型,像拼接管道一樣按順序合併在一起,從而完成資料探勘的所有階段,簡化模型的訓練和部署。
Iris
鳶尾花資料集,包含4個特徵變數(sepal length, sepal width, petal length和petal width)以及1個類別標籤(0-setosa, 1-versicolor, 2-virginica),我們的模型目標是:基於特徵變數,將3類鳶尾花區分開。
Step 0: 匯入所需包
```python
import packages
import pandas as pd import numpy as np from sklearn import datasets from sklearn.model_selection import train_test_split from sklearn_pandas import DataFrameMapper from sklearn.preprocessing import StandardScaler from sklearn2pmml import PMMLPipeline from sklearn2pmml import sklearn2pmml from xgboost import XGBClassifier ```
Step 1: 使用python訓練一個模型
```python
read data
iris = datasets.load_iris() X = pd.DataFrame(iris.data, columns=iris.feature_names) y = iris.target
split train and test dataset
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=123)
define datamapper
mapper = DataFrameMapper([ (["sepal length (cm)", "sepal width (cm)"], StandardScaler()), (["petal length (cm)"], None) ], df_out=True)
define a model
xgb = XGBClassifier(n_estimators=5, seed=123)
make a pipeline
pip_model = PMMLPipeline([ ('mapper', mapper), ("classifier", xgb)] )
train a model & predict on test data
pip_model.fit(X_train, y_train) pred_prob_pip = pip_model.predict_proba(X_test) ```
在例子中,我們先使用DataFrameMapper
定義了輸入的特徵變數只包含3個(去除了petal width),並且只對sepal length和sepal width進行標準化處理,而petal length則不做任何處理。然後定義了一個XGBClassifier
,最後通過PMMLPipeline
將兩個資料處理流程和模型結合在一起進行訓練。
Step 2: 儲存為PMML檔案
```python
save model
sklearn2pmml(pip_model, "iris_model.pmml", with_repr = True) ```
輸出的PMML檔案可以由任何編輯器開啟,形式如下:
Step 3: python中呼叫PMML校驗結果
python
from pypmml import Model
model = Model.fromFile('iris_model.pmml')
pred_prob_reloaded_model = model.predict(X_test)
重新讀取PMML檔案和原Pipeline預測結果在python環境下應該保持一致。
3. 可能會遇到什麼坑?😂
上面的例子實現很簡單,但是真正部署時,總會遇到一些坑,畢竟大家都是在踩坑中成長的嘛。下面就列出我在部署PMML過程中遇見的一些問題,僅供參考。
-
坑1: 可以訓練模型但是卻不能生成pmml檔案
可能是由於環境原因導致,sklearn/sklearn2pmml/sklearn_pandas需要適配,而且當sklearn2pmml版本過高而打jar版本過低,則會導致檔案無法讀取的問題,本文使用版本資訊如下:
- sklearn2pmml = 0.53.0
- sklearn = 0.23.1
- sklearn_pandas = 2.2.0
-
坑2: Java呼叫PMML和原Pipeline模型預測不一致(正常情況下,小數點後5位應該保持一致)
導致這個問題的原因可能是兩個: (1)資料型別不一致;(2)缺失值的處理。
-
資料型別不一致,可以嘗試以下2個解決方案:
- 因為生成pmml檔案時,所有的變數預設是double型別,而有些分類變數是string型別,所以可以考慮對分類變數進行labelencoder處理成數值型
- 將pmml檔案中double改成string
-
缺失值的處理:當資料中存在缺失值,且不是為nan,而是以-9999代替時,PMML檔案需要在datamapper和模型中同時定義
-9999
為缺失值, 否則就會出現預測不一致現象。此時應該```python
define datamapper
mapper = DataFrameMapper([ (["sepal length (cm)", "sepal width (cm)"], StandardScaler()), (["petal length (cm)"], ContinuousDomain(missing_values=-9999.0, with_data = False)) ], df_out=True)
define a model
xgb = XGBClassifier(n_estimators=5, seed=123, missing=-9999.0) ```
注:使用
ContinuousDomain
後會根據訓練資料找到每個特徵的資料範圍,而當測試資料數顯超出此範圍的數值後會報錯,因此需要設定with_data=False
來去除這一限制。
-
-
坑3: 原Pipeline模型和python讀取PMML檔案模型預測結果不一致
這種情況很大程度上也和缺失值有關。如果在正確處理坑2的後,還出現此類問題,可能是由於python讀取PMML檔案模型預測的時候,對於缺失特徵也傳入並賦值
-9999
。正確做法是,使用pypmml呼叫PMML檔案,應該對缺失特徵不傳入,或者賦值為nan,這樣pypmml呼叫PMML檔案和原Pipeline模型預測結果就能保持一致。
敬請期待
- Python構造Pipeline模型
- 使用Scala呼叫python訓練的PMML
禁止無授權轉載,轉載請聯絡作者,否則作者將保留一切合法權利。