Incompatibilidade de pickle de matrizes numpy entre Python 2 e 3


163

Estou tentando carregar o conjunto de dados MNIST vinculado aqui no Python 3.2 usando este programa:

import pickle
import gzip
import numpy


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

Infelizmente, isso me dá o erro:

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)

Tentei decodificar o arquivo em conserva no Python 2.7 e recodificá-lo. Então, eu executei este programa no 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.

Ele foi executado sem erros, então eu executei novamente este programa no 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)

No entanto, ele me deu o mesmo erro de antes. Como faço para que isso funcione?


Essa é uma abordagem melhor para carregar o conjunto de dados MNIST.


há quebras de compatibilidade entre 2,7 e 3.x. especialmente string vs unicode. E escolher um objeto numpy requer que os dois sistemas carreguem o módulo numpy, mas esses módulos são diferentes. Desculpe, não tenho uma resposta, mas isso pode não ser possível e provavelmente não é aconselhável. Se isso são coisas grandes (gzip), talvez hdf5 com pytables ??
— Phil Cooper

@ PhilCooper: Obrigado, seu comentário (poste isso como resposta?) Me deu uma dica para a resposta certa. Eu poderia ter usado o hdf5, mas parecia complicado aprender, então segui com numpy.save/load e funcionou.
— Neil G

O h5py é muito simples de usar, quase certamente muito mais fácil do que solucionar problemas de compatibilidade nebulosos com arrays numpy em excesso.
— DaveP

Você diz que "executou este programa no Python 2.7". OK, mas o que você executou em 3.2? :-) O mesmo?
— Lennart Regebro 03/07

@LennartRegebro: Depois de executar o segundo programa que seleciona as matrizes, executei o primeiro programa (substituindo o nome do arquivo mnistx.pkl.gz) no Python 3.2. Não funcionou, o que acho que ilustra algum tipo de incompatibilidade.
— Neil G

Respostas:


141

Isso parece algum tipo de incompatibilidade. Ele está tentando carregar um objeto "binstring", que é assumido como ASCII, enquanto neste caso são dados binários. Se isso é um bug no desenrolador de Python 3 ou um "uso indevido" do seletor por numpy, não sei.

Aqui está uma solução alternativa, mas não sei até que ponto os dados são significativos neste momento:

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)

Retirar a seleção no Python 2 e, em seguida, selecionar novamente, criará o mesmo problema novamente, portanto, você deve salvá-lo em outro formato.


211
Você pode usar pickle.load(file_obj, encoding='latin1')(pelo menos no Python 3.3). Isso parece funcionar.
— precisa saber é o seguinte

7
Para quem está usando carga numpy e enfrentando o problema semelhante: é possível passar codificação lá também:np.load('./bvlc_alexnet.npy', encoding='latin1')
— Serj Zaharchenko

Isso funcionou para mim ao adicionar encoding='latin1'falha. Obrigado!
— Guillem Cucurull

130

Se você está recebendo esse erro no python3, pode ser um problema de incompatibilidade entre o python 2 e o python 3; para mim, a solução foi loadcom a latin1codificação:

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

16

Parece ser um problema de incompatibilidade entre o Python 2 e o Python 3. Tentei carregar o conjunto de dados MNIST com

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

e funcionou para o Python 3.5.2


7

Parece que existem alguns problemas de compatibilidade no pickle entre 2.xe 3.x devido à mudança para o unicode. Seu arquivo parece ter sido modificado com o python 2.xe decodificá-lo no 3.x pode ser problemático.

Eu sugiro desmarcá-lo com python 2.xe salvar em um formato que seja mais bem reproduzido nas duas versões que você está usando.


2
Era o que eu estava tentando fazer. Qual formato você recomenda?
— Neil G

5
Eu acho que o problema pode ter sido codificação numpy dtype, que pode ser uma string. De qualquer forma, acabei usando numpy.save/load para fazer a ponte entre o python 2 e 3, e isso funcionou.
— Neil G

7

Eu apenas tropecei neste trecho. Espero que isso ajude a esclarecer o problema de compatibilidade.

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)

Considere adicionar mais informações amplificadoras. Como isso resolve o problema?
— Tom Aranda

@serge que ajudou, por favor, explique a resposta #
— Sarath Sadasivan Pillai

6

Experimentar:

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

A partir da documentação do pickle.loadmétodo:

Os argumentos opcionais da palavra-chave são fix_imports, codificação e erros, que são usados ​​para controlar o suporte de compatibilidade para o pickle stream gerado pelo Python 2.

Se fix_imports for True, pickle tentará mapear os nomes antigos do Python 2 para os novos nomes usados ​​no Python 3.

A codificação e os erros dizem ao pickle como decodificar instâncias de string de 8 bits selecionadas pelo Python 2; esses padrões são 'ASCII' e 'strict', respectivamente. A codificação pode ser 'bytes' para ler essas instâncias de cadeia de 8 bits como objetos de bytes.


0

Há hickle que é mais rápido que pickle e mais fácil. Tentei salvar e ler no pickle dump, mas durante a leitura houve muitos problemas e perdi uma hora e ainda não encontrei uma solução, embora eu estivesse trabalhando nos meus próprios dados para criar um chatbot.

vec_xe vec_ysão matrizes numpy:

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

Então você acabou de ler e executar as operações:

data2 = hkl.load( 'new_data_file.hkl' )
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.