Рассол несовместимость массивов между Python 2 и 3

163

Я пытаюсь загрузить набор данных MNIST, связанный здесь в Python 3.2, с помощью этой программы:

import pickle
import gzip
import numpy


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

К сожалению, это дает мне ошибку:

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)

Затем я попытался декодировать маринованный файл в Python 2.7 и перекодировать его. Итак, я запустил эту программу в 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.

Он работал без ошибок, поэтому я перезапустил эту программу в 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)

Однако, это дало мне ту же ошибку, что и раньше. Как мне заставить это работать?


Это лучший подход для загрузки набора данных MNIST.

Нил Г
источник
между 2.7 и 3.x есть разрывы совместимости. особенно строка против юникода. И выбор numy-объекта требует, чтобы обе системы загружали numpy-модуль, но эти модули разные. Извините, у меня нет ответа, но это не может быть выполнимо и, вероятно, не рекомендуется. Если это большие вещи (gzip), может быть, hdf5 с pytables ??
Фил Купер
@PhilCooper: Спасибо, ваш комментарий (опубликовать это как ответ?) Подсказал мне правильный ответ. Я мог бы использовать hdf5, но это казалось сложным для изучения, поэтому я выбрал numpy.save/load, и это сработало.
Нил Дж
h5py очень прост в использовании, почти наверняка намного проще, чем решение проблем с туманной совместимостью с помощью травления массивов.
DaveP
Вы говорите, что «запускали эту программу под Python 2.7». Хорошо, но что вы запускали под 3.2? :-) Такой же?
Леннарт Регебро
@LennartRegebro: После запуска второй программы, которая выбирает массивы, я запустил первую программу (подставив имя файла mnistx.pkl.gz) в Python 3.2. Это не сработало, что, я думаю, иллюстрирует некоторую несовместимость.
Нил Дж

Ответы:

141

Это похоже на какую-то несовместимость. Он пытается загрузить объект «binstring», который считается ASCII, в то время как в этом случае это двоичные данные. Если это ошибка в сборщике Python 3 или «неправильное использование» сборщиком по numpy, я не знаю.

Вот что-то вроде обходного пути, но я не знаю, насколько значимы данные на данном этапе:

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)

Отключение его в Python 2 и последующее повторное его создание создадут ту же проблему, поэтому вам нужно сохранить ее в другом формате.

Леннарт Регебро
источник
211
Вы можете использовать pickle.load(file_obj, encoding='latin1')(по крайней мере, в Python 3.3). Это похоже на работу.
Том Олдкрофт
7
Для тех, кто использует нагрузку numpy и сталкивается с подобной проблемой: там также можно пройти кодирование:np.load('./bvlc_alexnet.npy', encoding='latin1')
Серж Захарченко,
Это сработало для меня, когда добавление encoding='latin1'не удалось. Спасибо!
Гиллем Кукурул
130

Если вы получаете эту ошибку в python3, то это может быть проблема несовместимости между python 2 и python 3, для меня решение было с loadпомощью latin1кодировки:

pickle.load(file, encoding='latin1')
Цилидзи Мудау
источник
16

Кажется, это проблема несовместимости между Python 2 и Python 3. Я попытался загрузить набор данных MNIST с

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

и это работает для Python 3.5.2

Стив
источник
7

Похоже, что есть некоторые проблемы с совместимостью в pickle между 2.x и 3.x из-за перехода на unicode. Похоже, что ваш файл засолен с помощью Python 2.x, и декодирование его в 3.x может быть проблематичным.

Я бы посоветовал снять его с python 2.x и сохранить в формате, который более удобен для двух используемых вами версий.

Джон Лион
источник
2
Это то, что я пытался сделать. Какой формат вы рекомендуете?
Нил Дж
5
Я думаю, что проблема могла быть в кодировании numpy dtype, который мог бы быть строкой. В любом случае, я использовал numpy.save/load для устранения разрыва между питоном 2 и 3, и это сработало.
Нил Дж
7

Я просто наткнулся на этот фрагмент. Надеюсь, это поможет прояснить проблему совместимости.

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, который помог, пожалуйста, объяснение ответа
Сарат Садасиван Пиллаи
6

Пытаться:

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

Из документации pickle.loadметода:

Необязательными ключевыми аргументами являются fix_imports, кодировка и ошибки, которые используются для управления поддержкой совместимости для потока рассола, сгенерированного Python 2.

Если fix_imports равен True, pickle попытается отобразить старые имена Python 2 на новые имена, используемые в Python 3.

Кодирование и ошибки сообщают pickle, как декодировать экземпляры 8-битных строк, выбранные Python 2; по умолчанию это ASCII и строгое, соответственно. Кодировка может быть «байтами» для чтения этих 8-битных строковых экземпляров как байтовых объектов.

Маниш Кумбхаре
источник
0

Есть хикл, который быстрее, чем мариновать, и легче. Я пытался сохранить и прочитать его в дампе, но во время чтения было много проблем, потраченных впустую час, и я так и не нашел решения, хотя работал над своими данными, чтобы создать чат-бота.

vec_xи vec_yявляются массивами NumPy:

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

Затем вы просто читаете его и выполняете операции:

data2 = hkl.load( 'new_data_file.hkl' )
К.С. ХАРША
источник