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.

Neil G
fonte
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.

Lennart Regebro
fonte
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')
Tshilidzi Mudau
fonte
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

Steve
fonte
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.

John Lyon
fonte
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)
sarja
fonte
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.

Manish Kumbhare
fonte
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' )
KS HARSHA
fonte