Невідповідність нульових масивів між 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х. особливо рядок проти unicode. І вибір нумерованого об'єкта вимагає, щоб обидві системи завантажували модуль 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, в цьому випадку це бінарні дані. Якщо це помилка в програмі Unpickler 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
Для тих, хто використовує nummy навантаження та стикається з подібною проблемою: там також можна передати кодування: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

Схоже, є певні проблеми порівняння з порівняльністю у соління між 2.x та 3.x через перехід на unicode. Здається, ваш файл маринований python 2.x, а розшифровка його в 3.x може бути проблемою.

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


2
Це те, що я намагався зробити. Який формат ви рекомендуєте?
Ніл Г

5
Я думаю, що проблема могла полягати в кодуванні numtype dtype, який може бути рядком. У будь-якому випадку я в кінцевому підсумку використовую numpy.save/load, щоб подолати розрив між python 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 вірно, pickle спробує зіставити старі імена Python 2 з новими іменами, які використовуються в Python 3.

Кодування та помилки вказують на макіяж, як розшифрувати 8-бітові рядкові екземпляри, вибрані Python 2; ці значення за замовчуванням - "ASCII" і "строго" відповідно. Кодування може бути "байтами", щоб прочитати ці 8-бітні рядкові екземпляри як об'єкти байтів.


0

Є жировик, який швидше, ніж соління і простіше. Я спробував зберегти і прочитати його на смітнику, але під час читання виникло багато проблем і витрачався витрачений годину, і досі не знайшов рішення, хоча я працював над власними даними, щоб створити чат.

vec_xі vec_yє нумерованими масивами:

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

Потім ви просто прочитаєте його і виконайте операції:

data2 = hkl.load( 'new_data_file.hkl' )
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.