Python 2和3之间的numpy数组的Pickle不兼容


163

我正在尝试使用此程序加载在Python 3.2中链接到此处的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)

但是,它给了我与以前相同的错误。我该如何工作?


这是加载MNIST数据集的更好方法。


在2.7和3.x之间存在兼容性中断。特别是字符串与unicode。选择一个numpy对象需要两个系统都加载numpy模块,但是这些模块是不同的。抱歉,我没有答案,但这可能不可行,可能不明智。如果这是大事(gzip),也许是带有pytables的hdf5?
菲尔·库珀

@PhilCooper:谢谢,您的评论(将其发布为答案?)使我成为正确的答案。我本可以使用hdf5,但学习起来似乎很复杂,因此我使用了numpy.save/load并成功了。
Neil G'7

h5py的使用非常简单,几乎可以肯定比用酸洗numpy数组解决含糊的兼容性问题要容易得多。
DaveP

您说您“在Python 2.7下运行了该程序”。好的,但是您在3.2下运行了什么?:-) 相同?
Lennart Regebro

@LennartRegebro:运行第二个对数组进行腌制的程序后,我在Python 3.2中运行了第一个程序(用文件名mnistx.pkl.gz代替)。它没有用,我认为这说明了某种不兼容性。
尼尔·G

Answers:


141

这似乎有点不兼容。它正在尝试加载一个假定为ASCII的“ binstring”对象,而在这种情况下,它是二进制数据。如果这是Python 3取消选取器中的错误,还是numpy对选取器的“滥用”,我不知道。

这是一种解决方法,但是我不知道此时数据的意义如何:

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中取消选择它,然后重新选择它只会再次导致相同的问题,因此您需要将其另存为另一种格式。


210
您可以使用pickle.load(file_obj, encoding='latin1')(至少在Python 3.3中)。这似乎有效。
Tom Aldcroft 2014年

7
对于那些使用numpy加载并面临类似问题的用户:也可以在那里传递编码:np.load('./bvlc_alexnet.npy', encoding='latin1')
Serj Zaharchenko

添加encoding='latin1'失败时,这对我有用。谢谢!
Guillem Cucurull

130

如果您在python3中遇到此错误,则可能是python 2和python 3之间的不兼容问题,对我来说,解决方案是load使用latin1编码:

pickle.load(file, encoding='latin1')

16

它似乎是Python 2和Python 3之间的不兼容问题。我尝试使用以下命令加载MNIST数据集:

    train_set, valid_set, test_set = pickle.load(file, encoding='iso-8859-1')

它适用于Python 3.5.2


7

由于迁移到unicode ,似乎在2.x和3.x之间的泡菜中存在一些兼容性问题。您的文件似乎已被python 2.x腌制,并且在3.x中对其进行解码可能很麻烦。

我建议用python 2.x将其解开,并保存为一种在您使用的两个版本中都能更好地播放的格式。


2
那就是我想做的。您推荐哪种格式?
Neil G

5
我认为问题可能在于编码numpy dtype,它可能是字符串。无论如何,我最终都使用了numpy.save/load来弥合python 2和3之间的鸿沟,并且这行得通。
Neil

7

我只是偶然发现了这个片段。希望这有助于澄清兼容性问题。

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有帮助,请解释答案
Sarath Sadasivan Pillai

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,编码和错误,用于控制对Python 2生成的pickle流的兼容性支持。

如果fix_imports为True,则pickle将尝试将旧的Python 2名称映射到Python 3中使用的新名称。

编码和错误告诉pickle如何解码Python 2腌制的8位字符串实例;它们分别默认为“ ASCII”和“ strict”。编码可以是“字节”,以将这些8位字符串实例读取为字节对象。


0

有一个比泡菜快和容易的hi。我试图保存并在泡菜转储中阅读它,但是在阅读时有很多问题,浪费了一个小时,尽管我正在处理自己的数据以创建聊天机器人,但仍然找不到解决方案。

vec_x并且vec_y是numpy数组:

data=[vec_x,vec_y]
hkl.dump( data, 'new_data_file.hkl' )

然后,您只需阅读并执行以下操作:

data2 = hkl.load( 'new_data_file.hkl' )
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.