Incompatibilité Pickle des tableaux numpy entre Python 2 et 3

163

J'essaie de charger l'ensemble de données MNIST lié ici dans Python 3.2 en utilisant ce programme:

import pickle
import gzip
import numpy


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

Malheureusement, cela me donne l'erreur:

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)

J'ai ensuite essayé de décoder le fichier mariné en Python 2.7 et de le ré-encoder. Donc, j'ai exécuté ce programme 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.

Il a fonctionné sans erreur, j'ai donc relancé ce programme 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)

Cependant, cela m'a donné la même erreur qu'avant. Comment faire fonctionner cela?


C'est une meilleure approche pour charger l'ensemble de données MNIST.

Neil G
la source
il y a des coupures de compatibilité entre 2.7 et 3.x. en particulier string vs unicode. Et choisir un objet numpy nécessite que les deux systèmes chargent le module numpy mais ces modules sont différents. Désolé, je n'ai pas de réponse mais cela n'est peut-être pas faisable et n'est probablement pas conseillé. Si ce sont de grandes choses (gzip), peut-être hdf5 avec pytables ??
Phil Cooper
@PhilCooper: Merci, votre commentaire (poster ceci comme réponse?) M'a donné la bonne réponse. J'aurais pu utiliser hdf5, mais cela semblait compliqué à apprendre, alors j'ai opté pour numpy.save/load et cela a fonctionné.
Neil G
h5py est très simple à utiliser, presque certainement beaucoup plus facile que de résoudre les problèmes de compatibilité nébuleux avec le décapage de tableaux numpy.
DaveP
Vous dites que vous "avez exécuté ce programme sous Python 2.7". OK mais qu'avez-vous exécuté sous 3.2? :-) Le même?
Lennart Regebro
@LennartRegebro: Après avoir exécuté le deuxième programme qui pickles les tableaux, j'ai exécuté le premier programme (en remplaçant le nom de fichier mnistx.pkl.gz) dans Python 3.2. Cela n'a pas fonctionné, ce qui, je pense, illustre une sorte d'incompatibilité.
Neil G

Réponses:

141

Cela semble être une sorte d'incompatibilité. Il essaie de charger un objet "binstring", qui est supposé être ASCII, alors que dans ce cas il s'agit de données binaires. S'il s'agit d'un bug dans le dépickler Python 3, ou d'une "mauvaise utilisation" du pickler par numpy, je ne sais pas.

Voici une solution de contournement, mais je ne sais pas à quel point les données sont significatives à ce stade:

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)

Le décoller dans Python 2, puis le repiquer ne fera que créer à nouveau le même problème, vous devez donc l'enregistrer dans un autre format.

Lennart Regebro
la source
211
Vous pouvez utiliser pickle.load(file_obj, encoding='latin1')(au moins en Python 3.3). Cela semble fonctionner.
Tom Aldcroft
7
Pour ceux qui utilisent numpy load et sont confrontés au même problème: il est également possible d'y passer l'encodage:np.load('./bvlc_alexnet.npy', encoding='latin1')
Serj Zaharchenko
Cela a fonctionné pour moi lorsque l'ajout a encoding='latin1'échoué. Merci!
Guillem Cucurull
130

Si vous obtenez cette erreur dans python3, alors, il pourrait être un problème d'incompatibilité entre python 2 et Python 3, pour moi , la solution a consisté à loadavec le latin1codage:

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

Cela semble être un problème d'incompatibilité entre Python 2 et Python 3. J'ai essayé de charger le jeu de données MNIST avec

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

et cela a fonctionné pour Python 3.5.2

Steve
la source
7

Il semble qu'il y ait des problèmes de compatibilité dans pickle entre 2.x et 3.x en raison du passage à l'unicode. Votre fichier semble être décapé avec python 2.x et le décoder en 3.x pourrait être gênant.

Je suggérerais de le décoller avec python 2.x et de l'enregistrer dans un format qui joue plus bien dans les deux versions que vous utilisez.

John Lyon
la source
2
C'est ce que j'essayais de faire. Quel format recommandez-vous?
Neil G
5
Je pense que le problème a pu être l'encodage de dtype numpy, qui pourrait être une chaîne. Dans tous les cas, j'ai fini par utiliser numpy.save/load pour combler le fossé entre python 2 et 3, et cela a fonctionné.
Neil G
7

Je viens de tomber sur cet extrait. J'espère que cela aidera à clarifier le problème de compatibilité.

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
la source
Pensez à ajouter des informations supplémentaires. Comment cela résout-il le problème?
Tom Aranda
@serge qui a aidé, veuillez expliquer la réponse
Sarath Sadasivan Pillai
6

Essayer:

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 documentation de la pickle.loadméthode:

Les arguments de mot-clé facultatifs sont fix_imports, encoding et errors, qui sont utilisés pour contrôler la compatibilité avec le flux pickle généré par Python 2.

Si fix_imports vaut True, pickle essaiera de mapper les anciens noms Python 2 avec les nouveaux noms utilisés dans Python 3.

L'encodage et les erreurs indiquent à Pickle comment décoder les instances de chaîne 8 bits picklées par Python 2; ceux-ci par défaut sont respectivement «ASCII» et «strict». Le codage peut être des «octets» pour lire ces instances de chaîne de 8 bits en tant qu'objets octets.

Manish Kumbhare
la source
0

Il y a de l'hickle qui est plus rapide que le cornichon et plus facile. J'ai essayé de le sauvegarder et de le lire dans pickle dump, mais en lisant, il y avait beaucoup de problèmes et j'ai perdu une heure et je n'ai toujours pas trouvé de solution bien que je travaillais sur mes propres données pour créer un chatbot.

vec_xet vec_ysont des tableaux numpy:

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

Ensuite, vous venez de le lire et d'effectuer les opérations:

data2 = hkl.load( 'new_data_file.hkl' )
KS HARSHA
la source