簡體   English   中英

加載具有各種數據類型的字典列表時出現 EOFError

[英]EOFError when loading list of dicts with various datatypes

我有字典列表,其中每個字典包含多個不同的項目。 它在強化學習的訓練過程中用作記憶重放,我需要創建一個備份文件,以防該過程中斷。 每個字典代表一個環境步驟,因此結構相同,只有值不同。

每個 dict 包含的數據類型是: numpy.array、int、bool、string、 numpy 數組列表float Np 數組經過預處理,因此它確實包含真正的浮點數 - 沒有 NaN 或 Inf。

我的問題是,我嘗試了多種方法,如何存儲和加載文件,並且所有文件的行為都相似 - 創建備份沒有問題,但有時(甚至根本沒有 - 根本沒有模式可以在其他地方發現錯誤)加載時它,它會引發 EOFError。

列表中的最大數據量現在限制為 100k,創建的文件通常約為 128MB。

目前我正在通過 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)確實引發了錯誤

  • 保存期間沒有異常被抑制

  • 轉儲后,文件路徑作為dict(以保持基類的繼承)傳遞給主類,並與其他備份文件路徑(如神經網絡、優化器等)合並。

  • 錯誤文件大小是不確定的 - 有時它在列表達到其全部容量(100k 個樣本)之前失敗,然后它的 ofc 更小,有時錯誤發生在例如 500k 步之后,所以大小是正常的。 但是你讓我記住了一個非常重要的細節...... self._memory實際上是deque類型( from collections import deque )(它從父級繼承並允許像使用列表一樣使用它,這就是為什么我忘記了它) . 作為雙端隊列,保存“未滿”對象可能是一個問題,這將解釋 EOFError 的含義。 我會做一些測試並報告結果。

幾天沒有錯誤,所以我想它是固定的。 最后我使用了一些不同的東西,因為在 32GB RAM 上運行 64 位 python 版本時,我在保存過程中遇到了MemoryError ,其中一半以上可以使用。

這個實現似乎解決了加載時的MemoryErrorEOFError

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM