Pickle incompatibilidad de matrices numpy entre Python 2 y 3

163

Estoy tratando de cargar el conjunto de datos MNIST vinculado aquí en 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)

Lamentablemente, me da el error:

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)

Luego intenté decodificar el archivo en escabeche en Python 2.7 y volver a codificarlo. Entonces, ejecuté este programa en 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.

Se ejecutó sin error, así que volví a ejecutar este programa en 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)

Sin embargo, me dio el mismo error que antes. ¿Cómo hago para que esto funcione?


Este es un mejor enfoque para cargar el conjunto de datos MNIST.

Neil G
fuente
hay interrupciones de compatibilidad entre 2.7 y 3.x. especialmente cadena vs unicode. Y elegir un objeto numpy requiere que ambos sistemas carguen el módulo numpy pero esos módulos son diferentes. Lo siento, no tengo una respuesta, pero esto podría no ser factible y probablemente no sea aconsejable. Si esto es algo grande (gzip), ¿quizás hdf5 con pytables?
Phil Cooper
@PhilCooper: Gracias, tu comentario (¿publicar esto como respuesta?) Me dio la respuesta correcta. Podría haber usado hdf5, pero parecía complicado de aprender, así que elegí numpy.save/load y funcionó.
Neil G
h5py es muy simple de usar, casi con toda seguridad mucho más fácil que resolver problemas de compatibilidad nebulosos con decapado de matrices numpy.
DaveP
Dices que "ejecutaste este programa en Python 2.7". OK, pero ¿qué corriste bajo 3.2? :-) ¿Lo mismo?
Lennart Regebro
@LennartRegebro: Después de ejecutar el segundo programa que conserva las matrices, ejecuté el primer programa (sustituyendo el nombre de archivo mnistx.pkl.gz) en Python 3.2. No funcionó, lo que creo que ilustra algún tipo de incompatibilidad.
Neil G

Respuestas:

141

Esto parece una especie de incompatibilidad. Está intentando cargar un objeto "binstring", que se supone que es ASCII, mientras que en este caso son datos binarios. Si esto es un error en el desempañador de Python 3, o un "mal uso" del recolector por numpy, no lo sé.

Aquí hay una solución alternativa, pero no sé cuán significativos son los datos en este 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)

Desengancharlo en Python 2 y luego volver a engancharlo solo creará el mismo problema nuevamente, por lo que debe guardarlo en otro formato.

Lennart Regebro
fuente
211
Puede usar pickle.load(file_obj, encoding='latin1')(al menos en Python 3.3). Esto parece funcionar.
Tom Aldcroft
77
Para aquellos que usan una carga numpy y enfrentan un problema similar: también es posible pasar la codificación allí:np.load('./bvlc_alexnet.npy', encoding='latin1')
Serj Zaharchenko el
Esto funcionó para mí cuando la adición encoding='latin1'falló. ¡Gracias!
Guillem Cucurull
130

Si usted está recibiendo este error en python3, a continuación, podría ser un problema de incompatibilidad entre Python 2 y Python 3, para mí la solución era loadcon latin1la codificación:

pickle.load(file, encoding='latin1')
Tshilidzi Mudau
fuente
16

Parece ser un problema de incompatibilidad entre Python 2 y Python 3. Intenté cargar el conjunto de datos MNIST con

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

y funcionó para Python 3.5.2

Steve
fuente
7

Parece que hay algunos problemas de compatibilidad en pickle entre 2.xy 3.x debido al cambio a unicode. Su archivo parece estar en escabeche con python 2.xy decodificarlo en 3.x podría ser problemático.

Sugeriría deshabilitarlo con python 2.xy guardarlo en un formato que se reproduzca mejor en las dos versiones que está utilizando.

John Lyon
fuente
2
Eso es lo que estaba tratando de hacer. ¿Qué formato me recomiendan?
Neil G
55
Creo que el problema podría haber sido codificar numpy dtype, que podría ser una cadena. En cualquier caso, terminé usando numpy.save/load para cerrar la brecha entre python 2 y 3, y esto funcionó.
Neil G
7

Me topé con este fragmento. Espero que esto ayude a aclarar el problema de compatibilidad.

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)
sarga
fuente
Considere agregar más información amplificadora. ¿Cómo resuelve esto el problema?
Tom Aranda
@serge que ayudó, por favor, explicación a la respuesta
Sarath Sadasivan Pillai
6

Tratar:

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

De la documentación del pickle.loadmétodo:

Los argumentos opcionales de palabras clave son fix_imports, codificación y errores, que se utilizan para controlar el soporte de compatibilidad para el flujo de pickle generado por Python 2.

Si fix_imports es True, pickle intentará asignar los nombres antiguos de Python 2 a los nuevos nombres utilizados en Python 3.

La codificación y los errores le indican a pickle cómo decodificar instancias de cadenas de 8 bits seleccionadas por Python 2; estos predeterminados a 'ASCII' y 'estricto', respectivamente. La codificación puede ser 'bytes' para leer estas instancias de cadena de 8 bits como objetos de bytes.

Manish Kumbhare
fuente
0

Hay Hickle que es más rápido que encurtido y más fácil. Traté de guardarlo y leerlo en pickle dump, pero mientras leía hubo muchos problemas y desperdicié una hora y aún no encontré una solución, aunque estaba trabajando en mis propios datos para crear un chatbot.

vec_xy vec_yson matrices numpy:

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

Luego solo lo lees y realizas las operaciones:

data2 = hkl.load( 'new_data_file.hkl' )
KS HARSHA
fuente