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代码实现。如下

    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. import os
    9. os.environ["PATH"] += os.pathsep + 'C:/Program Files/Java/jdk1.8.0_171/bin'
    10. X=[[1,2,3,1],[2,4,1,5],[7,8,3,6],[4,8,4,7],[2,5,6,9]]
    11. y=[0,1,0,2,1]
    12. pipeline = PMMLPipeline([("classifier", tree.DecisionTreeClassifier(random_state=9))]);
    13. pipeline.fit(X,y)
    14. sklearn2pmml(pipeline, ".\demo.pmml", with_repr = True)

    如果是sklearn2pmml转化的结果,很多时候包含3部分,注释直接写下面了:

    1. ##################### 文件头部分,不必在意##################
    2. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    3. <PMML xmlns="http://www.dmg.org/PMML-4_3" version="4.3">
    4. <Header>
    5. <Application name="JPMML-SkLearn" version="1.5.3"/>
    6. <Timestamp>2018-06-24T05:47:17Z</Timestamp>
    7. </Header>
    8. ########### MiningBuildTask 根据你在py中定义的pmmlpipline自动生成相应的pipeline描述信息##############
    9. <MiningBuildTask>
    10. <Extension>PMMLPipeline(steps=[('classifier', DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
    11. max_features=None, max_leaf_nodes=None,
    12. min_impurity_decrease=0.0, min_impurity_split=None,
    13. min_samples_leaf=1, min_samples_split=2,
    14. min_weight_fraction_leaf=0.0, presort=False, random_state=9,
    15. splitter='best'))])</Extension>
    16. </MiningBuildTask>
    17. ################## 定义你建模过程中使用到的全部的变量以及对应类型等#########################
    18. <DataDictionary>
    19. <DataField name="y" optype="categorical" dataType="integer">
    20. <Value value="0"/>
    21. <Value value="1"/>
    22. <Value value="2"/>
    23. </DataField>
    24. <DataField name="x3" optype="continuous" dataType="float"/>
    25. <DataField name="x4" optype="continuous" dataType="float"/>
    26. </DataDictionary>
    27. ############################# 定义数据预处理和特征工程部分 ###########################
    28. <TransformationDictionary>
    29. <DerivedField name="double(x3)" optype="continuous" dataType="double">
    30. <FieldRef field="x3"/>
    31. </DerivedField>
    32. <DerivedField name="double(x4)" optype="continuous" dataType="double">
    33. <FieldRef field="x4"/>
    34. </DerivedField>
    35. </TransformationDictionary>
    36. ######################## 模型逻辑部分,每个模型的描述信息差异很大,但是本质上都是转化为具体的一大堆的类似规则
    37. 一样的字符串了##################################################################
    38. <TreeModel functionName="classification" missingValueStrategy="nullPrediction" splitCharacteristic="multiSplit">
    39. <MiningSchema>
    40. <MiningField name="y" usageType="target"/>
    41. <MiningField name="x3"/>
    42. <MiningField name="x4"/>
    43. </MiningSchema>
    44. <Output>
    45. <OutputField name="probability(0)" optype="continuous" dataType="double" feature="probability" value="0"/>
    46. <OutputField name="probability(1)" optype="continuous" dataType="double" feature="probability" value="1"/>
    47. <OutputField name="probability(2)" optype="continuous" dataType="double" feature="probability" value="2"/>
    48. </Output>
    49. <Node>
    50. <True/>
    51. <Node>
    52. <SimplePredicate field="double(x3)" operator="lessOrEqual" value="3.5"/>
    53. <Node score="1" recordCount="1.0">
    54. <SimplePredicate field="double(x3)" operator="lessOrEqual" value="2.0"/>
    55. <ScoreDistribution value="0" recordCount="0.0"/>
    56. <ScoreDistribution value="1" recordCount="1.0"/>
    57. <ScoreDistribution value="2" recordCount="0.0"/>
    58. </Node>
    59. <Node score="0" recordCount="2.0">
    60. <True/>
    61. <ScoreDistribution value="0" recordCount="2.0"/>
    62. <ScoreDistribution value="1" recordCount="0.0"/>
    63. <ScoreDistribution value="2" recordCount="0.0"/>
    64. </Node>
    65. </Node>
    66. <Node score="2" recordCount="1.0">
    67. <SimplePredicate field="double(x4)" operator="lessOrEqual" value="8.0"/>
    68. <ScoreDistribution value="0" recordCount="0.0"/>
    69. <ScoreDistribution value="1" recordCount="0.0"/>
    70. <ScoreDistribution value="2" recordCount="1.0"/>
    71. </Node>
    72. <Node score="1" recordCount="1.0">
    73. <True/>
    74. <ScoreDistribution value="0" recordCount="0.0"/>
    75. <ScoreDistribution value="1" recordCount="1.0"/>
    76. <ScoreDistribution value="2" recordCount="0.0"/>
    77. </Node>
    78. </Node>
    79. </TreeModel>
    80. </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官方提供的案例撸一遍熟悉一下就行了。