模型持久化方法(pickle和PMML)

标签: 机器学习

pickle方式

pickle方式应用场景:在python环境中训练模型,然后使用pickle将模型持久化为一个模型文件,然后就可以在python环境加载持久化后的模型文件对新数据进行预测。

1、安装pickle模块

pip install pickle

 

2、代码示例

pickle_demo.py模块完成了模型的训练,持久化和模型加载代码如下:

"""
pickle方式模型持久化
"""

import pickle
from sklearn import linear_model as lm
from src.utils import read_data
import os


def train_and_save_model(data, model_path):
    model = lm.LinearRegression()
    model.fit(data[["x"]], data["y"])
    pickle.dump(model, open(model_path, "wb"))

    return model


def load_model(model_path):
    model = pickle.load(open(model_path, "rb"))
    print(model.coef_)
    return model


if __name__ == "__main__":
    model_path = os.path.dirname(os.path.abspath(__file__)) + "/data/liner_model.pickle"
    train_and_save_model(read_data("simple_example.csv"), model_path)
    load_model(model_path)

使用到自定义模块utis.py代码如下:

import os
import pandas as pd


def read_data(file_name):
    """
    使用pandas读取数据
    """
    home_path = os.path.dirname(os.path.abspath(__file__))
    # Windows下的存储路径与Linux并不相同
    if os.name == "nt":
        data_path = "%s\\data\\%s" % (home_path, file_name)
    else:
        data_path = "%s/data/%s" % (home_path,file_name)

    return pd.read_csv(data_path)

simple.csv数据文件内容如下:

x,y
10,7.7
10,9.87
11,11.18
12,10.43
13,12.36
14,14.15
15,15.73
16,16.4
17,18.86
18,16.13
19,18.21
20,18.37
21,22.61
22,19.83
23,22.67
24,22.7
25,25.16
26,25.55
27,28.21
28,28.12

程序成功运行后,会生成src/data/liner_model.pickle文件,内容如图:

 

PMML方式

PMML方式是标准的一种方式,应用场景:主要应用在不同的环境,比如在python环境中训练模型,然后在Java环境调用模型。

1、安装sklearn2pmml

执行安装命令pip install sklearn2pmml,如图:

 

2、代码示例

pmml_demo.py模块完成模型训练和持久化,这里选用的是最简单的线性回归,代码如下:

import sklearn2pmml as pmml
from sklearn2pmml import PMMLPipeline
from src.utils import read_data
from sklearn import linear_model as lm
import os


def save_model(data, model_path):
    pipeline = PMMLPipeline([("regression", lm.LinearRegression())])

    pipeline.fit(data[["x"]], data["y"])
    pmml.sklearn2pmml(pipeline, model_path, with_repr=True)


if __name__ == "__main__":
    data = read_data("simple_example.csv")
    model_path = model_path = os.path.dirname(os.path.abspath(__file__)) + "/data/liner_model.pmml"
    save_model(data, model_path)

 生成一个src/data/liner_model.pmml文件,其实就是xml文件,内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PMML xmlns="http://www.dmg.org/PMML-4_3" xmlns:data="http://jpmml.org/jpmml-model/InlineTable" version="4.3">
	<Header>
		<Application name="JPMML-SkLearn" version="1.5.32"/>
		<Timestamp>2020-03-11T02:31:05Z</Timestamp>
	</Header>
	<MiningBuildTask>
		<Extension>PMMLPipeline(steps=[('regression', LinearRegression(copy_X=True, fit_intercept=True, n_jobs=1, normalize=False))])</Extension>
	</MiningBuildTask>
	<DataDictionary>
		<DataField name="y" optype="continuous" dataType="double"/>
		<DataField name="x" optype="continuous" dataType="double"/>
	</DataDictionary>
	<RegressionModel functionName="regression">
		<MiningSchema>
			<MiningField name="y" usageType="target"/>
			<MiningField name="x"/>
		</MiningSchema>
		<RegressionTable intercept="-0.9495378313625551">
			<NumericPredictor name="x" coefficient="1.0329669989952859"/>
		</RegressionTable>
	</RegressionModel>
</PMML>

下面通过Java代码来调用这个持久化的模型,其本质就是解析这个xml文件,java工程的pom.xml中需要引入解析模型的依赖包,如下:

<dependency>
	<groupId>org.jpmml</groupId>
	<artifactId>pmml-evaluator</artifactId>
	<version>1.4.1</version>
</dependency>

读取模型文件并做预测的java代码如下: 


import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBException;

import org.dmg.pmml.FieldName;
import org.dmg.pmml.PMML;
import org.jpmml.evaluator.Evaluator;
import org.jpmml.evaluator.FieldValue;
import org.jpmml.evaluator.InputField;
import org.jpmml.evaluator.ModelEvaluatorFactory;
import org.jpmml.evaluator.TargetField;
import org.xml.sax.SAXException;

/**
 * @Description: TODO
 * @author leboop
 * @date 2020年3月11日
 */
public class PMMLDemo {

	private static Evaluator loadPmml(String modelPath) {
		PMML pmml = new PMML();
		InputStream inputStream = null;
		try {
			inputStream = new FileInputStream(modelPath);
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			pmml = org.jpmml.model.PMMLUtil.unmarshal(inputStream);
		} catch (SAXException e1) {
			e1.printStackTrace();
		} catch (JAXBException e1) {
			e1.printStackTrace();
		} finally {
			// 关闭输入流
			try {
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		ModelEvaluatorFactory modelEvaluatorFactory = ModelEvaluatorFactory.newInstance();
		Evaluator evaluator = modelEvaluatorFactory.newModelEvaluator(pmml);
		pmml = null;

		return evaluator;
	}

	private static Object predict(Evaluator evaluator, int fearture) {
		// 输入数据
		Map<String, Integer> data = new HashMap<String, Integer>();
		data.put("x", fearture);
		// 模型的输入特征名称,模型是线性回归y=ax+b,特征名称就是x
		List<InputField> inputFields = evaluator.getInputFields();
		// 输出 [InputField{name=x, dataType=DOUBLE, opType=CONTINUOUS}]
		System.out.println(inputFields);
		// 过模型的原始特征,从画像中获取数据,作为模型输入
		Map<FieldName, FieldValue> arguments = new LinkedHashMap<FieldName, FieldValue>();
		// 遍历模型特征名称
		for (InputField inputField : inputFields) {
			FieldName inputFieldName = inputField.getName();
			// 输出x
			System.out.println(inputFieldName);
			// 从输入数据中获取对应特征名称的输入值,这里特征名称是x,输入值fearture=20,所以rawValue是Integer
			Object rawValue = data.get(inputFieldName.getValue());
			FieldValue inputFieldValue = inputField.prepare(rawValue);
			// 输出:ContinuousDouble{opType=CONTINUOUS, dataType=DOUBLE, value=20.0}
			System.out.println(inputFieldValue);
			// 组装输入的特征名称和对应的数值
			arguments.put(inputFieldName, inputFieldValue);
		}
		// 预测结果并输出map对象:{y=19.70980214854316}
		Map<FieldName, ?> results = evaluator.evaluate(arguments);
		System.out.println(results);
		// 模型的结果参数,输出:TargetField{name=y, dataType=DOUBLE, opType=CONTINUOUS}
		List<TargetField> targetFields = evaluator.getTargetFields();
		FieldName targetFieldName = targetFields.get(0).getName();
		// 获取结果对应的值,也就是y对应的值
		Object targetFieldValue = results.get(targetFieldName);
		// 输出:target: y value: 19.70980214854316
		System.out.println("target: " + targetFieldName.getValue() + " value: " + targetFieldValue);
		
		return targetFieldValue;
	}

	public static void main(String args[]) {
		String modelPath="G:\\pycharm_workspace\\machine_learning_study\\src\\data\\liner_model.pmml";
		Evaluator model = PMMLDemo.loadPmml(modelPath);
		Object result=PMMLDemo.predict(model, 20);
		//最后预测的结果是19.70980214854316
		System.out.println(result);
	}
}

程序输出结果:

[InputField{name=x, dataType=DOUBLE, opType=CONTINUOUS}]
x
ContinuousDouble{opType=CONTINUOUS, dataType=DOUBLE, value=20.0}
{y=19.70980214854316}
target: y value: 19.70980214854316
19.70980214854316

 

版权声明:本文为L_15156024189原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/L_15156024189/article/details/104788886

智能推荐

通信类最新成果(17-19)

- 2019世界移动通信大会(MWC) 1、5G视频+8k画质直播,延迟低至1s,除去解码时间只需40ms。 2、华为带来了一项自动驾驶技术的安全解决方案——车路协同系统。 目前的汽车自动驾驶技术,主要依赖车辆本身的雷达和摄像头。这样感应视野就有一定的局限性。而且感应装置往往无法识别红绿灯等等指示标志。 华为的车路协同系统,相当于为汽车和驾驶员提供了一个“上帝视...

Mysql索引

一.索引相关概念 Mysql索引是什么: 1)定义:索引(Index)是帮助MySQL高效获取数据的数据结构 2)本质:索引是数据结构(排好序的快速查找数据结构) 3)位置:索引本身很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上 优点: 1)提高检索效率,降低I/O成本 2)通过索引对数据进行排序,降低数据排序成本,降低CPU消耗 缺点: 1)虽然提高了查询效率,但降低了更...

MongoDB&C++开发 (七)【转】 MongoDB性能分析

有分析MongoDB性能的需求(主要是插入和查询),查阅资料总结如下。 摘自: MongoDB与MySQL的插入查询性能测试 CSDN博客 1.MongoDB与MySQL的插入查询性能测试 1.1 机器配置&数据规模 数据规模设定在1亿条。 机器配置: CPU:Intel(R) Xeon(R) CPU E5-2620 @ 2.00GHz 内存:65954040 KB (12核CPU,64G...

C++ greater/less 和建堆

文章目录 STL中的greater<>()和less<>() Heap 定义 堆排序 构建堆 堆排序 C++的STL中堆的实现 STL中的greater<>()和less<>() 两个函数的头文件为 排序的时候,默认是从小到大;从大到小排序要使第三个参数为greater()。 建堆的时候,默认是最大堆;最小堆要使第三个参数为greater()。 ma...

dataframe,array,matrix之间的转换和存储

test是一个5行3列的dataFframe...

猜你喜欢

vue-router与keep-alive

vue-router与keep-alive keep-alive是vue内置的一个组件,可以使被包含地组件保留状态,或避免重新渲染。 router-vue是vue-router里注册地组件,我们之前学了它是一个占位符,如果 被包裹在keep-alive里边,所有路径匹配到地视图组件都会被缓存 我们知道vue生命周期,里边有很多的回调函数,当到不同的阶段会执行对应的回调函数。 那一个vue实例何时开...

1.基于vue+element_ui 构建新项目——前期准备工作

一、安装Note.js省略 二、设置nodejs prefix(全局)和cache(缓存)路径 1、在nodejs安装路径下,新建node_global和node_cache两个文件夹 2、设置缓存文件夹  设置全局模块存放路径 设置成功后,之后用命令npm install XXX -g安装以后模块就在E:\develop_software\Nodejs10.15.3\node_global里 三...

EasyTouch5学习笔记

基本: Quick Gesture: 这个组件封装的是快速拖动功能 Quick name为了在脚本中方便调用而设置 Allow on the axes选择在哪个轴上拖动 Allow pick over UI element是否允许忽略掉UI响应 Stop drag on collision enter遇到碰撞体是否停下 Reset physic on drag 拖拽时是否忽略掉刚体 下面是几个事件...

关于STM32的bootloader无法跳转到RT-Thread的一些总结

最近由于工作需要,在调试STM32的bootloader,中间遇到了很多问题。 之前没有接触过BootLoader,跟着原子哥的IAP来学习的Bootlader原理。写了裸机程序来进行调试,过程还算比较顺利。最后在更新APP(基于RT-Thread的程序)时出现了问题,一直调试了好几天。 裸机bootloader跳转裸机的APP程序没有问题,跳转自身也没有问题。通过JLINK直接读取整个芯片,把A...

QCustomplot使用分享(九) 绘制图表-多功能游标

文章目录 一、概述 二、效果图 三、源码讲解 1、源码结构 2、头文件 3、添加游标 4、监测移动 5、移动游标 6、其他函数 四、测试方式 1、测试工程 2、测试文件 3、测试代码 五、相关文章 六、总结 七、关于美化 原文链接:QCustomplot使用分享(九) 绘制图表-多功能游标 一、概述 上一篇文章QCustomplot使用分享(八) 层(完结)讲述了第一篇QCustomPlot控件的...