在机器学习用于产品的时候,我们经常会遇到跨平台的问题。比如我们用Python基于一系列的机器学习库训练了一个模型,但是有时候其他的产品和项目想把这个模型集成进去,但是这些产品很多只支持某些特定的生产环境比如Java,为了上一个机器学习模型去大动干戈修改环境配置很不划算,此时我们就可以考虑用预测模型标记语言(Predictive Model Markup Language,以下简称PMML)来实现跨平台的机器学习模型部署了。

1. PMML概述

PMML是数据挖掘的一种通用的规范,它用统一的XML格式来描述我们生成的机器学习模型。这样无论你的模型是sklearn,R还是Spark MLlib生成的,我们都可以将其转化为标准的XML格式来存储。当我们需要将这个PMML的模型用于部署的时候,可以使用目标环境的解析PMML模型的库来加载模型,并做预测。

可以看出,要使用PMML,需要两步的工作,第一块是将离线训练得到的模型转化为PMML模型文件,第二块是将PMML模型文件载入在线预测环境,进行预测。这两块都需要相关的库支持。

2. PMML模型的生成和加载相关类库

PMML模型的生成相关的库需要看我们使用的离线训练库。如果我们使用的是sklearn,那么可以使用sklearn2pmml这个python库来做模型文件的生成,这个库安装很简单,使用"pip install sklearn2pmml"即可,相关的使用我们后面会有一个demo。如果使用的是Spark MLlib, 这个库有一些模型已经自带了保存PMML模型的方法,可惜并不全。如果是R,则需要安装包"XML"和“PMML”。此外,JAVA库JPMML可以用来生成R,SparkMLlib,xgBoost,Sklearn的模型对应的PMML文件。github地址是:https://github.com/jpmml/jpmml。

加载PMML模型需要目标环境支持PMML加载的库,如果是JAVA,则可以用JPMML来加载PMML模型文件。相关的使用我们后面会有一个demo。

3. PMML模型生成和加载示例

下面我们给一个示例,使用sklearn生成一个决策树模型,用sklearn2pmml生成模型文件,用JPMML加载模型文件,并做预测。

完整代码参见我的github:https://github.com/ljpzzz/machinelearning/blob/master/model-in-product/sklearn-jpmml

首先是用用sklearn生成一个决策树模型,由于我们是需要保存PMML文件,所以最好把模型先放到一个Pipeline数组里面。这个数组里面除了我们的决策树模型以外,还可以有归一化,降维等预处理操作,这里作为一个示例,我们Pipeline数组里面只有决策树模型。代码如下:

importnumpy as npimportmatplotlib.pyplot as plt%matplotlib inlineimportpandas as pdfrom sklearn importtreefrom sklearn2pmml.pipeline importPMMLPipelinefrom sklearn2pmml importsklearn2pmmlimportos

os.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)

上面这段代码做了一个非常简单的决策树分类模型,只有5个训练样本,特征有4个,输出类别有3个。实际应用时,我们需要将模型调参完毕后才将其放入PMMLPipeline进行保存。运行代码后,我们在当前目录会得到一个PMML的XML文件,可以直接打开看,内容大概如下:

2018-06-24T05:47:17Z

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'))])

可以看到里面就是决策树模型的树结构节点的各个参数,以及输入值。我们的输入被定义为x1-x4,输出定义为y。

有了PMML模型文件,我们就可以写JAVA代码来读取加载这个模型并做预测了。

我们创建一个Maven或者gradle工程,加入JPMML的依赖,这里给出maven在pom.xml的依赖,gradle的结构是类似的。

org.jpmml

pmml-evaluator

1.4.1

org.jpmml

pmml-evaluator-extension

1.4.1

接着就是读取模型文件并预测的代码了,具体代码如下:

importorg.dmg.pmml.FieldName;importorg.dmg.pmml.PMML;import org.jpmml.evaluator.*;importorg.xml.sax.SAXException;importjavax.xml.bind.JAXBException;importjava.io.FileInputStream;importjava.io.IOException;importjava.io.InputStream;importjava.util.HashMap;importjava.util.LinkedHashMap;importjava.util.List;importjava.util.Map;/*** Created by 刘建平Pinard on 2018/6/24.*/

public classPMMLDemo {privateEvaluator loadPmml(){

PMML pmml= newPMML();

InputStream inputStream= null;try{

inputStream= new FileInputStream("D:/demo.pmml");

}catch(IOException e) {

e.printStackTrace();

}if(inputStream == null){return null;

}

InputStream is=inputStream;try{

pmml=org.jpmml.model.PMMLUtil.unmarshal(is);

}catch(SAXException e1) {

e1.printStackTrace();

}catch(JAXBException e1) {

e1.printStackTrace();

}finally{//关闭输入流

try{

is.close();

}catch(IOException e) {

e.printStackTrace();

}

}

ModelEvaluatorFactory modelEvaluatorFactory=ModelEvaluatorFactory.newInstance();

Evaluator evaluator=modelEvaluatorFactory.newModelEvaluator(pmml);

pmml= null;returnevaluator;

}private int predict(Evaluator evaluator,int a, int b, int c, intd) {

Map data = new HashMap();

data.put("x1", a);

data.put("x2", b);

data.put("x3", c);

data.put("x4", d);

List inputFields =evaluator.getInputFields();//过模型的原始特征,从画像中获取数据,作为模型输入

Map arguments = new LinkedHashMap();for(InputField inputField : inputFields) {

FieldName inputFieldName=inputField.getName();

Object rawValue=data.get(inputFieldName.getValue());

FieldValue inputFieldValue=inputField.prepare(rawValue);

arguments.put(inputFieldName, inputFieldValue);

}

Map results =evaluator.evaluate(arguments);

List 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 instanceofComputable) {

Computable computable=(Computable) targetFieldValue;

primitiveValue=(Integer)computable.getResult();

}

System.out.println(a+ " " + b + " " + c + " " + d + ":" +primitiveValue);returnprimitiveValue;

}public static voidmain(String args[]){

PMMLDemo demo= newPMMLDemo();

Evaluator model=demo.loadPmml();

demo.predict(model,1,8,99,1);

demo.predict(model,111,89,9,11);

}

}

代码里有两个函数,第一个loadPmml是加载模型的,第二个predict是读取预测样本并返回预测值的。我的代码运行结果如下:

target: y value: {result=2, probability_entries=[0=0.0, 1=0.0, 2=1.0], entityId=5, confidence_entries=[]}

1 8 99 1:2

target: y value: {result=1, probability_entries=[0=0.0, 1=1.0, 2=0.0], entityId=6, confidence_entries=[]}

111 89 9 11:1

也就是样本(1,8,99,1)被预测为类别2,而(111,89,9,11)被预测为类别1。

以上就是PMML生成和加载的一个示例,使用起来其实门槛并不高,也很简单。

4. PMML总结与思考

PMML的确是跨平台的利器,但是是不是就没有缺点呢?肯定是有的!

第一个就是PMML为了满足跨平台,牺牲了很多平台独有的优化,所以很多时候我们用算法库自己的保存模型的API得到的模型文件,要比生成的PMML模型文件小很多。同时PMML文件加载速度也比算法库自己独有格式的模型文件加载慢很多。

第二个就是PMML加载得到的模型和算法库自己独有的模型相比,预测会有一点点的偏差,当然这个偏差并不大。比如某一个样本,用sklearn的决策树模型预测为类别1,但是如果我们把这个决策树落盘为一个PMML文件,并用JAVA加载后,继续预测刚才这个样本,有较小的概率出现预测的结果不为类别1.

第三个就是对于超大模型,比如大规模的集成学习模型,比如xgboost, 随机森林,或者tensorflow,生成的PMML文件很容易得到几个G,甚至上T,这时使用PMML文件加载预测速度会非常慢,此时推荐为模型建立一个专有的环境,就没有必要去考虑跨平台了。

此外,对于TensorFlow,不推荐使用PMML的方式来跨平台。可能的方法一是TensorFlow serving,自己搭建预测服务,但是会稍有些复杂。另一个方法就是将模型保存为TensorFlow的模型文件,并用TensorFlow独有的JAVA库加载来做预测。

我们在下一篇会讨论用python+tensorflow训练保存模型,并用tensorflow的JAVA库加载做预测的方法和实例。

(欢迎转载,转载请注明出处。欢迎沟通交流: liujianping-ok@163.com)

java加载pmml模型文件报错_PMML总结与思考PMML模型生成和加载示例相关推荐

  1. uniapp 使用pdf.js 加载本地pdf文件报错问题

    最近有在做一个移动端的应用,应用里涉及到大量的js游戏开发,使用Android原生做不太合适,就选择了uniapp,其中有一个功能是读取本地的pdf文件并展示.在网上查了点资料都是用pdf.js来开发 ...

  2. java hadoop2.6.0 读取文件报错_java 程序访问hdfs错误 hadoop2.2.0

    很奇怪的问题,程序在eclipse上跑没问题: 这就代码:FileSystem fs = FileSystem.get(URI.create(hdfs_file),  conf , "use ...

  3. pytorch 34 mmdeploy模型转换报错onnxruntime.capi.onnxruntime_pybind11_state.Fail解决方案

    使用mmdeploy部署mmrotate模型时出现以下报错,虽然不影响模型转换为onnx,但是影响模型的加载.出现这个报错,是因为mmdeploy转换完模型后,要加载onnx模型测试一下,但是onnx ...

  4. Java使用File类生成文件报错:java.io.FileNotFoundException: C:\... (拒绝访问。)

    今天在手写动态代理的时候使用File类创建文件报错:java.io.FileNotFoundException: C:\... (拒绝访问.) public class Test {public st ...

  5. 【错误记录】记录 Android 命令行执行 Java 程序中出现的错误 ( dx 打包 PC 可执行文件报错 | dalvik 命令执行 kotlin 编译的 dex 文件报错 )

    文章目录 前言 一.Android 命令行与 PC 可执行 JAR 文件不兼容 二.Android 命令行使用 dalvik 命令不能直接执行 Kotlin 编译的 dex 文件 前言 尝试在 And ...

  6. VMBox加载拷贝的vid报错E_INVALIDARG (0x80070057) Cannot register the hard disk 'D:\VMBox\win7.vdi' {7bca5a3

    VMBox加载拷贝的vid报错E_INVALIDARG (0x80070057) Cannot register the hard disk 'D:\VMBox\win7.vdi' {7bca5a3e ...

  7. java解析excel报错,poi解析excel文件报错

    getFileMagic() only operates on streams which support mark(int) 使用 bis 解决 BufferedInputStream bis = ...

  8. android运行jar文件路径,java命令行执行jar包报错解决

    今天遇到一个问题,在终端doc命令行下,执行java -jar 操作,报错Error: Unable to access jarfile CheckAndroidV2Signature.jar 找了各 ...

  9. python 读取文件报错:UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0xb5 in position 0: invalid start

    python 读取文件报错:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb5 in position 0: invalid start ...

最新文章

  1. 国内外开源与 SaaS ,团队协作平台、项目管理工具整理
  2. 虚拟化模板新建虚拟机后 wsus控制台无法看到所有客户端计算机
  3. makefile如何减小可执行文件的大小(没有用到的函数不参与链接)
  4. CentOS系统根目录组织结构
  5. java 远程调用url_使用Java的URL/HttpURLConnection进行远程调用(POST请求)
  6. axios的请求配置
  7. 低温linux内核启动readl,Linux内核启动流程分析(一)
  8. Machine Learning - XV. Anomaly Detection异常检测 (Week 9)
  9. c/c++的预处理定义 Stringizing Operator (#) Charizing Operator (#@) Token-Pasting Operator (##)
  10. python日记----2017.7.20
  11. eplan和西门子plc的对接_基于EPLAN的西门子电路图高效设计
  12. 内网通3.4.3045版本 免广告码 积分码 算法
  13. layui date插件设置不能跨月查询
  14. 计算机算法分析与设计心得体会,算法设计与分析课程的心得体会
  15. python合并工作簿所有内容_如何快速的合并多个 Excel 工作簿成为一个工作簿?...
  16. JVM与Java体系结构
  17. c语言文字居中,如何设置select和option的文字居中?
  18. 14期《读万卷书,行万里路》4月刊
  19. REST及其RESTful详解
  20. js 选择本地图片并显示

热门文章

  1. 灯具灼热丝测试依据标准和要求
  2. 2021年中国全球化品牌50强出炉,这些品牌势能辐射全球
  3. php 频繁插库处理队列,PHP+Redis 消息队列 实现高并发下注册人数统计的实例
  4. 2021--个人年度总结
  5. 计算机动画顺序在哪里设置,Keynote动画顺序怎么设置 Keynote动画顺序设置教程
  6. 在支付宝答了1000多个保险问题后,我最想告诉你这3点 | 简保君
  7. webpack之webpack.config.js配置
  8. react添加键盘事件(react-hook 监听键盘事件)
  9. DHCP和DHCP中继器
  10. bodipy荧光染料BDP 581/591 NHS ester/琥珀酰亚胺活化酯