1.pkl文件和pmml文件简介
python机器学习模型训练完之后可以保存为pkl文件,也可以保存为pmml文件。
那么什么时候保存为pkl文件,什么时候保存为pmml文件呢?
专业点说:模型需要跨平台使用,交由技术部门用java上线运行,需要使用pmml文件。
简单点说:给python开发用就保存为pkl文件,给java开发用就保存为pmml文件。
本章就讲讲机器学习模型pkl和pmml文件的保存加载使用,以及常见的报错和解决方式。
2.pkl文件的保存,加载,使用
机器学习模型保存为pkl文件有两种方式:可以使用joblib包,也可以使用pickle包。
2.1 joblib包和pickle包保存加载pkl区别
joblib包是由scikit-learn外带的,常用于保存机器学习模型。对于大数据而言,joblib比pickle更加高效。
其实实际使用时用joblib包和pickle包没什么差异。重点是:不要混用!!!
用joblib包保存的模型,最好还是用joblib包加载。因为用joblie包保存模型,加载时却用pickle包会报错:invalid load key, '\x00'。所以保存加载模型的时候建议使用同一个包,不要混着用。
接下来就用鸢尾花数据集,具体演示一下使用joblib包和pickle包保存加载pkl模型,以及用加载的pkl模型文件来预测结果。
2.2 使用joblib包保存加载pkl模型文件
2.2.1 joblib保存pkl模型文件joblib.dump()
# 导入并处理鸢尾花数据集import pandas as pdfrom sklearn.datasets import load_iris iris = load_iris() # 导入鸢尾花数据集df = pd.DataFrame(data=iris.data, columns=[i.replace(' ', '_')for i in iris.feature_names]) # 特征转DataFramedf['target'] = iris.target # 添加目标值df = df[df.target.isin([0, 1 ])] # 取目标值中的0,1类型的数据,用来做二分类算法# 分割数据集,用来训练模型x_train = df.drop('target', axis=1)y_train = df['target']# 使用LGBM训练模型from lightgbm import LGBMClassifiermodel = LGBMClassifier()model.fit(x_train, y_train)# 使用joblib保存模型为pkl文件import joblibjoblib.dump(model, filename='./model_joblib.pkl')
joblib.dump()参数说明: 参数model:要保存的模型(fit训练后的)。
参数filename:要保存的模型路径和名称。
2.2.2 joblib加载pkl模型文件joblib.load()
import joblibmodel = joblib.load(filename='./model_joblib.pkl')
joblib.load()参数说明: 参数filename:要加载的模型路径和名称。
2.3 使用pickle包保存加载pkl模型文件
2.3.1 pickle保存pkl模型文件pickle.dump()
# 导入并处理鸢尾花数据集import pandas as pdfrom sklearn.datasets import load_iris iris = load_iris() # 导入鸢尾花数据集df = pd.DataFrame(data=iris.data, columns=[i.replace(' ', '_')for i in iris.feature_names]) # 特征转DataFramedf['target'] = iris.target # 添加目标值df = df[df.target.isin([0, 1 ])] # 取目标值中的0,1类型的数据,用来做二分类算法# 分割数据集,用来训练模型x_train = df.drop('target', axis=1)y_train = df['target']# 使用LGBM训练模型from lightgbm import LGBMClassifiermodel = LGBMClassifier()model.fit(x_train, y_train)# 使用pickle保存模型为pkl文件import picklepickle.dump(model, file=open('./model_pickle.pkl', 'wb+'))
pickle.dump()参数说明: 参数model:要保存的模型(fit训练后的)。
参数file:简单点说就是要保存的模型路径和名称外加个open。
2.3.2 pickle加载pkl模型文件pickle.load()
import picklemodel = pickle.load(file=open('./model_pickle.pkl', 'rb'))
pickle.load()参数说明: 参数file:简单点说就是要加载的模型路径和名称外加个open。
2.4 使用pickle包加载joblib包保存的pkl模型文件会报错
让我们来试一下,使用pickle包来加载刚刚用joblib包保存的pkl模型文件会怎样。
果然报错啦,invalid load key, '\x00'。所以joblib包和pickle包最好不要混用。
import picklemodel = pickle.load(file=open('./model_joblib.pkl', 'rb'))---------------------------------------------------------------------------UnpicklingError Traceback (most recent call last)<ipython-input-30-1fe488e0924a> in <module> 1 import pickle----> 2 model = pickle.load(file=open('./model_joblib.pkl', 'rb'))UnpicklingError: invalid load key, '\x00'.
2.5 其他加载pkl文件的异常报错
No module named 'sklearn.preprocessing._label'
报错原因:训练模型和加载模型环境的sklearn版本不同。加载模型环境的sklearn的版本太低了。
解决方式:将加载模型环境的sklearn升级,版本>=0.22.X。(安装后重启服务)
pip install scikit-learn==0.22.0
2.6 pkl模型文件加载后预测结果prdict_proba()
pkl模型文件加载后的模型,和建模时训练后的模型是一模一样的,所以建模时怎么预测,加载后就怎么预测。(注:pmml模型文件加载后的模型,预测结果的方式是不同的。)
predict_proba预测结果时,不需要输入变量的名称,但输入的变量顺序必须和模型训练时相同。对比以下两种方式:
# 导入并处理鸢尾花数据集import pandas as pdfrom sklearn.datasets import load_iris iris = load_iris() # 导入鸢尾花数据集df = pd.DataFrame(data=iris.data, columns=[i.replace(' ', '_')for i in iris.feature_names]) # 特征转DataFramedf['target'] = iris.target # 添加目标值df = df[df.target.isin([0, 1 ])] # 取目标值中的0,1类型的数据,用来做二分类算法# 方式1import joblibmodel = joblib.load(filename='./model_joblib.pkl')feature = model.booster_.feature_name() # 查看模型的入模变量df['predict_proba_pkl1'] = model.predict_proba(df[feature])[:, 1] # 预测结果# 方式2import joblibimport numpy as npmodel = joblib.load(filename='./model_joblib.pkl')feature = model.booster_.feature_name() # 查看模型的入模变量df['predict_proba_pkl2'] = model.predict_proba(np.array(df[feature]))[:, 1] # 预测结果# 方式1:predict_proba的输入是DataFrame,DataFrame的变量顺序和入模变量顺序必须相同# 方式2:predict_proba的输入是二维数组,二维数组中的变量顺序和入模变量顺序必须相同# 总结:predict_proba预测结果时,不需要输入变量的名称,但输入的变量顺序必须和模型训练时相同
3.pmml文件的保存,加载,使用
pmml文件一般是给java开发部署的时候才会用到,如果只是pyhton开发使用,建议使用pkl文件。
机器学习模型保存为pmml文件也有两种方式:
(1)在管道pipeline中进行fit后保存为pmml文件。
(2)直接将pkl文件转为pmml文件。
这两种方式保存的pmml文件结果是不同的,当然加载后使用其预测结果的方式也是不同的。
3.1 方式1:在管道pipeline中进行fit后保存为pmml文件,加载,使用
3.1.1 方式1:保存pmml文件
代码如下,可以看到模型在管道pipeline中进行了fit,然后保存为了pmml文件。
# 导入并处理鸢尾花数据集import pandas as pdfrom sklearn.datasets import load_iris iris = load_iris() # 导入鸢尾花数据集df = pd.DataFrame(data=iris.data, columns=[i.replace(' ', '_')for i in iris.feature_names]) # 特征转DataFramedf['target'] = iris.target # 添加目标值df = df[df.target.isin([0, 1 ])] # 取目标值中的0,1类型的数据,用来做二分类算法# 分割数据集,用来训练模型x_train = df.drop('target', axis=1)y_train = df['target']# 加载LGBM模型(不需要训练)from lightgbm import LGBMClassifiermodel = LGBMClassifier()# fit后保存为pmml文件from sklearn2pmml import PMMLPipeline, sklearn2pmmlpipeline = PMMLPipeline([('classifier', model)])pipeline.fit(x_train, y_train)sklearn2pmml(pipeline, 'model_fit_to_pmml.pmml', with_repr=True)
让我们打开生成的pmml文件看一下,里面是些什么内容: 可以看到pmml文件中保存了变量的名称。
<figcaption style="text-align: center; line-height: 1.75; color: rgb(136, 136, 136); font-size: 0.8em;">图片</figcaption>
3.1.2 方式1:加载pmml文件
from pypmml import Modelmodel_pmml = Model.fromFile('model_fit_to_pmml.pmml')model_pmml.inputNames # 查看变量
加载后可以用model_pmml.inputNames来查看入模的变量:输出是具体的入模变量名称。
<figcaption style="text-align: center; line-height: 1.75; color: rgb(136, 136, 136); font-size: 0.8em;">图片</figcaption>
3.1.3 方式1:使用pmml文件预测结果predict()
上文中,pkl文件预测结果的时候,不需要输入变量的名称,但输入的变量顺序必须和模型训练时相同。
那么使用方式1,保存的pmml文件,加载后预测结果输入应该是什么呢?和pkl文件相同吗?
当然是不同的,不然pmml文件内部为什么要保存变量的名称呢。
使用方式1,保存的pmml文件,预测结果时,需要输入变量的名称,但输入的变量顺序无所谓(可以是一个字典)。代码如下:
df['predict_proba_fit_to_pmml'] = model_pmml.predict(df)['probability(1)']# 预测结果时,需要输入变量的名称,但输入的变量顺序无所谓(可以是一个字典)model_pmml.predict(df.to_dict(orient='records')[0])['probability(1)']
3.1.4 方式1:和pkl文件预测结果对比有偏差
使用方式1保存的pmml文件,如果加载后预测结果和pkl文件预测结果对比有偏差。但偏差样本的占比在1%以内,并且偏差的预测概率值在小数点10位之后,那么是正常情况。
原因是:pmml用的是64位浮点,pkl用的是32位浮点。
如果偏差样本占比很大,并且偏差值相差也很大,那么就要检查一下数据和模型了的问题了。
3.2 方式2:直接将pkl文件转为pmml文件
3.2.1 方式2:pkl文件转pmml文件
方式2,直接将pkl文件转成pmml文件,在管道pipeline中省去了fit的步骤。
import joblibmodel = joblib.load(filename='./model_joblib.pkl')from sklearn2pmml import PMMLPipeline, sklearn2pmmlpipeline = PMMLPipeline([('classifier', model)])sklearn2pmml(pipeline, 'model_pkl_to_pmml.pmml', with_repr=True)
让我们打开生成的pmml文件看一下,对比一下方式1生成的pmml文件有什么区别: 我们可以看到,方式1生成的pmml文件原本保存具体变量名的地方,变成了x1、x1...。
<figcaption style="text-align: center; line-height: 1.75; color: rgb(136, 136, 136); font-size: 0.8em;">图片</figcaption>
3.2.2 方式2:加载pmml文件
from pypmml import Modelmodel_pmml = Model.fromFile('model_pkl_to_pmml.pmml')model_pmml.inputNames
加载后可以用model_pmml.inputNames来查看入模的变量:输出x1、x2...,没有具体的指标名。
<figcaption style="text-align: center; line-height: 1.75; color: rgb(136, 136, 136); font-size: 0.8em;">图片</figcaption>
3.2.3 方式2:使用pmml文件预测结果predict()
使用方式2保存的pmml文件因为内部没有保存具体的变量名,所以加载后预测结果,输入和pkl文件一样,不需要输入变量的名称,输入是一个数组,但输入的变量顺序必须和模型训练时相同。
df['predict_proba_pkl_to_pmml'] = [c[1] for c in model_pmml.predict(np.array(df[feature]))]
3.2.4 方式2:和pkl文件预测结果对比有偏差
使用方式2保存的pmml文件,如果加载后预测结果和pkl文件预测结果对比有偏差。
如果偏差占比占比很大,并且偏差值相差特别大,那么应该是数据和模型有问题,需要核查一下。但是如果是偏差值在(-0.005~+0.005)左右,偏差比较大,基本是可以排除数据和模型的问题。这个时候不妨直接把pmml交给java开发,说不定就能对上了。这也许是java环境造成的差异。
3.3 保存pmml文件时报错
RuntimeError: The SkLearn2PMML application has failed. The Java executable should have printed more information about the failure into its standard output and/or standard error streams
报错原因1:没java环境,java环境匹配。
解决方式:安装配置java1.8环境。
报错原因2:sklearn的版本太高了,而sklearn2pmml的版本太低了。
解决方式:升级sklearn2pmml。如果sklearn版本>=0.22.0,sklearn2pmml可以升级到0.51.0。