pickle/joblib AttributeError: module '__main__' has no attribute 'thing' in pytest

pickle/joblib AttributeError: module '__main__' has no attribute 'thing' in pytest

我已经构建了一个自定义的sklearn管道,如下:

pipeline = make_pipeline(
    SelectColumnsTransfomer(features_to_use),
    ToDummiesTransformer('feature_0', prefix='feat_0', drop_first=True,  dtype=bool), # Dummify customer_type
    ToDummiesTransformer('feature_1', prefix='feat_1'), # Dummify the feature
    ToDummiesTransformer('feature_2', prefix='feat_2'), # Dummify 
    ToDummiesTransformer('feature_3', prefix='feat_3'), # Dummify
)
pipeline.fit(df)

SelectColumnsTransfomerToDummiesTransformer 是实现 BaseEstimatorTransformerMixin 的自定义 sklearn 步骤。 为了序列化这个对象,我使用

from sklearn.externals import joblib
joblib.dump(pipeline, 'data_pipeline.joblib')

但是当我用

反序列化时
pipeline = joblib.load('data_pipeline.joblib') 

我得到 AttributeError: module '__main__' has no attribute 'SelectColumnsTransfomer'

我已阅读其他类似问题并按照此博文 here 中的说明进行操作,但无法解决问题。 我正在复制粘贴 类,并将它们导入代码中。如果我创建此练习的简化版本,整个过程都有效,但出现问题是因为我 运行 正在使用 pytest 进行一些测试,而当我 运行 pytest 时,它似乎没有看到我的自定义类,其实还有这部分错误 self = <sklearn.externals.joblib.numpy_pickle.NumpyUnpickler object at 0x7f821508a588>, module = '__main__', name = 'SelectColumnsTransfomer' 这暗示我 NumpyUnpickler 看不到 SelectColumnsTransfomer 即使在测试中它是导入的。

我的测试代码

import pytest
from app.pipeline import * # the pipeline objects 
                          # SelectColumnsTransfomer and ToDummiesTransformer 
                          # are here!


@pytest.fixture(scope="module")
def clf():
    pipeline = joblib.load("persistence/data_pipeline.joblib")
    return clf

def test_fake(clf):
    assert True

好的,我发现问题了。我发现这个问题与我原先认为的Python: pickling and dealing with "AttributeError: 'module' object has no attribute 'Thing'"博文中解释的问题无关。 您可以通过对文件进行酸洗和取消酸洗来轻松解决问题。我使用一个单独的脚本(一个 Jupyther 笔记本)来 pickle 和一个普通的 [python 脚本来 unpicle。当我在同一个 class 中完成所有操作时,它起作用了。

当我尝试像这样保存 Pytorch class 时收到相同的错误消息:

import torch.nn as nn

class custom(nn.Module):
    def __init__(self):
        super(custom, self).__init__()
        print("Class loaded")

model = custom()

然后像这样使用 Joblib 转储此模型:

from joblib import dump
dump(model, 'some_filepath.jobjib')

问题是我在 Kaggle 内核中 运行ning 上面的代码。然后下载转储文件并尝试在本地使用此脚本加载它:

from joblib import load
model = load(model, 'some_filepath.jobjib')

我解决这个问题的方法是 运行 所有这些代码片段都在我的本地计算机上,而不是创建 class 并将其转储到 Kaggle 上,而是加载它在我的本地机器上。想在这里添加这个,因为@DarioB 对 的评论让我感到困惑,因为他们提到了 'function',这不适用于我更简单的情况。