Niezgodność Pickle tablic numpy między Pythonem 2 i 3


163

Próbuję załadować zestaw danych MNIST połączony tutaj w Pythonie 3.2 za pomocą tego programu:

import pickle
import gzip
import numpy


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

Niestety daje mi błąd:

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)

Następnie próbowałem zdekodować piklowany plik w Pythonie 2.7 i ponownie go zakodować. Uruchomiłem więc ten program w Pythonie 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.

Działał bez błędów, więc ponownie uruchomiłem ten program w Pythonie 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)

Jednak dało mi to ten sam błąd co poprzednio. Jak sprawić, by to zadziałało?


Jest to lepsze podejście do ładowania zestawu danych MNIST.


istnieją przerwy w kompatybilności między 2.7 a 3.x. zwłaszcza string vs Unicode. A wybranie obiektu numpy wymaga, aby oba systemy załadowały moduł numpy, ale te moduły są różne. Przepraszam, nie mam odpowiedzi, ale może to nie być możliwe i prawdopodobnie nie jest zalecane. Jeśli to są duże rzeczy (gzip), może hdf5 z pytables?
Phil Cooper,

@PhilCooper: Dziękuję, Twój komentarz (zamieść to jako odpowiedź?) Wskazał mi właściwą odpowiedź. Mogłem użyć hdf5, ale nauczenie się tego wydawało się skomplikowane, więc poszedłem z numpy.save/load i to zadziałało.
Neil G,

h5py jest bardzo prosty w użyciu, prawie na pewno o wiele łatwiejszy niż rozwiązywanie mglistych problemów ze zgodnością z wytrawianiem tablic numpy.
DaveP,

Mówisz, że „uruchomiłeś ten program pod Pythonem 2.7”. OK, ale co uruchomiłeś pod 3.2? :-) To samo?
Lennart Regebro

@LennartRegebro: Po uruchomieniu drugiego programu, który trawi tablice, uruchomiłem pierwszy program (zastępując nazwę pliku mnistx.pkl.gz) w Pythonie 3.2. To nie zadziałało, co, jak sądzę, ilustruje pewien rodzaj niezgodności.
Neil G

Odpowiedzi:


141

Wydaje się, że jest to jakaś niezgodność. Próbuje załadować obiekt „binstring”, który zakłada, że ​​jest to ASCII, podczas gdy w tym przypadku są to dane binarne. Jeśli jest to błąd w Unpicklerze Pythona 3, czy też „niewłaściwe użycie” tego narzędzia przez numpy, to nie wiem.

Oto coś w rodzaju obejścia, ale nie wiem, jak znaczące są dane w tym momencie:

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)

Rozpakowanie go w Pythonie 2, a następnie ponowne wybranie spowoduje tylko ten sam problem, więc musisz zapisać go w innym formacie.


211
Możesz użyć pickle.load(file_obj, encoding='latin1')(przynajmniej w Pythonie 3.3). To wydaje się działać.
Tom Aldcroft,

7
Dla tych, którzy używają numpy load i borykają się z podobnym problemem: można tam również przekazać kodowanie:np.load('./bvlc_alexnet.npy', encoding='latin1')
Serj Zaharchenko

To zadziałało, gdy dodawanie encoding='latin1'nie powiodło się. Dzięki!
Guillem Cucurull

130

Jeśli otrzymujesz ten błąd w python3, to może to być problem niezgodności między Python 2 i Python 3, dla mnie rozwiązaniem było loadz latin1kodowaniem:

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

16

Wydaje się, że jest to problem z niekompatybilnością między Pythonem 2 i Pythonem 3. Próbowałem załadować zestaw danych MNIST za pomocą

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

i działało dla Pythona 3.5.2


7

Wygląda na to, że istnieją pewne problemy z kompatybilnością w pikle między 2.x a 3.x z powodu przejścia na Unicode. Twój plik wygląda na wytrawiony w Pythonie 2.xi dekodowanie go w 3.x może być kłopotliwe.

Sugerowałbym rozpakowanie go za pomocą Pythona 2.xi zapisanie w formacie, który gra ładniej w dwóch wersjach, których używasz.


2
To właśnie próbowałem zrobić. Który format polecacie?
Neil G,

5
Myślę, że problem mógł polegać na kodowaniu numpy dtype, który może być ciągiem. W każdym razie skończyło się na użyciu numpy.save/load, aby wypełnić lukę między Pythonem 2 i 3 i to zadziałało.
Neil G,

7

Właśnie natknąłem się na ten fragment. Mam nadzieję, że pomoże to wyjaśnić problem ze zgodnością.

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)

Zastanów się nad dodaniem większej ilości informacji. Jak to rozwiązuje problem?
Tom Aranda

@serge, które pomogło, proszę wyjaśnić odpowiedź
Sarath Sadasivan Pillai

6

Próbować:

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

Z dokumentacji pickle.loadmetody:

Opcjonalne argumenty słów kluczowych to fix_imports, kodowanie i błędy, które są używane do kontrolowania obsługi zgodności dla strumienia pikle generowanego przez Python 2.

Jeśli fix_imports ma wartość True, pickle spróbuje zmapować stare nazwy Pythona 2 na nowe nazwy używane w Pythonie 3.

Kodowanie i błędy mówią pickle, jak dekodować 8-bitowe instancje ciągów marynowane przez Python 2; te domyślne to odpowiednio „ASCII” i „ścisłe”. Kodowanie może mieć wartość „bajtów”, aby odczytać te 8-bitowe instancje ciągów jako obiekty bajtów.


0

Jest hickle, która jest szybsza niż marynata i łatwiejsza. Próbowałem go zapisać i przeczytać w zrzucie pikli, ale podczas czytania było dużo problemów i zmarnowałem godzinę i nadal nie znalazłem rozwiązania, chociaż pracowałem na własnych danych, aby stworzyć chatbota.

vec_xi vec_ysą tablicami numpy:

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

Następnie po prostu go przeczytaj i wykonaj operacje:

data2 = hkl.load( 'new_data_file.hkl' )
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.