• PMML讲解及使用


    1. PMML概述

    PMML全称预言模型标记语言(Predictive Model Markup Language),利用XML描述和存储数据挖掘模型,是一个已经被W3C所接受的标准。使用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模型文件。

                             PMML åå«æ°æ®é¢å¤çåæ°æ®åå¤ç以åé¢æµæ¨¡åæ¬èº«

    pmml支持的model有 :

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

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

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

    1.  
      import numpy as np
    2.  
      import matplotlib.pyplot as plt
    3.  
      %matplotlib inline
    4.  
      import pandas as pd
    5.  
      from sklearn import tree
    6.  
      from sklearn2pmml.pipeline import PMMLPipeline
    7.  
      from sklearn2pmml import sklearn2pmml
    8.  
       
    9.  
      import os
    10.  
      os.environ["PATH"] += os.pathsep + 'C:/Program Files/Java/jdk1.8.0_171/bin'
    11.  
       
    12.  
      X=[[1,2,3,1],[2,4,1,5],[7,8,3,6],[4,8,4,7],[2,5,6,9]]
    13.  
      y=[0,1,0,2,1]
    14.  
      pipeline = PMMLPipeline([("classifier", tree.DecisionTreeClassifier(random_state=9))]);
    15.  
      pipeline.fit(X,y)
    16.  
       
    17.  
      sklearn2pmml(pipeline, ".demo.pmml", with_repr = True)

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

    1.  
      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    2.  
      <PMML xmlns="http://www.dmg.org/PMML-4_3" version="4.3">
    3.  
      <Header>
    4.  
      <Application name="JPMML-SkLearn" version="1.5.3"/>
    5.  
      <Timestamp>2018-06-24T05:47:17Z</Timestamp>
    6.  
      </Header>
    7.  
      <MiningBuildTask>
    8.  
      <Extension>PMMLPipeline(steps=[('classifier', DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
    9.  
      max_features=None, max_leaf_nodes=None,
    10.  
      min_impurity_decrease=0.0, min_impurity_split=None,
    11.  
      min_samples_leaf=1, min_samples_split=2,
    12.  
      min_weight_fraction_leaf=0.0, presort=False, random_state=9,
    13.  
      splitter='best'))])</Extension>
    14.  
      </MiningBuildTask>
    15.  
      <DataDictionary>
    16.  
      <DataField name="y" optype="categorical" dataType="integer">
    17.  
      <Value value="0"/>
    18.  
      <Value value="1"/>
    19.  
      <Value value="2"/>
    20.  
      </DataField>
    21.  
      <DataField name="x3" optype="continuous" dataType="float"/>
    22.  
      <DataField name="x4" optype="continuous" dataType="float"/>
    23.  
      </DataDictionary>
    24.  
      <TransformationDictionary>
    25.  
      <DerivedField name="double(x3)" optype="continuous" dataType="double">
    26.  
      <FieldRef field="x3"/>
    27.  
      </DerivedField>
    28.  
      <DerivedField name="double(x4)" optype="continuous" dataType="double">
    29.  
      <FieldRef field="x4"/>
    30.  
      </DerivedField>
    31.  
      </TransformationDictionary>
    32.  
      <TreeModel functionName="classification" missingValueStrategy="nullPrediction" splitCharacteristic="multiSplit">
    33.  
      <MiningSchema>
    34.  
      <MiningField name="y" usageType="target"/>
    35.  
      <MiningField name="x3"/>
    36.  
      <MiningField name="x4"/>
    37.  
      </MiningSchema>
    38.  
      <Output>
    39.  
      <OutputField name="probability(0)" optype="continuous" dataType="double" feature="probability" value="0"/>
    40.  
      <OutputField name="probability(1)" optype="continuous" dataType="double" feature="probability" value="1"/>
    41.  
      <OutputField name="probability(2)" optype="continuous" dataType="double" feature="probability" value="2"/>
    42.  
      </Output>
    43.  
      <Node>
    44.  
      <True/>
    45.  
      <Node>
    46.  
      <SimplePredicate field="double(x3)" operator="lessOrEqual" value="3.5"/>
    47.  
      <Node score="1" recordCount="1.0">
    48.  
      <SimplePredicate field="double(x3)" operator="lessOrEqual" value="2.0"/>
    49.  
      <ScoreDistribution value="0" recordCount="0.0"/>
    50.  
      <ScoreDistribution value="1" recordCount="1.0"/>
    51.  
      <ScoreDistribution value="2" recordCount="0.0"/>
    52.  
      </Node>
    53.  
      <Node score="0" recordCount="2.0">
    54.  
      <True/>
    55.  
      <ScoreDistribution value="0" recordCount="2.0"/>
    56.  
      <ScoreDistribution value="1" recordCount="0.0"/>
    57.  
      <ScoreDistribution value="2" recordCount="0.0"/>
    58.  
      </Node>
    59.  
      </Node>
    60.  
      <Node score="2" recordCount="1.0">
    61.  
      <SimplePredicate field="double(x4)" operator="lessOrEqual" value="8.0"/>
    62.  
      <ScoreDistribution value="0" recordCount="0.0"/>
    63.  
      <ScoreDistribution value="1" recordCount="0.0"/>
    64.  
      <ScoreDistribution value="2" recordCount="1.0"/>
    65.  
      </Node>
    66.  
      <Node score="1" recordCount="1.0">
    67.  
      <True/>
    68.  
      <ScoreDistribution value="0" recordCount="0.0"/>
    69.  
      <ScoreDistribution value="1" recordCount="1.0"/>
    70.  
      <ScoreDistribution value="2" recordCount="0.0"/>
    71.  
      </Node>
    72.  
      </Node>
    73.  
      </TreeModel>
    74.  
      </PMML>


    1、sklearn生成pmml文件 :

    1.  
      pipeline = PMMLPipeline([
    2.  
       
    3.  
      ('mapper', mapper),
    4.  
      ("classifier", linear_model.LinearRegression())
    5.  
      ])
    6.  
      pipeline.fit(heart_data[heart_data.columns.difference(["chd"])], heart_data["chd"])
    7.  
       
    8.  
      sklearn2pmml(pipeline, "lrHeart.xml", with_repr = True)

    2、jpmml加载pmml文件 
    先添加maven依赖,

    1.  
      <dependency>
    2.  
      <groupId>org.jpmml</groupId>
    3.  
      <artifactId>pmml-evaluator</artifactId>
    4.  
      <version>1.4.2</version>
    5.  
      </dependency>
    6.  
       
    7.  
      <dependency>
    8.  
       
    9.  
      <groupId>org.jpmml</groupId>
    10.  
      <artifactId>pmml-evaluator-extension</artifactId>
    11.  
      <version>1.4.2</version>
    12.  
      </dependency>

     然后加载pmml模型和调用

    1.  
      PMML pmml;
    2.  
      try(InputStream is = ...){
    3.  
       
    4.  
      pmml = org.jpmml.model.PMMLUtil.unmarshal(is);
    5.  
      }

    4. PMML 深度解析

    您已了解了何为 PMML 及其重要性,现在让我们来深入探究这种语言本身。如上所述,PMML 的结构反映了常用于创建预测解决方案的八大步骤,从在 “数据词典” 步骤中定义原始输入数据字段到在 “模型验证” 步骤中验证模型是否得到正确部署。

    清单 1 展示了一个含有三个字段的解决方案中 PMML 元素 DataDictionary 的定义,这三个字段是:数值型输入字段 Value、分类输入字段 Element 和数值型输出字段 Risk

    清单 1. DataDictionary 元素

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    <DataDictionary numberOfFields="3">

        <DataField dataType="double" name="Value" optype="continuous">

            <Interval closure="openClosed" rightMargin="60" />

        </DataField>

        <DataField dataType="string" name="Element" optype="categorical">

            <Value property="valid" value="Magnesium" />

            <Value property="valid" value="Sodium" />

            <Value property="valid" value="Calcium" />

            <Value property="valid" value="Radium" />

        </DataField>

        <DataField dataType="double" name="Risk" optype="continuous" />

    </DataDictionary>

    请注意,对于字段 Value,范围从负无穷大到 60 的值是有效值。高于 60 的值被定义为无效值。(尽管在此没有显示,您可以使用 PMML 元素 MiningSchema 为无效值和遗漏值定义合适的处理方法。)考虑到字段 Element 是分类的,有效值被明确地列出。如果该特定字段的数据提要包含元素 Iron,将该元素作为无效值处理。

    图 2 展示了神经网络模型的图形表示,其中输入层包含 3 个神经元,隐藏层包含 2 个神经元,输出层包含 1 个神经元。如您所期望的,PMML 可以完全呈现这样一个结构。

    图 2. 一个简单的神经网络模型,其中在对预测进行计算之前,数据经过一系列层

    一个简单的神经网络模型,其中在对预测进行计算之前,数据经过一系列层

    清单 2 展示了隐藏层及其神经元以及输入层(0、1 和 2)和隐藏层(3 和 4)中神经元的连接权重的定义。

    清单 2. 在 PMML 中定义神经层及其神经元

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    <NeuralLayer numberOfNeurons="2">

        <Neuron id="3" bias="-3.1808306946637">

            <Con from="0" weight="0.119477686963504" />

            <Con from="1" weight="-1.97301278112877" />

            <Con from="2" weight="3.04381251760906" />

        </Neuron>

        <Neuron id="4" bias="0.743161353729323">

            <Con from="0" weight="-0.49411146396721" />

            <Con from="1" weight="2.18588757615864" />

            <Con from="2" weight="-2.01213331163562" />

        </Neuron>

    </NeuralLayer>

    PMML 不是一件艰难的事。其复杂程度反映了其呈现的建模技术的复杂程度。事实上,它揭开了许多人感到神秘的预测分析的秘密和黑匣子。利用 PMML,任何预测解决方案都可以采用同样的顺序用同一种语言元素呈现。

    在公司中,PMML 不仅可以作为应用程序之间也可以作为部门、服务提供商及外部供应商之间的混合语。在这种情况下,PMML 就成为定义预测解决方案交流的单一、清晰流程的一个标准。

    5. 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库加载来做预测。

    【转载】:https://www.cnblogs.com/pinard/p/9220199.html

                      https://www.jianshu.com/p/0eb9b2c904a9

                      https://www.ibm.com/developerworks/cn/opensource/ind-PMML1/

  • 相关阅读:
    003 01 Android 零基础入门 01 Java基础语法 01 Java初识 03 Java程序的执行流程
    002 01 Android 零基础入门 01 Java基础语法 01 Java初识 02 Java简介
    001 01 Android 零基础入门 01 Java基础语法 01 Java初识 01 导学
    001 Android Studio 首次编译执行项目过程中遇到的几个常见问题
    Dora.Interception,为.NET Core度身打造的AOP框架 [2]:以约定的方式定义拦截器
    Dora.Interception,为.NET Core度身打造的AOP框架 [1]:更加简练的编程体验
    监视EntityFramework中的sql流转你需要知道的三种方式Log,SqlServerProfile, EFProfile
    轻量级ORM框架——第二篇:Dapper中的一些复杂操作和inner join应该注意的坑
    轻量级ORM框架——第一篇:Dapper快速学习
    CF888G Xor-MST(异或生成树模板)
  • 原文地址:https://www.cnblogs.com/exmyth/p/13752479.html
Copyright © 2020-2023  润新知