PMML跨平台机器学习模型落地经验总结

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值