Pickle сбрасывает огромный файл без ошибки памяти

У меня есть программа, в которой я в основном корректирую вероятность того, что определенные вещи происходят, основываясь на том, что уже известно. Мой файл данных уже сохранен как объект словаря pickle в Dictionary.txt.

Проблема в том, что каждый раз, когда я запускаю программу, которую он извлекает в Dictionary.txt, превращает его в объект словаря, редактирует и перезаписывает Dictionary.txt. Это довольно много памяти, поскольку Dictionary.txt составляет 123 МБ. Когда я получаю дамп, я получаю MemoryError, все выглядит нормально, когда я его вытащил..

  • Есть ли лучший (более эффективный) способ внесения изменений? (Возможно, без необходимости перезаписывать весь файл каждый раз)

  • Есть ли способ, которым я могу вызвать сборку мусора (через модуль gc)? (У меня уже есть автоматическое включение через gc.enable())

  • Я знаю, что помимо readlines() вы можете читать построчно. Можно ли поэтапно редактировать словарь построчно, когда у меня уже есть полностью заполненный файл объекта словаря в программе.

  • Есть другие решения?

Спасибо за уделенное время.

Ответ 1

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

сохранить модель на диск

from sklearn.externals import joblib
filename = 'finalized_model.sav'
joblib.dump(model, filename)  

некоторое время спустя... загрузить модель с диска

loaded_model = joblib.load(filename)
result = loaded_model.score(X_test, Y_test) 

print(result)

Ответ 2

Я являюсь автором пакета под названием klepto (а также автором dill). klepto создан для хранения и извлечения объектов очень простым способом и предоставляет простой интерфейс словаря для баз данных, кеш-памяти и хранения на диске. Ниже я показываю хранение больших объектов в "архиве каталога", который представляет собой каталог файловой системы с одним файлом на запись. Я выбираю сериализацию объектов (медленнее, но использует dill, поэтому вы можете хранить практически любой объект), и я выбираю кеш. Использование кеша памяти позволяет мне иметь быстрый доступ к архиву каталога без необходимости иметь весь архив в памяти. Взаимодействие с базой данных или файлом может быть медленным, но взаимодействие с памятью происходит быстро... и вы можете заполнить кеш памяти, как вам нравится, из архива.

>>> import klepto
>>> d = klepto.archives.dir_archive('stuff', cached=True, serialized=True)
>>> d
dir_archive('stuff', {}, cached=True)
>>> import numpy
>>> # add three entries to the memory cache
>>> d['big1'] = numpy.arange(1000)
>>> d['big2'] = numpy.arange(1000)
>>> d['big3'] = numpy.arange(1000)
>>> # dump from memory cache to the on-disk archive
>>> d.dump()
>>> # clear the memory cache
>>> d.clear()
>>> d
dir_archive('stuff', {}, cached=True)
>>> # only load one entry to the cache from the archive
>>> d.load('big1')
>>> d['big1'][-3:]
array([997, 998, 999])
>>> 

klepto обеспечивает быстрый и гибкий доступ к большим объемам хранения, а если архив позволяет осуществлять параллельный доступ (например, некоторые базы данных), вы можете читать результаты параллельно. Он также легко обменивается результатами в разных параллельных процессах или на разных машинах. Здесь я создаю второй экземпляр архива, указывающий на тот же архив каталога. Легко передавать ключи между двумя объектами и не отличается от другого процесса.

>>> f = klepto.archives.dir_archive('stuff', cached=True, serialized=True)
>>> f
dir_archive('stuff', {}, cached=True)
>>> # add some small objects to the first cache  
>>> d['small1'] = lambda x:x**2
>>> d['small2'] = (1,2,3)
>>> # dump the objects to the archive
>>> d.dump()
>>> # load one of the small objects to the second cache
>>> f.load('small2')
>>> f       
dir_archive('stuff', {'small2': (1, 2, 3)}, cached=True)

Вы также можете выбрать различные уровни сжатия файлов и вы хотите, чтобы файлы отображались в памяти. Есть много разных как для файловых серверов, так и для баз данных. Интерфейс идентично, однако.

Что касается ваших других вопросов по сборке мусора и редактированию частей словаря, то оба возможны с помощью klepto, так как вы можете индивидуально загружать и удалять объекты из кеша памяти, выгружать, загружать и синхронизировать с архивом бэкэнд или любой другой словарь.

Смотрите более длинный учебник здесь: https://github.com/mmckerns/tlkklp

Получить klepto здесь: https://github.com/uqfoundation

Ответ 3

У меня была ошибка памяти и разрешили ее с помощью протокола = 2:

cPickle.dump(obj, file, protocol=2)

Ответ 4

Если ваш ключ и значения являются строками, вы можете использовать один из встроенных постоянных систем хранения значений ключа, доступных в стандартной библиотеке Python. Пример из документа anydbm:

import anydbm

# Open database, creating it if necessary.
db = anydbm.open('cache', 'c')

# Record some values
db['www.python.org'] = 'Python Website'
db['www.cnn.com'] = 'Cable News Network'

# Loop through contents.  Other dictionary methods
# such as .keys(), .values() also work.
for k, v in db.iteritems():
    print k, '\t', v

# Storing a non-string key or value will raise an exception (most
# likely a TypeError).
db['www.yahoo.com'] = 4

# Close when done.
db.close()

Ответ 5

Пробовали ли вы использовать поточный рассол: https://code.google.com/p/streaming-pickle/

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

Ответ 6

Как насчет этого?

import cPickle as pickle
p = pickle.Pickler(open("temp.p","wb")) 
p.fast = True 
p.dump(d) # d could be your dictionary or any file

Ответ 7

Недавно у меня была эта проблема. Попробовав cpickle с ASCII и бинарным протоколом 2, я обнаружил, что мой SVM из sci-kit, обученный на 20+ gb данных, не травил из-за ошибки памяти. Тем не менее, пакет укропа, похоже, решил проблему. Dill не будет создавать много улучшений для словаря, но может помочь в потоковой передаче. Он предназначен для потока маринованных байтов по сети.

import dill

with open(path,'wb') as fp:
    dill.dump(outpath,fp)
    dill.load(fp)

Если эффективность является проблемой, попробуйте загрузить/сохранить в базу данных. В этом случае решение для хранения данных может быть проблемой. При 123 МБ Pandas должно быть хорошо. Однако, если машина имеет ограниченную память, SQL предлагает быстрые, оптимизированные операции с мешками над данными, обычно с поддержкой многопоточности. Мое ядро ​​svm сохранено.

Ответ 8

Ни один из вышеперечисленных ответов не работал у меня. Я закончил с использованием Hickle, который является заменой для рассола на основе HDF5. Вместо того, чтобы сохранять его в рассол, он сохраняет данные в файл HDF5. API для большинства случаев использования идентичен, и у него есть некоторые действительно интересные функции, такие как сжатие.

pip install hickle

Пример:

# Create a numpy array of data
array_obj = np.ones(32768, dtype='float32')

# Dump to file
hkl.dump(array_obj, 'test.hkl', mode='w')

# Load data
array_hkl = hkl.load('test.hkl')

Ответ 9

Это может показаться тривиальным, но попробуйте использовать 64-битный Python, если вы этого не сделали.