Python 2和3之间numpy数组的pickle不兼容
Posted
技术标签:
【中文标题】Python 2和3之间numpy数组的pickle不兼容【英文标题】:Pickle incompatibility of numpy arrays between Python 2 and 3 【发布时间】:2012-07-03 13:58:57 【问题描述】:我正在尝试使用此程序在 Python 3.2 中加载链接 here 的 MNIST 数据集:
import pickle
import gzip
import numpy
with gzip.open('mnist.pkl.gz', 'rb') as f:
l = list(pickle.load(f))
print(l)
不幸的是,它给了我错误:
Traceback (most recent call last):
File "mnist.py", line 7, in <module>
train_set, valid_set, test_set = pickle.load(f)
UnicodeDecodeError: 'ascii' codec can't decode byte 0x90 in position 614: ordinal not in range(128)
然后我尝试在 Python 2.7 中解码腌制文件,然后重新编码。所以,我在 Python 2.7 中运行了这个程序:
import pickle
import gzip
import numpy
with gzip.open('mnist.pkl.gz', 'rb') as f:
train_set, valid_set, test_set = pickle.load(f)
# Printing out the three objects reveals that they are
# all pairs containing numpy arrays.
with gzip.open('mnistx.pkl.gz', 'wb') as g:
pickle.dump(
(train_set, valid_set, test_set),
g,
protocol=2) # I also tried protocol 0.
它运行没有错误,所以我在 Python 3.2 中重新运行了这个程序:
import pickle
import gzip
import numpy
# note the filename change
with gzip.open('mnistx.pkl.gz', 'rb') as f:
l = list(pickle.load(f))
print(l)
但是,它给了我和以前一样的错误。我该如何让它发挥作用?
This is a better approach for loading the MNIST dataset.
【问题讨论】:
2.7 和 3.x 之间存在兼容性中断。特别是字符串与 unicode。并且选择一个 numpy 对象需要两个系统都加载 numpy 模块,但这些模块是不同的。抱歉,我没有答案,但这可能是不可行的,也可能是不可取的。如果这是大事(gzip),也许 hdf5 和 pytables?? @PhilCooper:谢谢,您的评论(将其作为答案发布?)让我找到了正确的答案。我本可以使用 hdf5,但学习起来似乎很复杂,所以我使用了 numpy.save/load 并且这很有效。 h5py 使用起来非常简单,几乎可以肯定比使用酸洗 numpy 数组解决模糊的兼容性问题要容易得多。 你说你“在 Python 2.7 下运行这个程序”。好的,但是你在 3.2 下运行了什么? :-) 一样吗? @LennartRegebro:在运行第二个处理数组的程序后,我在 Python 3.2 中运行了第一个程序(替换文件名 mnistx.pkl.gz)。它不起作用,我认为这说明了某种不兼容。 【参考方案1】:这似乎是某种不兼容。它试图加载一个“binstring”对象,该对象被假定为 ASCII,而在这种情况下它是二进制数据。如果这是 Python 3 unpickler 中的错误,或者是 numpy 对pickler 的“滥用”,我不知道。
这是一种解决方法,但我不知道此时数据有多大意义:
import pickle
import gzip
import numpy
with open('mnist.pkl', 'rb') as f:
u = pickle._Unpickler(f)
u.encoding = 'latin1'
p = u.load()
print(p)
在 Python 2 中取消腌制然后重新腌制只会再次产生相同的问题,因此您需要将其保存为另一种格式。
【讨论】:
你可以使用pickle.load(file_obj, encoding='latin1')
(至少在 Python 3.3 中)。这似乎有效。
对于那些使用 numpy load 并面临类似问题的人:也可以在那里传递编码:np.load('./bvlc_alexnet.npy', encoding='latin1')
添加 encoding='latin1'
失败时,这对我有用。谢谢!
就我而言,只有pickle.load(open(file_path, "rb"), encoding="latin1")
有效。【参考方案2】:
如果您在 python3 中遇到此错误,则可能是 python 2 和 python 3 之间的不兼容问题,对我来说,解决方案是 load
和 latin1
编码:
pickle.load(file, encoding='latin1')
【讨论】:
【参考方案3】:这似乎是 Python 2 和 Python 3 之间的不兼容问题。我尝试用
加载 MNIST 数据集 train_set, valid_set, test_set = pickle.load(file, encoding='iso-8859-1')
它适用于 Python 3.5.2
【讨论】:
【参考方案4】:由于迁移到 unicode,在 2.x 和 3.x 之间的 pickle 中看起来像 there are some compatablility issues。你的文件似乎是用 python 2.x 腌制的,在 3.x 中解码它可能很麻烦。
我建议用 python 2.x 解开它并保存为在您使用的两个版本中播放得更好的格式。
【讨论】:
这就是我想要做的。您推荐哪种格式? 我认为问题可能是编码 numpy dtype,它可能是一个字符串。无论如何,我最终使用 numpy.save/load 来弥补 python 2 和 3 之间的差距,这很有效。【参考方案5】:我只是偶然发现了这个 sn-p。希望这有助于澄清兼容性问题。
import sys
with gzip.open('mnist.pkl.gz', 'rb') as f:
if sys.version_info.major > 2:
train_set, valid_set, test_set = pickle.load(f, encoding='latin1')
else:
train_set, valid_set, test_set = pickle.load(f)
【讨论】:
考虑添加更多放大信息。这如何解决问题? @serge 有帮助,请解释答案【参考方案6】:试试:
l = list(pickle.load(f, encoding='bytes')) #if you are loading image data or
l = list(pickle.load(f, encoding='latin1')) #if you are loading text data
来自pickle.load
方法的文档:
可选的关键字参数是fix_imports、encoding和errors,用于控制对Python 2生成的pickle流的兼容性支持。
如果 fix_imports 为 True,pickle 将尝试将旧的 Python 2 名称映射到 Python 3 中使用的新名称。
编码和错误告诉 pickle 如何解码 Python 2 腌制的 8 位字符串实例;这些默认分别为“ASCII”和“严格”。编码可以是“字节”,以将这些 8 位字符串实例读取为字节对象。
【讨论】:
【参考方案7】:hickle 比 pickle 更快更容易。 我试图在泡菜转储中保存和阅读它,但是在阅读时出现了很多问题并浪费了一个小时,尽管我正在处理自己的数据以创建聊天机器人,但仍然没有找到解决方案。
vec_x
和 vec_y
是 numpy 数组:
data=[vec_x,vec_y]
hkl.dump( data, 'new_data_file.hkl' )
然后你只需阅读它并执行操作:
data2 = hkl.load( 'new_data_file.hkl' )
【讨论】:
以上是关于Python 2和3之间numpy数组的pickle不兼容的主要内容,如果未能解决你的问题,请参考以下文章
python数据分析 python numpy--数组--运算,切片和索引