pickle/joblib AttributeError:模块'__main__'在pytest中没有属性'thing'

Posted

技术标签:

【中文标题】pickle/joblib AttributeError:模块\'__main__\'在pytest中没有属性\'thing\'【英文标题】:pickle/joblib AttributeError: module '__main__' has no attribute 'thing' in pytestpickle/joblib AttributeError:模块'__main__'在pytest中没有属性'thing' 【发布时间】:2019-04-10 04:04:52 【问题描述】:

我已经建立了一个自定义的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

【问题讨论】:

joblib.load __main__ AttributeError的可能重复 【参考方案1】:

好的,我发现了问题。我发现这个问题与我最初认为的 Python: pickling and dealing with "AttributeError: 'module' object has no attribute 'Thing'" 的博文中解释的问题无关。 您可以通过对对象进行酸洗和取消酸洗文件来轻松解决问题。我正在使用一个单独的脚本(一个 Jupyther 笔记本)来腌制,并使用一个普通的 [python 脚本来取消腌制。当我在同一个班级做所有事情时,它起作用了。

【讨论】:

“让你的对象拾取和解开文件”是什么意思?您能否在您的答案中也分享代码。 拾取和拆解必须由同一个对象在同一个脚本内完成。 您确定旧对象不只是重新使用吗?我不认为答案解决方案适用于 Python 实例。 这个答案看不懂。 今天我在寻找解决方案,所以要详细说明一下:“定义函数的模块必须是可导入的,并且必须具有函数名称作为属性”。如果函数是在 Jupyter Notebook 中定义的,则它是不可导入的,因此在可导入模块中定义它是使它能够工作的原因。【参考方案2】:

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

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 内核中运行上面的代码。然后下载转储文件并尝试在本地使用此脚本加载它:

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

我解决问题的方法是在我的计算机上本地运行所有这些代码 sn-ps,而不是创建类并将其转储到 Kaggle,而是将其加载到我的本地计算机上。想在此处添加此内容,因为 @DarioB 的 answer 上的 cmets 让我感到困惑,因为他们提到了一个不适用于我更简单的情况的“函数”。

【讨论】:

以上是关于pickle/joblib AttributeError:模块'__main__'在pytest中没有属性'thing'的主要内容,如果未能解决你的问题,请参考以下文章

python 串口

使用opencv进行人脸识别时出现属性错误

在 Python 中导入历史标准普尔 500 指数数据 [关闭]

如何在 PyQt5 中返回 QlistWidget 中项目的值

Python:获取所有节点的度数,然后在networkx中绘制箱线图

gwpy 包给出错误 - AttributeError:模块“matplotlib.pyplot”在 Google Colab 中没有属性“FigureManagerBase”