我想创建一个持久的scikit-learn模型,稍后通过哈希对其进行引用。使用joblib进行序列化,如果我的数据没有变化,我期望完全(位级)完整性。但是每次我运行代码时,磁盘上的模型文件都会具有不同的哈希值。为什么会这样,并且每次我运行代码不变时如何进行真正相同的序列化?设置固定的种子无济于事(在这个简单的示例中,不确定sklearn的算法是否完全利用随机数)。
import numpy as np
from sklearn import linear_model
import joblib
import hashlib
# set a fixed seed …
np.random.seed(1979)
# internal md5sum function
def md5(fname):
hash_md5 = hashlib.md5()
with open(fname, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
# dummy regression data
X = [[0., 0., 0.,1.], [1.,0.,0.,0.], [2.,2.,0.,1.], [2.,5.,1.,0.]]
Y = [[0.1, -0.2], [0.9, 1.1], [6.2, 5.9], [11.9, 12.3]]
# create model
reg = linear_model.LinearRegression()
# save model to disk to make it persistent
with open("reg.joblib", "w"):
joblib.dump(reg, "reg.joblib")
# load persistant model from disk
with open("reg.joblib", "r"):
model = joblib.load("reg.joblib")
# fit & predict
reg.fit(X,Y)
model.fit(X,Y)
myprediction1 = reg.predict([[2., 2., 0.1, 1.1]])
myprediction2 = model.predict([[2., 2., 0.1, 1.1]])
# run several times … why does md5sum change everytime?
print(md5("reg.joblib"))
print(myprediction1, myprediction2)
经过一番研究,我找到了我问题的答案。对于每次运行,joblib文件具有不同的哈希值的问题与scikit-learn或训练后的模型无关。实际上,可以使用joblib.hash(reg)
证明纯模型的MD5和是相同的,这意味着训练后的回归模型的权重没有变化。这个方便的功能现在也解决了我原来的“业务”问题。
转储文件的不可复制MD5总和的根本原因在于pickle
所基于的基础joblib.dump
序列化模型的实现。决定性的提示来自How to hash a large object (dataset) in Python?。 old finding在互联网深度的某个位置提供了一些背景信息:
由于pickle数据格式实际上是一种很小的面向堆栈的编程语言,并且某些对象的编码具有一定的自由度,所以两个模块可能为同一输入对象生成不同的数据流。但是,可以保证它们始终能够读取彼此的数据流。