Pickle-Inkompatibilität von Numpy-Arrays zwischen Python 2 und 3

163

Ich versuche, das hier in Python 3.2 verlinkte MNIST-Dataset mit diesem Programm zu laden :

import pickle
import gzip
import numpy


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

Leider gibt es mir den Fehler:

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)

Ich habe dann versucht, die eingelegte Datei in Python 2.7 zu dekodieren und neu zu kodieren. Also habe ich dieses Programm in Python 2.7 ausgeführt:

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.

Es lief ohne Fehler, also habe ich dieses Programm in Python 3.2 erneut ausgeführt:

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)

Es gab mir jedoch den gleichen Fehler wie zuvor. Wie bringe ich das zum Laufen?


Dies ist ein besserer Ansatz zum Laden des MNIST-Datasets.

Neil G.
quelle
Es gibt Kompatibilitätsbrüche zwischen 2.7 und 3.x. vor allem String vs Unicode. Für die Auswahl eines Numpy-Objekts müssen beide Systeme das Numpy-Modul laden, diese Module sind jedoch unterschiedlich. Entschuldigung, ich habe keine Antwort, aber dies ist möglicherweise nicht machbar und wahrscheinlich nicht ratsam. Wenn das große Dinge sind (gzip), vielleicht hdf5 mit pytables ??
Phil Cooper
@PhilCooper: Danke, Ihr Kommentar (als Antwort posten?) Hat mich auf die richtige Antwort aufmerksam gemacht. Ich hätte hdf5 verwenden können, aber es schien kompliziert zu lernen, also habe ich mich für numpy.save/load entschieden und das hat funktioniert.
Neil G
h5py ist sehr einfach zu bedienen, mit ziemlicher Sicherheit viel einfacher als das Lösen nebulöser Kompatibilitätsprobleme mit dem Beizen von Numpy-Arrays.
DaveP
Sie sagen, Sie haben "dieses Programm unter Python 2.7 ausgeführt". OK, aber was hast du unter 3.2 gemacht? :-) Das Gleiche?
Lennart Regebro
@LennartRegebro: Nachdem ich das zweite Programm ausgeführt habe, das die Arrays auswählt, habe ich das erste Programm (anstelle des Dateinamens mnistx.pkl.gz) in Python 3.2 ausgeführt. Es hat nicht funktioniert, was meiner Meinung nach eine Art Inkompatibilität darstellt.
Neil G

Antworten:

141

Dies scheint eine Art Inkompatibilität zu sein. Es wird versucht, ein "binstring" -Objekt zu laden, von dem angenommen wird, dass es ASCII ist, während es sich in diesem Fall um Binärdaten handelt. Ob dies ein Fehler im Python 3-Unpickler oder ein "Missbrauch" des Picklers durch Numpy ist, weiß ich nicht.

Hier ist eine Art Problemumgehung, aber ich weiß nicht, wie aussagekräftig die Daten zu diesem Zeitpunkt sind:

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)

Wenn Sie es in Python 2 entfernen und dann erneut auswählen, wird das gleiche Problem nur erneut auftreten. Sie müssen es also in einem anderen Format speichern.

Lennart Regebro
quelle
210
Sie können verwenden pickle.load(file_obj, encoding='latin1')(zumindest in Python 3.3). Das scheint zu funktionieren.
Tom Aldcroft
7
Für diejenigen, die Numpy Load verwenden und mit einem ähnlichen Problem konfrontiert sind: Es ist auch möglich, die Codierung dort zu übergeben:np.load('./bvlc_alexnet.npy', encoding='latin1')
Serj Zaharchenko
Dies funktionierte bei mir, als das Hinzufügen encoding='latin1'fehlschlug. Vielen Dank!
Guillem Cucurull
130

Wenn Sie diesen Fehler in python3 bekommen, dann könnte es ein Kompatibilitätsproblem zwischen Python 2 und Python 3, für mich war die Lösung loadmit latin1kodiert:

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

Es scheint ein Inkompatibilitätsproblem zwischen Python 2 und Python 3 zu sein. Ich habe versucht, das MNIST-Dataset mit zu laden

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

und es funktionierte für Python 3.5.2

Steve
quelle
7

Es sieht so aus, als ob es aufgrund der Umstellung auf Unicode einige Kompatibilitätsprobleme bei Pickle zwischen 2.x und 3.x gibt. Ihre Datei scheint mit Python 2.x eingelegt zu sein, und das Dekodieren in 3.x kann problematisch sein.

Ich würde vorschlagen, es mit Python 2.x zu entfernen und in einem Format zu speichern, das für die beiden von Ihnen verwendeten Versionen besser geeignet ist.

John Lyon
quelle
2
Das habe ich versucht. Welches Format empfehlen Sie?
Neil G
5
Ich denke, das Problem könnte darin bestanden haben, numpy dtype zu codieren, was eine Zeichenfolge sein könnte. Auf jeden Fall habe ich numpy.save/load verwendet, um die Lücke zwischen Python 2 und 3 zu schließen, und das hat funktioniert.
Neil G
7

Ich bin gerade auf diesen Ausschnitt gestoßen. Ich hoffe, dies hilft, das Kompatibilitätsproblem zu klären.

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
quelle
Erwägen Sie, weitere Informationen hinzuzufügen. Wie löst dies das Problem?
Tom Aranda
@serge das hat geholfen, bitte Erklärung zur Antwort
Sarath Sadasivan Pillai
6

Versuchen:

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

Aus der Dokumentation der pickle.loadMethode:

Optionale Schlüsselwortargumente sind fix_imports, Codierung und Fehler, mit denen die Kompatibilitätsunterstützung für den von Python 2 generierten Pickle-Stream gesteuert wird.

Wenn fix_imports True ist, versucht pickle, die alten Python 2-Namen den neuen Namen zuzuordnen, die in Python 3 verwendet werden.

Die Codierung und die Fehler zeigen pickle an, wie von Python 2 ausgewählte 8-Bit-String-Instanzen decodiert werden sollen. Diese sind standardmäßig 'ASCII' bzw. 'strict'. Die Codierung kann 'Bytes' sein, um diese 8-Bit-String-Instanzen als Bytes-Objekte zu lesen.

Manish Kumbhare
quelle
0

Es gibt Hickle, das schneller als Pickle und einfacher ist. Ich habe versucht, es in Pickle Dump zu speichern und zu lesen, aber beim Lesen gab es viele Probleme und ich habe eine Stunde verschwendet und immer noch keine Lösung gefunden, obwohl ich an meinen eigenen Daten gearbeitet habe, um einen Chatbot zu erstellen.

vec_xund vec_ysind numpy Arrays:

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

Dann lesen Sie es einfach und führen die Operationen aus:

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