https://zhuanlan.zhihu.com/p/429842534
PMML全称预言模型标记模型(Predictive Model Markup Language),以XML 为载体呈现数据挖掘模型。
PMML的一个优点是可以跨语言跨平台,而不需考虑分析和预测过程中的具体实现细节。但其实对于很多灵活的自定义操作,还是需要考虑具体的实现细节。
本质上来说,pmml的角色类似于csv,python中的数据以csv的格式存储,然后java可以使用csvreader或c++ 使用csv-parser 来读取csv文件,从而实现不同编程语言之间的数据传输。
再说的简单点,模型的训练过程中虽然存在很多不确定性,但是目前业界应用的模型的推断的过程中大部分情况下是确定性的,既然是确定性的就可以通过语言来描述,比如说xgb模型,预测某个样本,先判断落在哪个叶子结点上,然后叶子结点权重加权求和再加个activation就可以得到预测结果了,既然可以通过语言描述,自然可以通过代码来描述,使用不同语言的代码来实现这个逻辑就可以了,但是这样明显太麻烦了,所以jpmml以及sklearn2pmml的项目出现了,把这些繁琐的逻辑都封装成现成的函数,实现的过程是类似的,只不过可以通过api来一键完成。
pmml使得模型的部署省去了很多的麻烦。主要原因在于jpmml以及其下属的sklearn2pmml提供了直接从python的sklearn api 到java代码的快速转换。说白了有人给你写了转换的接口,所以才能这么方便快速,简单来说,其实jpmml做的事情是把sklearn里的大部分api都用java实现了一遍,然后sklearn2pmml 转化的时候直接进行匹配,因此,一些自定义的py操作是没法进行正常转换的因为没有对应的java代码实现。如下
import numpy as npimport matplotlib.pyplot as plt%matplotlib inlineimport pandas as pdfrom sklearn import treefrom sklearn2pmml.pipeline import PMMLPipelinefrom sklearn2pmml import sklearn2pmmlimport osos.environ["PATH"] += os.pathsep + 'C:/Program Files/Java/jdk1.8.0_171/bin'X=[[1,2,3,1],[2,4,1,5],[7,8,3,6],[4,8,4,7],[2,5,6,9]]y=[0,1,0,2,1]pipeline = PMMLPipeline([("classifier", tree.DecisionTreeClassifier(random_state=9))]);pipeline.fit(X,y)sklearn2pmml(pipeline, ".\demo.pmml", with_repr = True)
如果是sklearn2pmml转化的结果,很多时候包含3部分,注释直接写下面了:
##################### 文件头部分,不必在意##################<?xml version="1.0" encoding="UTF-8" standalone="yes"?><PMML xmlns="http://www.dmg.org/PMML-4_3" version="4.3"><Header><Application name="JPMML-SkLearn" version="1.5.3"/><Timestamp>2018-06-24T05:47:17Z</Timestamp></Header>########### MiningBuildTask 根据你在py中定义的pmmlpipline自动生成相应的pipeline描述信息##############<MiningBuildTask><Extension>PMMLPipeline(steps=[('classifier', DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,max_features=None, max_leaf_nodes=None,min_impurity_decrease=0.0, min_impurity_split=None,min_samples_leaf=1, min_samples_split=2,min_weight_fraction_leaf=0.0, presort=False, random_state=9,splitter='best'))])</Extension></MiningBuildTask>################## 定义你建模过程中使用到的全部的变量以及对应类型等#########################<DataDictionary><DataField name="y" optype="categorical" dataType="integer"><Value value="0"/><Value value="1"/><Value value="2"/></DataField><DataField name="x3" optype="continuous" dataType="float"/><DataField name="x4" optype="continuous" dataType="float"/></DataDictionary>############################# 定义数据预处理和特征工程部分 ###########################<TransformationDictionary><DerivedField name="double(x3)" optype="continuous" dataType="double"><FieldRef field="x3"/></DerivedField><DerivedField name="double(x4)" optype="continuous" dataType="double"><FieldRef field="x4"/></DerivedField></TransformationDictionary>######################## 模型逻辑部分,每个模型的描述信息差异很大,但是本质上都是转化为具体的一大堆的类似规则一样的字符串了##################################################################<TreeModel functionName="classification" missingValueStrategy="nullPrediction" splitCharacteristic="multiSplit"><MiningSchema><MiningField name="y" usageType="target"/><MiningField name="x3"/><MiningField name="x4"/></MiningSchema><Output><OutputField name="probability(0)" optype="continuous" dataType="double" feature="probability" value="0"/><OutputField name="probability(1)" optype="continuous" dataType="double" feature="probability" value="1"/><OutputField name="probability(2)" optype="continuous" dataType="double" feature="probability" value="2"/></Output><Node><True/><Node><SimplePredicate field="double(x3)" operator="lessOrEqual" value="3.5"/><Node score="1" recordCount="1.0"><SimplePredicate field="double(x3)" operator="lessOrEqual" value="2.0"/><ScoreDistribution value="0" recordCount="0.0"/><ScoreDistribution value="1" recordCount="1.0"/><ScoreDistribution value="2" recordCount="0.0"/></Node><Node score="0" recordCount="2.0"><True/><ScoreDistribution value="0" recordCount="2.0"/><ScoreDistribution value="1" recordCount="0.0"/><ScoreDistribution value="2" recordCount="0.0"/></Node></Node><Node score="2" recordCount="1.0"><SimplePredicate field="double(x4)" operator="lessOrEqual" value="8.0"/><ScoreDistribution value="0" recordCount="0.0"/><ScoreDistribution value="1" recordCount="0.0"/><ScoreDistribution value="2" recordCount="1.0"/></Node><Node score="1" recordCount="1.0"><True/><ScoreDistribution value="0" recordCount="0.0"/><ScoreDistribution value="1" recordCount="1.0"/><ScoreDistribution value="2" recordCount="0.0"/></Node></Node></TreeModel></PMML>
可以看到里面就是决策树的树结构节点的各个参数,以及输入值。我们的输入被定义为x1-x4,输出定义为y;
这些不是纯粹自动生成的,而是开发预先写好的转换逻辑,就类似于开发人员写了一个字典,定义了py代码到pmml的映射。因此,你要自己用numpy实现了一个model,需要自己去考虑model转pmml的逻辑(那特么还不如自己用java来写model)
现阶段,传统的机器学习模型和表格数据的应用走jpmml的这一套流程没啥大问题,复杂的逻辑有一个比较好的方式就是python实现一遍,然后按照jpmml的官方提供的实现的java代码的模版把逻辑用java重新写一遍,然后测试二者的输出结果是否相同(java可以使用ijava来实现交互式编程,测试的时候会比较方便)。类似于在sklearn中通过集成其base下的各种父类然自定义sklearn api。
深度这一套就不要走pmml了,太坑,直接走tf或torch官方提供的案例撸一遍熟悉一下就行了。
