EOFError при загрузке списка диктов с различными типами данных - PullRequest
0 голосов
/ 01 марта 2020

У меня есть список диктов, где каждый дикт содержит несколько разных предметов. Он используется в качестве воспроизведения памяти в процессе обучения обучению подкреплению, и мне нужно создать файл резервной копии на случай, если что-то прервет этот процесс. Каждый dict представляет один шаг среды, поэтому структура одинакова, отличаются только значения.

Типы данных, которые содержит каждый dict: numpy .array, int, bool, string, list из numpy массивов и float . Массив Np предварительно обработан, поэтому он содержит реальные числа с плавающей точкой - без NaN или Inf.

Моя проблема в том, что я пробовал несколько способов, как хранить и загружать файлы, и все они вели себя одинаково - резервное копирование создано без проблем, но иногда (или даже не совсем - просто без шаблона, чтобы обнаружить ошибку в другом месте) при загрузке это вызывает EOFError.

Максимальный объем данных в списке теперь ограничен 100 КБ, и созданный файл обычно около 128 МБ.

В настоящее время я пытаюсь сделать это с помощью pickle.dumps, но в прошлом я пробовал использовать обычные файлы JobLib dump / load и copy.deepcopy для дампа.

def _save_backup(self, path:str, name:str) -> dict:
    file_path = path+name+'_memory.joblib'
    with open(file_path, "wb") as f:
        serialized_mem = pickle.dumps(self._memory,protocol=pickle.HIGHEST_PROTOCOL)
        dump(serialized_mem,f)    
    return {'memory':file_path}


def _load_backup(self, data:dict):
    if os.path.exists(data['memory']):
        with open(data['memory'], "rb") as f:
            serialized_mem = load(f)
            self._memory = pickle.loads(serialized_mem)

Редактировать

для ответа tdelaney комментарий:

  • загрузка и выгрузка из joblib

from joblib import dump, load import pickle

  • Идея заключалась в том, чтобы сериализовать объект в строку с помощью pickle.dumps, и поскольку он только создает строку, но не сохраняет в файл, я затем использую joblib.dump для создания такого файла.

  • ошибка действительно возникает в serialized_mem = load(f)* 1 038 *

  • Никакие исключения не подавляются при сохранении

  • после дампа filepath передается как dict (для сохранения наследования базового класса) в основной класс и объединяется с другими путями файлов резервных копий, такими как нейронная сеть, оптимизатор и т. д. c.

  • Размер файла ошибки не определен c - иногда происходит сбой до того, как список достигает полной емкости (100k образцов), а затем его c меньше, и иногда возникает ошибка, например, после 500 тыс. шагов, поэтому размер нормальный Но вы заставили меня вспомнить довольно важную деталь ... на самом деле self._memory имеет тип deque (from collections import deque) (он унаследован от parent и позволяет работать с ним как со списком, поэтому Я забыл об этом). И в качестве deque это может быть проблема с сохранением «недопустимого» объекта, что объясняет значение EOFError. Я сделаю несколько тестов и сообщу результат.

1 Ответ

0 голосов
/ 05 марта 2020

Пару дней без ошибок, поэтому я думаю, что это исправлено. В конце я использовал что-то немного другое, так как во время сохранения у меня возникла MemoryError при работе с 64-битной python версией на 32 ГБ ОЗУ с более чем половиной доступного для использования.

Эта реализация, кажется, решает как MemoryError, так и EOFError при загрузке

def save_backup(self, path:str, name:str) -> dict:
    # save memory
    file_path = path+name+'_memory.joblib'
    with open(file_path, "wb") as f:
        for data in list(self._memory):
            pickle.dump(data,f)  
    # save other files
    d = self._save_backup(path,name) # child class method
    # merge dicts
    d.update({'memory':file_path})
    return d


def load_backup(self, data:dict):
    # load memory
    if os.path.exists(data['memory']):
        with open(data['memory'], "rb") as f:
            self._memory.clear()
            while True:
                try:
                    self._memory.append(pickle.load(f))
                except EOFError:
                    break
    # load others
    self._load_backup(data) # child class method
...