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

Nei*_*l G 147 python pickle python-3.x

我试图加载链接的MNIST数据集在这里使用该程序在Python 3.2:

import pickle
import gzip
import numpy


with gzip.open('mnist.pkl.gz', 'rb') as f:
    l = list(pickle.load(f))
    print(l)
Run Code Online (Sandbox Code Playgroud)

不幸的是,它给了我错误:

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)
Run Code Online (Sandbox Code Playgroud)

然后我尝试在Python 2.7中解码pickle文件,并重新编码.所以,我在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.
Run Code Online (Sandbox Code Playgroud)

它运行没有错误,所以我在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)
Run Code Online (Sandbox Code Playgroud)

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


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

Len*_*bro 127

这似乎是某种不兼容性.它试图加载一个"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)
Run Code Online (Sandbox Code Playgroud)

在Python 2中取消它然后重新排序它只会再次产生同样的问题,所以你需要以另一种格式保存它.

  • 你可以使用`pickle.load(file_obj,encoding ='latin1')`(至少在Python 3.3中).这个_seems_工作. (199认同)
  • 对于那些使用numpy加载并面临类似问题的人:也可以在那里传递编码:`np.load('./ bvlc_alexnet.npy',encoding ='latin1')` (7认同)

Tsh*_*dau 107

如果你在python3中遇到这个错误,那么,它可能是python 2和python 3之间的不兼容问题,对我来说解决方案是load使用lattin1编码:

pickle.load(file, encoding='latin1')
Run Code Online (Sandbox Code Playgroud)


小智 10

它似乎是Python 2和Python 3之间的不兼容问题.我尝试加载MNIST数据集

    train_set, valid_set, test_set = pickle.load(file, encoding='iso-8859-1')
Run Code Online (Sandbox Code Playgroud)

它适用于Python 3.5.2


Joh*_*yon 7

由于转向unicode ,看起来在2.x和3.x之间的pickle中存在一些兼容性问题.您的文件似乎使用python 2.x进行pickle并在3.x中解码可能会很麻烦.

我建议用python 2.x解开它并保存到一个格式,在你正在使用的两个版本中播放得更好.

  • 我认为问题可能是编码numpy dtype,它可能是一个字符串.无论如何,我最终使用numpy.save/load来弥合python 2和3之间的差距,这很有效. (5认同)
  • 这就是我试图做的。你推荐哪种格式? (2认同)

小智 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)
Run Code Online (Sandbox Code Playgroud)


Man*_*are 7

尝试:

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
Run Code Online (Sandbox Code Playgroud)

pickle.load方法的文档中:

可选的关键字参数是 fix_imports、encoding 和 errors,用于控制对 Python 2 生成的 pickle 流的兼容性支持。

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

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