我需要序列化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这样的模块的要求之外,这种方法是否存在其他缺陷?任何意见或建议将是最有帮助的。

我认为YHatDato采取了类似的方法,但是出于类似的目的在那里推出了Dill自己的实现。

最佳答案

我是dill的作者。 dill的构建完全是为了完成您的工作……(将数值拟合保留在类实例中以进行统计),然后可以将这些对象分配给不同的资源并以令人尴尬的并行方式运行。因此,答案是肯定的-我已经使用 mystic 和/或 sklearn 运行了与您一样的代码。

请注意,许多sklearn的作者使用cloudpickle来启用sklearn对象的并行计算,而不是dilldill可以比cloudpickle pickle 更多类型的对象,但是(在撰写本文时)cloudpickle在 pickle 将对全局字典的引用作为闭包的一部分的对象方面稍好一些(默认情况下,dill通过引用做到这一点)物理存储依赖性。但是,cloudpickle具有dill模式,其作用类似于"recurse",因此使用此模式时的区别很小。 (要启用cloudpickle模式,请执行"recurse",或将dill.settings['recurse'] = True用作recurse=True中的标记)。另一个小区别是dill.dump包含对cloudpicklescikits.timeseries之类的特殊支持,而PIL.Image不支持。

从好的方面来说,dill不会通过引用来对类进行 pickle ,因此通过对类实例进行 pickle ,它可以对类对象本身进行序列化-这是一个很大的优势,因为它可以对dill的分类器,模型等派生类的实例进行序列化处于 pickle 时的确切状态……因此,如果您对类对象进行了修改,则实例仍会正确解包。除了对象的范围更广(通常是较小的 pickle )之外,sklearndill相比还有其他优点-但是,我不在这里列出它们。您要求陷阱,所以差异不是陷阱。

主要陷阱:

  • 您应该在类上安装您的类引用的任何内容
    远程机器,以防cloudpickle(或dill)将其 pickle
    引用。
  • 您应该尝试将您的类和类方法设置为
    尽可能独立的(例如,不要引用在
    您类(class)中的全局范围)。
  • cloudpickle对象可以很大,因此可以将许多对象保存到一个
    pickle 并不总是一个好主意……您可能想使用 sklearn
    它具有用于缓存和存档的klepto接口(interface),并允许您配置存档接口(interface)以分别存储每个键值对(例如,每个文件一个条目)。
  • 关于python - 使用Dill序列化scikit-learn/statsmodels模型有哪些陷阱?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32757656/

    10-12 23:14