我需要序列化scikit-learn/statsmodels模型,以便将所有依赖项(代码+数据)打包在人工制品中,并且可以使用该人工制品来初始化模型并进行预测。不能使用pickle module
,因为这只会处理数据依赖关系(不会打包代码)。因此,我一直在使用Dill进行实验。为了使我的问题更加精确,下面是一个示例,其中我构建了一个模型并将其持久化。
from sklearn import datasets
from sklearn import svm
from sklearn.preprocessing import Normalizer
import dill
digits = datasets.load_digits()
training_data_X = digits.data[:-5]
training_data_Y = digits.target[:-5]
test_data_X = digits.data[-5:]
test_data_Y = digits.target[-5:]
class Model:
def __init__(self):
self.normalizer = Normalizer()
self.clf = svm.SVC(gamma=0.001, C=100.)
def train(self, training_data_X, training_data_Y):
normalised_training_data_X = normalizer.fit_transform(training_data_X)
self.clf.fit(normalised_training_data_X, training_data_Y)
def predict(self, test_data_X):
return self.clf.predict(self.normalizer.fit_transform(test_data_X))
model = Model()
model.train(training_data_X, training_data_Y)
print model.predict(test_data_X)
dill.dump(model, open("my_model.dill", 'w'))
与此对应,这是我初始化持久化模型(在新的 session 中)并进行预测的方法。请注意,此代码未明确初始化或不了解
class Model
。import dill
from sklearn import datasets
digits = datasets.load_digits()
training_data_X = digits.data[:-5]
training_data_Y = digits.target[:-5]
test_data_X = digits.data[-5:]
test_data_Y = digits.target[-5:]
with open("my_model.dill") as model_file:
model = dill.load(model_file)
print model.predict(test_data_X)
有谁用过 dill 吗?数据科学家的想法是为他们实现的每个模型扩展
ModelWrapper class
,然后围绕该模型构建基础结构,以保留模型,将模型作为服务部署并管理模型的整个生命周期。class ModelWrapper(object):
__metaclass__ = abc.ABCMeta
def __init__(self, model):
self.model = model
@abc.abstractmethod
def predict(self, input):
return
def dumps(self):
return dill.dumps(self)
def loads(self, model_string):
self.model = dill.loads(model_string)
除了安全隐患(任意代码执行)和必须在服务模型的机器上安装像
scikit-learn
这样的模块的要求之外,这种方法是否存在其他缺陷?任何意见或建议将是最有帮助的。我认为YHat和Dato采取了类似的方法,但是出于类似的目的在那里推出了Dill自己的实现。
最佳答案
我是dill
的作者。 dill
的构建完全是为了完成您的工作……(将数值拟合保留在类实例中以进行统计),然后可以将这些对象分配给不同的资源并以令人尴尬的并行方式运行。因此,答案是肯定的-我已经使用 mystic
和/或 sklearn
运行了与您一样的代码。
请注意,许多sklearn
的作者使用cloudpickle
来启用sklearn
对象的并行计算,而不是dill
。 dill
可以比cloudpickle
pickle 更多类型的对象,但是(在撰写本文时)cloudpickle
在 pickle 将对全局字典的引用作为闭包的一部分的对象方面稍好一些(默认情况下,dill
通过引用做到这一点)物理存储依赖性。但是,cloudpickle
具有dill
模式,其作用类似于"recurse"
,因此使用此模式时的区别很小。 (要启用cloudpickle
模式,请执行"recurse"
,或将dill.settings['recurse'] = True
用作recurse=True
中的标记)。另一个小区别是dill.dump
包含对cloudpickle
和scikits.timeseries
之类的特殊支持,而PIL.Image
不支持。
从好的方面来说,dill
不会通过引用来对类进行 pickle ,因此通过对类实例进行 pickle ,它可以对类对象本身进行序列化-这是一个很大的优势,因为它可以对dill
的分类器,模型等派生类的实例进行序列化处于 pickle 时的确切状态……因此,如果您对类对象进行了修改,则实例仍会正确解包。除了对象的范围更广(通常是较小的 pickle )之外,sklearn
与dill
相比还有其他优点-但是,我不在这里列出它们。您要求陷阱,所以差异不是陷阱。
主要陷阱:
远程机器,以防
cloudpickle
(或dill
)将其 pickle 引用。
尽可能独立的(例如,不要引用在
您类(class)中的全局范围)。
cloudpickle
对象可以很大,因此可以将许多对象保存到一个pickle 并不总是一个好主意……您可能想使用
sklearn
它具有用于缓存和存档的
klepto
接口(interface),并允许您配置存档接口(interface)以分别存储每个键值对(例如,每个文件一个条目)。 关于python - 使用Dill序列化scikit-learn/statsmodels模型有哪些陷阱?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32757656/