我尝试在两台不同的计算机上运行它,但每当我尝试加载pickle文件时,我都会得到:
AttributeError: Can't get attribute 'MyClass'
我试图了解我做错了什么,或者我对泡菜的作用是否有错误的理解?我该如何解决它?
我想知道为什么当我只调用 xyz.fit(data) 时 SKLearn 就可以工作,并且在加载 pickle 后它就可以工作,同时我调用 xyz.add_one(5) 的代码给了我一个错误?
我自己的班级: 制作泡菜:
import base64
import pickle
class MyClass:
def add_one(self, x):
return x + 1
obj = MyClass()
add_one = obj
pickled_data = pickle.dumps(add_one)
encoded_data = base64.b64encode(pickled_data)
with open("some_location.txt", "wb") as f:
f.write(encoded_data)
在另一台计算机上加载 Pickle:
import base64
import pickle
# Read the encoded data from the file
with open("some_location.txt", "rb") as f:
encoded_data = f.read()
pickled_data = base64.b64decode(encoded_data)
loaded = pickle.loads(pickled_data)
result = loaded.add_one(5)
print(result) # Output: 6
# Errored out: AttributeError: Can't get attribute 'MyClass'
同时,当我尝试使用 SKlearn 执行此操作时,我能够毫无问题地调用类中保存的方法。 示例:
from sklearn import svm
from sklearn import datasets
import pickle
iris = datasets.load_iris()
X, y = iris.data, iris.target
clf = svm.SVC()
clf.fit(X, y)
with open("/dbfs/FileStore/tables/tmp/test.txt",'wb') as f:
pickle.dump(clf,f)
在单独的计算机中:
import pickle
X = [[5.1, 3.5, 1.4, 0.2],
[4.9, 3, 1.4, 0.2],
[4.7, 3.2, 1.3, 0.2],
[4.6, 3.1, 1.5, 0.2],
[5, 3.6, 1.4, 0.2]]
with open('/dbfs/FileStore/tables/tmp/test.txt', 'rb') as f:
clf2 = pickle.load(f)
print(clf2.predict(X[0:5]))
完整的错误输出在这里很有帮助。如果我们将第一个脚本放入
t.py
中,将第二个脚本放入 y.py
中,然后依次运行一个脚本,我们会得到:
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "/private/tmp/tmpvenv-ec8f9/y.py", line 10, in <module>
loaded = pickle.loads(pickled_data)
^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: Can't get attribute 'MyClass' on <module 'y' from '/private/tmp/tmpvenv-ec8f9/y.py'>
最后一行向我们表明,Python 正在尝试重新水合对象,并正在寻找
MyClass
类型来重新创建 obj
。所以它在我们正在运行的文件中寻找该类(on <module 'y' from '/private/tmp/tmpvenv-ec8f9/y.py'>
)。但是,当然,MyClass
不存在。
这里的问题是,当我们尝试再次加载正在腌制的对象时,无法找到该对象的类型。当您 pickle
sklearn.SVC
实例时,该代码可能适合您,因为您在两个环境中都安装了该库,因此当您加载 pickle 对象时它始终可用。 (可以确认一下吗?)
我们可以通过在
MyClass
中添加 y.py
来完成这项工作(尽管可能会产生令人惊讶的结果)。如果我们添加:
import base64
import pickle
+ class MyClass:
+ def add_one(self, x):
+ return x + 10
# Read the encoded data from the file
with open("some_location.txt", "rb") as f:
encoded_data = f.read()
pickled_data = base64.b64decode(encoded_data)
loaded = pickle.loads(pickled_data)
result = loaded.add_one(5)
print(result)
然后当我们运行它时我们得到:
$ python -m y
15
加载腌制对象已恢复,但使用
MyClass
中定义的 y.py
类型,这与原来的有所不同!