PMML简介
PMML全称预言模型标记语言(Predictive Model Markup Language),利用XML描述和存储数据挖掘模型,是一个已经被W3C所接受的标准。使用pmml储存好模型之后,任何软件栈都可以调用pmml储存好的模型。主要用于跨平台的机器学习模型部署。PMML允许以简单的方式将模型和数据转换一起表示。 PMML可以完成数据预处理(by每个样本),一些简单的特征工程,以及常见的所有机器学习模型。最常见的任务就是把python训练完成的机器学习模型做成pmml文件,在java环境下做线上的推断任务。
本文主要对最常用的机器学习模型lightgbm(下文简称lgb),转pmml文件做一些经验总结,这是第一篇着重介绍常见的lgb模型如何转成pmml文件以及自定义损失函数,评价函数后的lgb模型如何做转换。
pmml转换流程
1)jpmml项目
有很多专门针对sklearn模型接口的jpmml项目,本文使用
https://github.com/jpmml/jpmml-lightgbm
针对lgb模型的项目进行转换
2)环境搭建
step0:java环境
网上有很多攻略啦 非开发人员可以参考自然搜索排名靠前的攻略 应该不会有坑。
step1:mvn clean install 编译出可执行文件 有点慢
target/jpmml-lightgbm-executable-1.3-SNAPSHOT.jar
3)训练你的lgb模型
lgb原生接口采用model.save_model(‘model.txt’)进行保存
sklearn接口采用model.booster_.save_model(“model.txt”)进行保存
tree
version=v2
num_class=1
num_tree_per_iteration=1
label_index=0
max_feature_idx=xx
objective=binary sigmoid:1
在txt文件中必须要保证有objective
如果自定义了loss,训练得出的模型文件里不会有这个objective,显然模型直接的预测结果就是raw_score,所有叶子节点的值加和。
在给定了objective 后等于为输出加上了可识别的激活函数,本文案例是二分类模型,objective=binary sigmoid:1 保证了输出会激活到0~1
加上这行以后,在load模型python里的预测值也将经过sigmoid
4)进行转换
java -jar target/jpmml-lightgbm-executable-1.3-SNAPSHOT.jar --lgbm-input lightgbm.txt --pmml-output lightgbm.pmml
5)打分验证
from jpmml_evaluator.pyjnius import jnius_configure_classpath, PyJNIusBackend
from jpmml_evaluator import make_evaluator
from base.sql_tool import *# 比如与落库的离线打分数据进行对比
class pmml_test_tool(object):
def __init__(self, table_path, pmml_path, features, prob_sql_name, err_max_rate):
self.table_path = table_path # 数据库离线数据
self.pmml_path = pmml_path# pmml 文件
self.features = features# 特征列名
self.prob_sql_name = prob_sql_name# 数据库内的对比数据字段名
self.err_max_rate = err_max_rate# 可接受偏差
self.data = []
def get_pmml_predicting(self):
# Configure JVM
jnius_configure_classpath()
backend = PyJNIusBackend()
evaluator = make_evaluator(backend, self.pmml_path).verify()
print("load Model successful!")
inputFields = evaluator.getInputFields()
print("Input fields: " + str([inputField.getName() for inputField in inputFields]))
outputFields = evaluator.getOutputFields()
outputFields_list = [outputField.getName() for outputField in outputFields]
# pmml文件的多输出都打印出来
print("Output fields: " + str([outputField.getName() for outputField in outputFields]))
test_columns = self.features
# get data
sc = sqlclass()
arguments_df = sc.sql_to_df(self.table_path)
print('load testing data finish!')
data_ot = arguments_df[test_columns]
print(arguments_df.isnull().sum())
results_df = evaluator.evaluateAll(data_ot)
print(results_df)
arguments_df["prob_pmml"] = results_df[outputFields_list[-1]]
# 以下是模型打分与pmml打分对比
arguments_df["diff"] = abs(arguments_df["prob_pmml"] - arguments_df[self.prob_sql_name])
print(arguments_df["diff"].sum())
print(arguments_df[arguments_df["diff"] > self.err_max_rate][
["prob_pmml", self.prob_sql_name, "diff"]].sort_values('diff', ascending=False))
self.data = arguments_df
if __name__ == "__main__":
import lightgbm as lgb
model = lgb.Booster(
model_file='./models/model_use/xxx.txt')
features = list(model.feature_name())
pt = pmml_test_tool(table_path='''select * from xxx limit 1000''',
pmml_path='./models/model_use/xxx.pmml',
features=features,
prob_sql_name='prob_new',
err_max_rate=0.0001)
pt.get_pmml_predicting()
这样是对sigmoid之后的预测值进行了对比
如果需要输出原始值
<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 dataType="double" feature="transformedValue" isFinalResult="false" name="transformedlgbmValue" optype="continuous">
<Apply function="+">
<FieldRef field="lgbmValue"/>
<Constant dataType="double">
0
</Constant>
</Apply>
</OutputField>
</Output>
上一个segment里是所有的树加和成变量lgbmValue:raw_score
从FieldRef field里取出lgbmValue变量并构建新的变量transformedlgbmValue 进行输出即可
详细的pmml语法与处理操作可以参考:
https://blog.csdn.net/cuyi7076/article/details/107158141