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, если вы этого не сделали.