1. 程式人生 > >機器學習模型部署及線上預測

機器學習模型部署及線上預測

到目前為止,我們訓練的傳統機器學習模型都只能進行本地預測(本地呼叫test方法),那麼怎麼樣把我們的模型部署到線上,然後做線上實時預測呢?

我們的模型實際上就是一個y = f(x)函式,x是特徵資料,y是預測結果。我們訓練模型的目的就是為了得到f(x)函式的引數;
訓練完成後需要對引數進行序列化儲存,生成模型檔案,這一步叫做模型的匯出;
模型的部署即載入模型檔案並在記憶體組裝f(x)函式提供線上服務;
線上預測即轉換線上資料為模型所需要的特徵資料格式,然後呼叫線上服務,生成預測結果。所有的機器學習包括深度學習框架訓練的模型都是按照以上四個步驟進行部署和線上預測的,只是模型檔案的不同。

因為scikit-learn已經成為Python最重要的機器學習庫(沒有之一),並且到目前為止我們所有的機器學習模型都是通過它訓練的,下面主要介紹通過sklearn訓練的模型的部署方式:

模型訓練完成後,直接將模型匯出為PMML(Predictive Model Markup Language)檔案。注:PMML是資料探勘的一種通用的規範,它用統一的XML格式來描述我們生成的機器學習模型,無論你的模型是sklearn,R還是Spark MLlib生成的,我們都可以使用相應的方法將其轉化為PMML。關於PMML內部格式細節,請參考 PMML
 



clf = tree.DecisionTreeClassifier()
pipeline =PMMLPipeline([("classifier", clf)])
pipeline.fit(train_feature, train_target)
# 匯出PMML模型檔案
from sklearn2pmml import sklearn2pmml
sklearn2pmml(pipeline,"DecisionTree.pmml", with_repr = True)



或者在Python端先將模型序列化為pickle,再在Java端將pickle檔案轉為pmml:



clf = tree.DecisionTreeClassifier()
pipeline = PMMLPipeline([("classifier", clf)])
pipeline.fit(train_feature, train_target)
# 匯出pickle模型檔案
from sklearn.externals import joblib
joblib.dump(pipeline, "pipeline.pkl.z", compress = 9)



java -jar target/jpmml-sklearn-executable-1.5-SNAPSHOT.jar --pkl-input pipeline.pkl.z--pmml-output pipeline.pmml



2. 模型載入、部署、服務:實際中,一般將服務封裝為JavaWeb應用或RPC服務,在應用內部載入模型,部署服務。注:JPMML是一個強大的包含模型匯出、載入、部署等一條蛇服務的工具包。



private Evaluator loadPmml(){
InputStream is = newFileInputStream("D:/demo.pmml");
PMML pmml = org.jpmml.model.PMMLUtil.unmarshal(is);
ModelEvaluatorFactory modelEvaluatorFactory =
ModelEvaluatorFactory.newInstance();
Evaluator evaluator =modelEvaluatorFactory.newModelEvaluator(pmml);
return evaluator;
}
private int predict(Evaluator evaluator,inta, int b, int c, int d) {
Map<String, Integer> data = new  HashMap<String, Integer>();
data.put("x1", a);
data.put("x2", b);
data.put("x3", c);
data.put("x4", d);
List<InputField> inputFields =evaluator.getInputFields();
//過模型的原始特徵,從畫像中獲取資料,作為模型輸入
Map<FieldName, FieldValue> arguments =new LinkedHashMap<FieldName, FieldValue>();
for(InputField inputField : inputFields) {
FieldName inputFieldName = inputField.getName();  
Object rawValue = data.get(inputFieldName.getValue());
FieldValue inputFieldValue = inputField.prepare(rawValue);
arguments.put(inputFieldName, inputFieldValue);
}

Map<FieldName, ?> results =evaluator.evaluate(arguments);
List<TargetField> targetFields =evaluator.getTargetFields();

TargetField targetField = targetFields.get(0);
FieldName targetFieldName =targetField.getName();

Object targetFieldValue =results.get(targetFieldName);
System.out.println("target: " +targetFieldName.getValue() + " value: " + targetFieldValue);
int primitiveValue = -1;
if (targetFieldValue instanceof Computable)
{
 
Computable computable = (Computable) targetFieldValue;
 
primitiveValue = (Integer)computable.getResult();
}
System.out.println(a + " " + b +" " + c + " " + d + ":" + primitiveValue);
return primitiveValue;
}



PMML的確是跨平臺的利器,但是也會存在一些問題:

PMML為了滿足跨平臺通用性,犧牲了很多平臺獨有的優化,所以很多時候我們用演算法庫自己的儲存模型的API得到的模型檔案,要比生成的PMML模型檔案小很多;
PMML檔案載入速度也比演算法庫自己獨有格式的模型檔案載入慢很多。
PMML載入得到的模型和演算法庫自己獨有的模型相比,預測會有一點點的偏差,當然這個偏差並不大。比如某一個樣本,用sklearn的決策樹模型本地預測為類別1,但是如果我們把這個決策樹匯出為PMML,並用JAVA載入後,預測有較小的概率出現預測的結果不為類別1;
對於超大模型,比如大規模的整合學習模型(xgboost、隨機森林等)以及神經網路,生成的PMML檔案很容易得到幾個G,甚至上T,這時使用PMML檔案載入預測就不太合適了,此時推薦為模型建立一個專有的環境,就沒有必要去考慮跨平臺了。

文章轉載八斗問答