当我在 linux (x86-64) 中反序列化已在 os-x (darwin) 上序列化的causalml (0.10.0) 模型时,出现以下错误:
ValueError: numpy.ndarray size changed, may indicate binary incompatibility.
出乎意料的是,尝试在同一个 python 会话中再次反序列化它确实成功了!
环境
在序列化机器上:
- Python 3.8,一首诗 .venv
- numpy
1.18.5
(兼容 causalml 0.10.0 的最新版本) - 操作系统-x
在反序列化机器上:
- 基于 AWS lambda python 3.8 的 docker
- 蟒蛇 3.8
- linux x86_64
两者都有cython
版本0.28
,causalml
版本0.10.0
。
使用cython
版本0.29.26
(根据pip兼容),重新运行不成功。
错误在causaltree.cpython-38-x86_64-linux-gnu.so
.
Joblib 或 Pickle
我尝试了 python 的pickle
和joblib
,都引发了错误。
在使用 joblib 的情况下,会发生以下堆栈跟踪:
File "/var/task/joblib/numpy_pickle.py", line 577, in load
obj = _unpickle(fobj)
File "/var/task/joblib/numpy_pickle.py", line 506, in _unpickle
obj = unpickler.load()
File "/var/lang/lib/python3.8/pickle.py", line 1212, in load
dispatch[key[0]](self)
File "/var/lang/lib/python3.8/pickle.py", line 1537, in load_stack_global
self.append(self.find_class(module, name))
File "/var/lang/lib/python3.8/pickle.py", line 1579, in find_class
__import__(module, level=0)
File "/var/task/causalml/inference/tree/__init__.py", line 3, in <module>
from .causaltree import CausalMSE, CausalTreeRegressor
File "__init__.pxd", line 238, in init causalml.inference.tree.causaltree
使用更新的 python 版本
其他答案提到升级(在反序列化环境中)到更新的 numpy,它应该是向后兼容的,可能会有所帮助。就我而言,它没有帮助。
安装 causalml 后,我pip3 install --upgrade numpy==XXX
在反序列化机器上单独替换了 numpy 版本。
- 对于 numpy
1.18.5
和1.19.5
,错误提到:Expected 96 from C header, got 80 from PyObject
- 使用 numpy
1.20.3
,错误提到:Expected 96 from C header, got 88 from PyObject
其他 numpy 数组可以序列化和反序列化吗?:是的
为了验证 numpy 序列化和反序列化是否真的可行,我测试了序列化一个随机数组(使用pickle
和joblib
:
with open(str(path / "numpy.pkl"), "wb") as f:
pickle.dump(object, f, protocol=5)
with open(str(path / "numpy.joblib"), "wb") as f:
joblib.dump(object, f, compress=True)
这些实际上反序列化没有错误:
with open(str(path / "numpy.pkl"), "rb") as f:
read_object = pickle.load(f)
with open(str(path / "numpy.pkl"), "rb") as f:
read_object = joblib.load(f)
麻木源
如果我查看这一行numpy
的源代码,似乎只有在检索到的大小大于预期大小时才会引发错误。
其他一些(较旧的)stackoverflow 答案提到可以按如下方式使警告静音。但也没有帮助:
import warnings;
warnings.filterwarnings("ignore", message="numpy.dtype size changed");
warnings.filterwarnings("ignore", message="numpy.ufunc size changed");
尝试两次解决了它 我找到了解决这个问题的一种方法:在同一个 python 会话中,两次加载序列化模型。第一次引发错误,第二次没有。
然后,加载的模型会按预期运行。
怎么了?有没有办法让它第一次成功?