Serialization 定制scikit学习酸洗不';不能在网格搜索中工作

Serialization 定制scikit学习酸洗不';不能在网格搜索中工作,serialization,scikit-learn,keras,pickle,Serialization,Scikit Learn,Keras,Pickle,我已经写了一个scikit学习估计器。它有一个参数和一个由fit设置的model属性 class MyEstimator(BaseEstimator, TransformerMixin): def __init__(self, param="default"): self.param = param self.model_ = None def fit(self, x, y): # Sets the value of self.m

我已经写了一个scikit学习估计器。它有一个参数和一个由
fit
设置的
model
属性

class MyEstimator(BaseEstimator, TransformerMixin):
    def __init__(self, param="default"):
        self.param = param
        self.model_ = None

    def fit(self, x, y):
        # Sets the value of self.model_
我希望能够pickle
MyEstimator
,但是我创建的
model\uu
对象不能用pickle序列化,因为它是一个模型。按照博客文章“”的示例,我向类中添加了以下pickling处理程序方法

class MyEstimator(BaseEstimator, TransformerMixin):
    def __getstate__(self):
        state = super().__getstate__().copy()
        with tempfile.NamedTemporaryFile(suffix=".hdf5", delete=True) as fd:
            keras.models.save_model(self.model_, fd.name, overwrite=True)
            state["model_"] = fd.read()
        return state

    def __setstate__(self, state):
        super().__setstate__(state)
        with tempfile.NamedTemporaryFile(suffix=".hdf5", delete=True) as fd:
            fd.write(state["model_"])
            fd.flush()
            self.__dict__["model_"] = keras.models.load_model(fd.name)
这将用keras的序列化程序生成的可pickle的表示形式替换不可pickle的
模型
成员。使用这种定制,我可以调用
fit
,序列化和反序列化,并返回我的原始模型。一切正常

e = MyEstimator()
e.fit(x, y)
with open("myfile.pk", mode="wb") as f:
    pickle.dump(e, f)
with open("myfile.pk", mode="rb") as f:
    pickle.load(f) # Returns a copy of e
但是,当我试图将MyEstimator放入a中并对a的结果进行pickle处理时,序列化不起作用

pickle.dump
调用过程中,我希望看到
MyEstimator.\uuuuu getstate\uuuu
使用一个合适的
self.model\uu
对象调用。(这是我在网格搜索之外单独序列化模型时发生的情况。)相反,
self.model
None
,因此我无法序列化网格搜索生成的
best\u estimator

看起来网格搜索序列化正在实例化一个新的
MyEstimator
对象,而不是使用管道中的对象。我觉得这是不对的。我已经浏览了scikit学习代码,但看不出这是在哪里发生的

这是scikit learn中的一个bug,还是我做错了什么


(注意:keras确实有一个可以将某些keras模型转换为scikit学习估计器的方法,但出于其他原因,我不能在这里使用它,我不确定它是否会有相同的问题。)

搜索对象包含一个混合的
MyEstimator
对象,其中一些对象没有调用
fit
。修复方法是在尝试使用keras工具序列化之前,检查
model_uu
是否为
None

class MyEstimator(BaseEstimator, TransformerMixin):
    def __getstate__(self):
        state = super().__getstate__().copy()
        if self.model_ is not None:
            with tempfile.NamedTemporaryFile(suffix=".hdf5", delete=True) as fd:
                keras.models.save_model(self.model_, fd.name, overwrite=True)
                state["model_"] = fd.read()
        return state

    def __setstate__(self, state):
        super().__setstate__(state)
        if self.model_ is not None:
            with tempfile.NamedTemporaryFile(suffix=".hdf5", delete=True) as fd:
                fd.write(state["model_"])
                fd.flush()
                self.__dict__["model_"] = keras.models.load_model(fd.name)

我不知道为什么在网格搜索完成后,搜索对象中会有任何不适合的模型,但确实有。

看看这一点:大多数scikit中的模型评估工具,如
cross\u val\u score
GridSearchCV
等,都会在拟合之前克隆给定的估计器。在GridSearchCV中,您可以看到它克隆了它。指出特定的源代码行会有所帮助。我在调试器中单步执行此过程时迷路了。我不明白为什么搜索完成后会有任何克隆没有调用
fit
。你是在尝试pickle整个
GridSearchCV
对象,还是仅仅是
GridSearchCV。最佳估计器(基本上就是你想要的)我正在尝试pickle整个搜索对象。我知道,
GridSearchCV.best_estimator\u
是我在测试时使用的,但我也想比较各种超参数设置的交叉验证分数。
class MyEstimator(BaseEstimator, TransformerMixin):
    def __getstate__(self):
        state = super().__getstate__().copy()
        if self.model_ is not None:
            with tempfile.NamedTemporaryFile(suffix=".hdf5", delete=True) as fd:
                keras.models.save_model(self.model_, fd.name, overwrite=True)
                state["model_"] = fd.read()
        return state

    def __setstate__(self, state):
        super().__setstate__(state)
        if self.model_ is not None:
            with tempfile.NamedTemporaryFile(suffix=".hdf5", delete=True) as fd:
                fd.write(state["model_"])
                fd.flush()
                self.__dict__["model_"] = keras.models.load_model(fd.name)