zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    Redis 集合(Set)
    北京Uber优步司机奖励政策(1月21日)
    成都Uber优步司机奖励政策(1月21日)
    滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(1月21日)
    全国各城市Uber客服联系方式(电话、邮箱、微博)
    成都Uber优步司机奖励政策(1月20日)
    北京Uber优步司机奖励政策(1月20日)
    滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(1月20日)
    Linq聚合函数使用
    Linq查询案例
  • 原文地址:https://www.cnblogs.com/exmyth/p/13752479.html
Copyright © 2011-2022 走看看