1.pkl文件和pmml文件簡介
python機(jī)器學(xué)習(xí)模型訓(xùn)練完之后可以保存為pkl文件,也可以保存為pmml文件刊懈。
那么什么時(shí)候保存為pkl文件,什么時(shí)候保存為pmml文件呢恢氯?
專業(yè)點(diǎn)說:模型需要跨平臺(tái)使用靖苇,交由技術(shù)部門用java上線運(yùn)行,需要使用pmml文件苏章。
簡單點(diǎn)說:給python開發(fā)用就保存為pkl文件寂嘉,給java開發(fā)用就保存為pmml文件奏瞬。
本章就講講機(jī)器學(xué)習(xí)模型pkl和pmml文件的保存加載使用,以及常見的報(bào)錯(cuò)和解決方式泉孩。
2.pkl文件的保存硼端,加載,使用
機(jī)器學(xué)習(xí)模型保存為pkl文件有兩種方式:可以使用joblib包寓搬,也可以使用pickle包珍昨。
2.1 joblib包和pickle包保存加載pkl區(qū)別
joblib包是由scikit-learn外帶的,常用于保存機(jī)器學(xué)習(xí)模型句喷。對于大數(shù)據(jù)而言镣典,joblib比pickle更加高效。
其實(shí)實(shí)際使用時(shí)用joblib包和pickle包沒什么差異唾琼。重點(diǎn)是:不要混用P执骸!锡溯!
用joblib包保存的模型赶舆,最好還是用joblib包加載。因?yàn)橛胘oblie包保存模型祭饭,加載時(shí)卻用pickle包會(huì)報(bào)錯(cuò):invalid load key, '\x00'芜茵。所以保存加載模型的時(shí)候建議使用同一個(gè)包,不要混著用倡蝙。
接下來就用鳶尾花數(shù)據(jù)集九串,具體演示一下使用joblib包和pickle包保存加載pkl模型,以及用加載的pkl模型文件來預(yù)測結(jié)果寺鸥。
2.2 使用joblib包保存加載pkl模型文件
2.2.1 joblib保存pkl模型文件joblib.dump()
# 導(dǎo)入并處理鳶尾花數(shù)據(jù)集import pandas as pdfrom sklearn.datasets import load_iris iris = load_iris() # 導(dǎo)入鳶尾花數(shù)據(jù)集df = pd.DataFrame(data=iris.data, columns=[i.replace(' ', '_')for i in iris.feature_names]) # 特征轉(zhuǎn)DataFramedf['target'] = iris.target # 添加目標(biāo)值df = df[df.target.isin([0, 1 ])] # 取目標(biāo)值中的0,1類型的數(shù)據(jù)猪钮,用來做二分類算法# 分割數(shù)據(jù)集,用來訓(xùn)練模型x_train = df.drop('target', axis=1)y_train = df['target']# 使用LGBM訓(xùn)練模型from lightgbm import LGBMClassifiermodel = LGBMClassifier()model.fit(x_train, y_train)# 使用joblib保存模型為pkl文件import joblibjoblib.dump(model, filename='./model_joblib.pkl')
joblib.dump()參數(shù)說明: 參數(shù)model:要保存的模型(fit訓(xùn)練后的)析既。
參數(shù)filename:要保存的模型路徑和名稱躬贡。
2.2.2 joblib加載pkl模型文件joblib.load()
import joblibmodel = joblib.load(filename='./model_joblib.pkl')
joblib.load()參數(shù)說明: 參數(shù)filename:要加載的模型路徑和名稱。
2.3 使用pickle包保存加載pkl模型文件
2.3.1 pickle保存pkl模型文件pickle.dump()
# 導(dǎo)入并處理鳶尾花數(shù)據(jù)集import pandas as pdfrom sklearn.datasets import load_iris iris = load_iris() # 導(dǎo)入鳶尾花數(shù)據(jù)集df = pd.DataFrame(data=iris.data, columns=[i.replace(' ', '_')for i in iris.feature_names]) # 特征轉(zhuǎn)DataFramedf['target'] = iris.target # 添加目標(biāo)值df = df[df.target.isin([0, 1 ])] # 取目標(biāo)值中的0,1類型的數(shù)據(jù)眼坏,用來做二分類算法# 分割數(shù)據(jù)集拂玻,用來訓(xùn)練模型x_train = df.drop('target', axis=1)y_train = df['target']# 使用LGBM訓(xùn)練模型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()參數(shù)說明: 參數(shù)model:要保存的模型(fit訓(xùn)練后的)。
參數(shù)file:簡單點(diǎn)說就是要保存的模型路徑和名稱外加個(gè)open宰译。
2.3.2 pickle加載pkl模型文件pickle.load()
import picklemodel = pickle.load(file=open('./model_pickle.pkl', 'rb'))
pickle.load()參數(shù)說明: 參數(shù)file:簡單點(diǎn)說就是要加載的模型路徑和名稱外加個(gè)open檐蚜。
2.4 使用pickle包加載joblib包保存的pkl模型文件會(huì)報(bào)錯(cuò)
讓我們來試一下,使用pickle包來加載剛剛用joblib包保存的pkl模型文件會(huì)怎樣沿侈。
果然報(bào)錯(cuò)啦闯第,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文件的異常報(bào)錯(cuò)
No module named 'sklearn.preprocessing._label'
報(bào)錯(cuò)原因:訓(xùn)練模型和加載模型環(huán)境的sklearn版本不同咳短。加載模型環(huán)境的sklearn的版本太低了填帽。
解決方式:將加載模型環(huán)境的sklearn升級(jí),版本>=0.22.X咙好。(安裝后重啟服務(wù))
pip install scikit-learn==0.22.0
2.6 pkl模型文件加載后預(yù)測結(jié)果prdict_proba()
pkl模型文件加載后的模型篡腌,和建模時(shí)訓(xùn)練后的模型是一模一樣的,所以建模時(shí)怎么預(yù)測勾效,加載后就怎么預(yù)測嘹悼。(注:pmml模型文件加載后的模型,預(yù)測結(jié)果的方式是不同的层宫。)
predict_proba預(yù)測結(jié)果時(shí)杨伙,不需要輸入變量的名稱,但輸入的變量順序必須和模型訓(xùn)練時(shí)相同萌腿。對比以下兩種方式:
# 導(dǎo)入并處理鳶尾花數(shù)據(jù)集import pandas as pdfrom sklearn.datasets import load_iris iris = load_iris() # 導(dǎo)入鳶尾花數(shù)據(jù)集df = pd.DataFrame(data=iris.data, columns=[i.replace(' ', '_')for i in iris.feature_names]) # 特征轉(zhuǎn)DataFramedf['target'] = iris.target # 添加目標(biāo)值df = df[df.target.isin([0, 1 ])] # 取目標(biāo)值中的0,1類型的數(shù)據(jù)限匣,用來做二分類算法# 方式1import joblibmodel = joblib.load(filename='./model_joblib.pkl')feature = model.booster_.feature_name() # 查看模型的入模變量df['predict_proba_pkl1'] = model.predict_proba(df[feature])[:, 1] # 預(yù)測結(jié)果# 方式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] # 預(yù)測結(jié)果# 方式1:predict_proba的輸入是DataFrame,DataFrame的變量順序和入模變量順序必須相同# 方式2:predict_proba的輸入是二維數(shù)組毁菱,二維數(shù)組中的變量順序和入模變量順序必須相同# 總結(jié):predict_proba預(yù)測結(jié)果時(shí)膛腐,不需要輸入變量的名稱,但輸入的變量順序必須和模型訓(xùn)練時(shí)相同
3.pmml文件的保存鼎俘,加載,使用
pmml文件一般是給java開發(fā)部署的時(shí)候才會(huì)用到辩涝,如果只是pyhton開發(fā)使用贸伐,建議使用pkl文件。
機(jī)器學(xué)習(xí)模型保存為pmml文件也有兩種方式:
(1)在管道pipeline中進(jìn)行fit后保存為pmml文件怔揩。
(2)直接將pkl文件轉(zhuǎn)為pmml文件捉邢。
這兩種方式保存的pmml文件結(jié)果是不同的,當(dāng)然加載后使用其預(yù)測結(jié)果的方式也是不同的商膊。
3.1 方式1:在管道pipeline中進(jìn)行fit后保存為pmml文件伏伐,加載,使用
3.1.1 方式1:保存pmml文件
代碼如下晕拆,可以看到模型在管道pipeline中進(jìn)行了fit藐翎,然后保存為了pmml文件。
# 導(dǎo)入并處理鳶尾花數(shù)據(jù)集import pandas as pdfrom sklearn.datasets import load_iris iris = load_iris() # 導(dǎo)入鳶尾花數(shù)據(jù)集df = pd.DataFrame(data=iris.data, columns=[i.replace(' ', '_')for i in iris.feature_names]) # 特征轉(zhuǎn)DataFramedf['target'] = iris.target # 添加目標(biāo)值df = df[df.target.isin([0, 1 ])] # 取目標(biāo)值中的0,1類型的數(shù)據(jù)实幕,用來做二分類算法# 分割數(shù)據(jù)集吝镣,用來訓(xùn)練模型x_train = df.drop('target', axis=1)y_train = df['target']# 加載LGBM模型(不需要訓(xùn)練)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文件看一下,里面是些什么內(nèi)容: 可以看到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文件預(yù)測結(jié)果predict()
上文中,pkl文件預(yù)測結(jié)果的時(shí)候整吆,不需要輸入變量的名稱拱撵,但輸入的變量順序必須和模型訓(xùn)練時(shí)相同辉川。
那么使用方式1,保存的pmml文件拴测,加載后預(yù)測結(jié)果輸入應(yīng)該是什么呢乓旗?和pkl文件相同嗎?
當(dāng)然是不同的昼扛,不然pmml文件內(nèi)部為什么要保存變量的名稱呢寸齐。
使用方式1,保存的pmml文件抄谐,預(yù)測結(jié)果時(shí)渺鹦,需要輸入變量的名稱,但輸入的變量順序無所謂(可以是一個(gè)字典)蛹含。代碼如下:
df['predict_proba_fit_to_pmml'] = model_pmml.predict(df)['probability(1)']# 預(yù)測結(jié)果時(shí)毅厚,需要輸入變量的名稱,但輸入的變量順序無所謂(可以是一個(gè)字典)model_pmml.predict(df.to_dict(orient='records')[0])['probability(1)']
3.1.4 方式1:和pkl文件預(yù)測結(jié)果對比有偏差
使用方式1保存的pmml文件浦箱,如果加載后預(yù)測結(jié)果和pkl文件預(yù)測結(jié)果對比有偏差吸耿。但偏差樣本的占比在1%以內(nèi),并且偏差的預(yù)測概率值在小數(shù)點(diǎn)10位之后酷窥,那么是正常情況咽安。
原因是:pmml用的是64位浮點(diǎn),pkl用的是32位浮點(diǎn)蓬推。
如果偏差樣本占比很大妆棒,并且偏差值相差也很大,那么就要檢查一下數(shù)據(jù)和模型了的問題了沸伏。
3.2 方式2:直接將pkl文件轉(zhuǎn)為pmml文件
3.2.1 方式2:pkl文件轉(zhuǎn)pmml文件
方式2糕珊,直接將pkl文件轉(zhuǎn)成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文件有什么區(qū)別: 我們可以看到,方式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...苟蹈,沒有具體的指標(biāo)名。
<figcaption style="text-align: center; line-height: 1.75; color: rgb(136, 136, 136); font-size: 0.8em;">圖片</figcaption>
3.2.3 方式2:使用pmml文件預(yù)測結(jié)果predict()
使用方式2保存的pmml文件因?yàn)閮?nèi)部沒有保存具體的變量名右核,所以加載后預(yù)測結(jié)果慧脱,輸入和pkl文件一樣,不需要輸入變量的名稱贺喝,輸入是一個(gè)數(shù)組菱鸥,但輸入的變量順序必須和模型訓(xùn)練時(shí)相同宗兼。
df['predict_proba_pkl_to_pmml'] = [c[1] for c in model_pmml.predict(np.array(df[feature]))]
3.2.4 方式2:和pkl文件預(yù)測結(jié)果對比有偏差
使用方式2保存的pmml文件,如果加載后預(yù)測結(jié)果和pkl文件預(yù)測結(jié)果對比有偏差氮采。
如果偏差占比占比很大殷绍,并且偏差值相差特別大,那么應(yīng)該是數(shù)據(jù)和模型有問題鹊漠,需要核查一下主到。但是如果是偏差值在(-0.005~+0.005)左右,偏差比較大躯概,基本是可以排除數(shù)據(jù)和模型的問題登钥。這個(gè)時(shí)候不妨直接把pmml交給java開發(fā),說不定就能對上了娶靡。這也許是java環(huán)境造成的差異牧牢。
3.3 保存pmml文件時(shí)報(bào)錯(cuò)
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
報(bào)錯(cuò)原因1:沒java環(huán)境,java環(huán)境匹配姿锭。
解決方式:安裝配置java1.8環(huán)境塔鳍。
報(bào)錯(cuò)原因2:sklearn的版本太高了,而sklearn2pmml的版本太低了呻此。
解決方式:升級(jí)sklearn2pmml轮纫。如果sklearn版本>=0.22.0,sklearn2pmml可以升級(jí)到0.51.0焚鲜。