【问题标题】:What are the pitfalls of using Dill to serialise scikit-learn/statsmodels models?使用 Dill 序列化 scikit-learn/statsmodels 模型的陷阱是什么?
【发布时间】:2015-12-21 20:07:33
【问题描述】:

我需要序列化 ​​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'))

与此相对应,这是我如何初始化持久模型(在新会话中)并进行预测。请注意,此代码没有显式初始化或知道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 is this way吗?这个想法是让数据科学家为他们实施的每个模型扩展一个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 实现。

【问题讨论】:

  • 好的。我有一个工作原型,它似乎工作正常。现在,我需要对 R 做同样的事情。对此有什么建议吗?

标签: python scikit-learn pickle statsmodels dill


【解决方案1】:

好的,在您的示例代码中 pickle 可以正常工作,我一直使用 pickle 来打包模型并在以后使用它,除非您想将模型直接发送到另一台服务器或保存 @987654322 @,因为那是Dill擅长的,pickle做不到的。这还取决于您的代码、您使用的类型等,pickle 可能会失败,Dill 更稳定。

Dill 主要基于pickle,因此它们非常相似,您应该考虑/研究一些事情:

  1. Dill的限制

    frame,generator,traceback标准类型不能打包。

  2. cloudpickle 也可能是解决您的问题的好主意,它在酸洗对象方面有更好的支持(比泡菜,不比 Dill 更好),您也可以轻松地泡菜代码。

一旦目标机器加载了正确的库(注意不同的python 版本,因为它们可能会错误您的代码),只要Dillcloudpickle 都应该可以正常工作,只要不要使用不受支持的标准类型。

希望这会有所帮助。

【讨论】:

  • 我需要在另一台服务器上运行模型。这个想法是将模型存储在键值存储中,并在需要时将它们放在服务端点后面。
  • 那么Dillcloudpickle 应该都能满足您的需求。
【解决方案2】:

我使用picklescikit-learn 打包高斯过程(GP)。

主要原因是因为使用pickle 构建GP 需要很长时间并且加载速度更快。因此,在我的代码初始化中,我检查模型的数据文件是否已更新并在必要时重新生成模型,否则只需从 pickle 反序列化它!

我会按各自的顺序使用pickledillcloudpickle

注意pickle 包含protocol 关键字参数,一些值可以显着加快和减少内存使用! 最后,如有必要,我会使用 CPython STL 的压缩来包装 pickle 代码。

【讨论】:

    【解决方案3】:

    我是dill 作者。 dill 旨在完全按照您正在做的事情......(在类实例中保持数值拟合以进行统计),然后这些对象可以分布到不同的资源并以令人尴尬的并行方式运行。所以,答案是肯定的——我已经使用mystic 和/或sklearn 运行了像你这样的代码。

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

    从好的方面来说,dill 不会通过引用来腌制类,因此通过腌制类实例,它会序列化类对象本身——这是一个很大的优势,因为它序列化分类器、模型的派生类的实例, 等等来自sklearn 在酸洗时的确切状态......所以如果你对类对象进行修改,实例仍然会正确取消选择。 dillcloudpickle 相比还有其他优点,除了对象范围更广(通常是更小的泡菜)——但是,我不会在这里列出它们。你问的是陷阱,所以差异不是陷阱。

    主要陷阱:

    • 你应该将你的类引用的任何东西都安装在 远程机器,以防万一dill(或cloudpickle)通过腌制它 参考。

    • 您应该尝试将您的类和类方法设置为 尽可能自包含(例如,不要引用定义在 类的全局范围)。

    • sklearn 对象可能很大,因此将其中许多对象保存到一个 泡菜并不总是一个好主意……您可能想使用klepto 它具有用于缓存和归档的dict 接口,并允许您配置归档接口以单独存储每个键值对(例如每个文件一个条目)。

    【讨论】:

    • 作者您好,如何使 dill dump 结果变小,有没有压缩级别选项?
    • @CSQGB:您可以选择不同的序列化协议之一......它们会产生不同大小的泡菜。我相信,更高的版本号往往会更小。在压缩方面,像klepto(使用dill)这样的库可以提供一个压缩的序列化对象。
    猜你喜欢
    • 2011-12-13
    • 2019-04-17
    • 2013-12-21
    • 2018-05-26
    • 2011-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-09
    相关资源
    最近更新 更多