1.简述

PMML全称预言模型标记模型(Predictive Model Markup Language),以XML 为载体呈现数据挖掘模型。PMML 允许您在不同的应用程序之间轻松共享预测分析模型。因此,您可以在一个系统中定型一个模型,在 PMML 中对其进行表达,然后将其移动到另一个系统中,而不需考虑分析和预测过程中的具体实现细节。使得模型的部署摆脱了模型开发和产品整合的束缚。通俗地讲, 我有一个决策树模型, 使用效果也不错, 那么就可以把树的结构(节点间的父子关系, 节点内的丰富信息 等)序列化为PMML文件, 共享给其他人使用.  这样无论你的模型是sklearn,R还是Spark MLlib生成的,我们都可以将其转化为标准的XML格式来存储。当我们需要将这个PMML的模型用于部署的时候,可以使用目标环境的解析PMML模型的库来加载模型,并做预测。

2. 主要结构

PMML 文件的结构遵从了用于构建预测解决方案的常用步骤,包括:

  1. 数据词典 
    这是一种数据分析阶段的产品,可以识别和定义哪些输入数据字段对于解决眼前的问题是最有用的。这可以包括数值、顺序和分类字段。
  2. 挖掘架构 
    定义了处理缺少值和离群值的策略。这非常有用,因为通常情况,当将模型应用于实践时,所需的输入数据字段可能为空或者被误呈现。
  3. 数据转换 
    定义了将原始输入数据预处理至派生字段所需的计算。派生字段(有时也称为特征检测器)对输入字段进行合并或修改,以获取更多相关信息。例如,为了预测停车所需的制动压力,一个预测模型可能将室外温度和水的存在(是否在下雨?)作为原始数据。派生字段可能会将这两个字段结合起来,以探测路上是否结冰。然后结冰字段被作为模型的直接输入来预测停车所需的制动压力。
  4. 模型定义 
    定义了用于构建模型的结构和参数。PMML 涵盖了多种统计技术。例如,为了呈现一个神经网络,它定义了所有的神经层和神经元之间的连接权重。对于一个决策树来说,它定义了所有树节点及简单和复合谓语。
  5. 输出 
    定义了预期模型输出。对于一个分类任务来说,输出可以包括预测类及与所有可能类相关的概率。
  6. 目标 
    定义了应用于模型输出的后处理步骤。对于一个回归任务来说,此步骤支持将输出转变为人们很容易就可以理解的分数(预测结果)。
  7. 模型解释 
    定义了将测试数据传递至模型时获得的性能度量标准(与训练数据相对)。这些度量标准包括字段相关性、混淆矩阵、增益图及接收者操作特征(ROC)曲线图。
  8. 模型验证 
    定义了一个包含输入数据记录和预期模型输出的示例集。这是非常重要的一个步骤,因为在应用程序之间移动模型时,该模型需要通过匹配测试。这样就可以确保,在呈现相同的输入时,新系统可以生成与旧系统同样的输出。 如果实际情况是这样的话,一个模型将被认为经过了验证,且随时可用于实践。

一个通用的PMML文件结构如下(参考http://dmg.org/pmml/v4-3/GeneralStructure.html):

<?xml version="1.0"?>
<PMML version="4.3"xmlns="http://www.dmg.org/PMML-4_3"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Header copyright="Example.com"/><DataDictionary> ... </DataDictionary>... a model ...</PMML>

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

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

    加载PMML模型需要目标环境支持PMML加载的库,如果是JAVA,则可以用JPMML来加载PMML模型文件。

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

不过,当训练和预测使用同一种开发语言的时候,PMML 就没有必要使用了,因为任何中间格式都会牺牲掉独有的优化。

  • 整个流程分为两部分:离线和在线。
  • 离线部分流程是将样本进行特征工程,然后进行训练,生成模型。一般离线部分常用 Python 中的 sklearn、R 或者 Spark ML 来训练模型。
  • 在线部分是根据请求得到样本数据,对这些数据采用与离线特征工程一样的方式来处理,然后使用模型进行评估。一般在线部分常用 Java、C++ 来开发。
  • 离线部分与在线部分是通过 PMML 连接的,也就是说离线训练好了模型之后,将模型导出为 PMML 文件,在线部分加载该 PMML 文件生成对应的评估模型。

我们可以看到,PMML 是连接离线与在线环节的关键,一般导出 PMML 文件和 加载 PMML 文件都需要各个语言来做单独的实现。不过幸运的是,已经有很多大神实现了这些,可以参见:https://github.com/jpmml 。

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

        将离线训练得到的模型转化为PMML模型文件

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

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

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import pandas as pd
from sklearn import tree
from sklearn2pmml.pipeline import PMMLPipeline
from sklearn2pmml import sklearn2pmmlimport os
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文件,可以直接打开看,内容大概如下:

<?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><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。

将PMML模型文件载入在线预测环境,进行预测

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

    <dependency><groupId>org.jpmml</groupId><artifactId>pmml-evaluator</artifactId><version>1.4.1</version></dependency><dependency><groupId>org.jpmml</groupId><artifactId>pmml-evaluator-extension</artifactId><version>1.4.1</version></dependency>

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

import org.dmg.pmml.FieldName;
import org.dmg.pmml.PMML;
import org.jpmml.evaluator.*;
import org.xml.sax.SAXException;import javax.xml.bind.JAXBException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;/*** Created by 刘建平Pinard on 2018/6/24.*/
public class PMMLDemo {private Evaluator loadPmml(){PMML pmml = new PMML();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;return evaluator;}private int predict(Evaluator evaluator,int a, 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;}public static void main(String args[]){PMMLDemo demo = new PMMLDemo();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生成和加载的一个示例,使用起来其实门槛并不高,也很简单。

5. PMML总结与思考

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

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

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

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

参考:

https://blog.csdn.net/hellozhxy/article/details/81563370

https://blog.csdn.net/hellozhxy/article/details/82142700

[机器学习]PMML预测模型标记语言相关推荐

  1. [机器学习] PMML实现模型上线

    机器学习在用于产品的时候,经常会遇到跨平台的问题. 比如用Python基于一系列的机器学习库训练了一个模型,但是有时候其他的产品和项目想把这个模型集成进去,但是这些产品很多只支持某些特定的生产环境比如 ...

  2. 【博士论文】机器学习中的标记增强理论与应用研究

    来源:专知 本文为论文,建议阅读5分钟本文对标记增强进行研究. 来自东南大学徐宁的博士论文,入选2021年度"CCF优秀博士学位论文奖"初评名单! https://www.ccf. ...

  3. 如何在时间紧迫情况下进行机器学习:构建标记的新闻 数据 库 开发 标记 网站 阅读1629 原文:How we built Tagger News: machine learning on a

    如何在时间紧迫情况下进行机器学习:构建标记的新闻 数据 库 开发 标记 网站 阅读1629  原文:How we built Tagger News: machine learning on a ti ...

  4. 安全性断言标记语言(SAML)介绍

    简介 安全是所有Web项目在设计时都要考虑的一个重要因素.无论是选择最短口令,决定何时使用SSL加密HTTP会话,还是通过自动登录cookie来识别用户,都经常要付出重大的设计努力,以保护用户的身份信 ...

  5. “可扩展标记语言”(XML) 提供一种描述结构化数据的方法。

    摘要: "可扩展标记语言"(XML) 提供一种描述结构化数据的方法.与主要用于控制数据的显示和外观的 HTML 标记不同,XML 标记用于定义数据本身的结构和数据类型. XML 使 ...

  6. WPF第一章(XAML前台标记语言(Chapter02代码讲解))

    XAML前台标记语言(Chapter2代码讲解)     很不好意思,工作有点忙,博客停了两天.相对于一门语言的学习,理论知识和实践必不可少,大多数时间我们要用,对于代码也是,一边不行可以看两遍,实在 ...

  7. HTML超文本描述语言,HTML超文本标记语言的介绍

    一.概念 1.定义 超级文本标记语言是标准通用标记语言下的一个应用,也是一种规范,一种标准, 它通过标记符号来标记要显示的网页中的各个部分. 简而言之:一种为普通文件中某些字句加上标示的语言,其目的在 ...

  8. 可扩展标记语言--XML

    XML(EXtensible Markup Language)可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言. 在电子计算机中,标记指计算机所能理解的信息符号, ...

  9. html语言设计表格,HTML标记语言——表格标记

    HTML标记语言--表格标记 互联网   发布时间:2008-10-17 18:55:24   作者:佚名   我要评论 点击这里返回网页教学网 HTML教程 栏目. 上文:标记语言--标题 原文出处 ...

最新文章

  1. wake_lock_timeout的使用方法【转】
  2. Spring Cloud构建微服务架构:分布式服务跟踪(抽样收集)【Dalston版】
  3. c语言程序设计 a b,用C语言编程时,a+=b 和 a=a+b 真的完全等价吗?
  4. Android Studio(9)--添加应用资源
  5. 5.21工作记录(修改页面跳转,去掉多余的js;增加图片清除功能)
  6. Vue:router的beforeEach与afterEach钩子函数
  7. 虚拟IP技术 ip地址漂移技术
  8. 【学习笔记】《网络安全态势感知》第三章:网络安全数据采集与融合
  9. linux测速(含脚本)
  10. 计算机硬盘根目录是什么,根目录是什么(d盘根目录是什么意思)
  11. 当我在浏览器输入 www.baiu.com 之后发生了什么
  12. linux mantis安装 yum,CentOS 安装和配置 Mantis
  13. 七战DTCC铸成ACE Director 去哪儿网周彦伟畅聊数据库的十八般武艺
  14. 【电脑常用办公软件】万彩办公大师教程丨截屏大师工具的应用
  15. 说说你平时怎么优化mysql的_面试:给我说说你平时是如何优化MySQL的?
  16. 【CF1646D】D. Weight the Tree(树形dp、贪心)
  17. 【张宇2021考研】数学二(样卷)扫描版
  18. PyCharm快捷键——代码运行快捷键
  19. Linux安装指定版本的docker及添加国内镜像源
  20. 2022年安全员-B证题库模拟考试平台操作

热门文章

  1. 使用amap-js引入高德地图AMap及其UI组件AMapUI
  2. Java历程-初学篇 Day05选择结构(2)
  3. spring BeanFactory加载xml配置文件示例
  4. 检测到目标URL启用了 Microsoft ASP.NET 调试
  5. Oracle SQL Access Advisor 说明
  6. dedecms在linux主机下的一个奇怪错误
  7. python操作mongodb语法_python操作mongodb怎么找到所有的集合
  8. python语言有哪些类型的运算符_python(4)-变量 数据类型和运算符
  9. jqGrid getGridParam办法
  10. android长截屏代码,android长截屏原理及实现代码