我有一个字典列表,其中每个字典包含多个不同的项目。它用作强化学习训练过程中的记忆重播,我需要创建一个备份文件,以防过程中断。每个字典代表一个环境步骤,因此结构相同,只有值不同。
每个字典包含的数据类型为: numpy.array,int,bool,字符串,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评论:
from joblib import dump, load
import pickle
想法是通过pickle.dumps将对象序列化为字符串,并且由于它仅创建字符串但不保存到文件中,因此我使用joblib.dump来创建此类文件。
serialized_mem = load(f)
中引发了错误
保存期间没有例外
转储后,文件路径作为dict(保持基类的继承)传递到主类,并与备份文件的其他路径(如神经网络,优化器等)合并。
错误文件的大小不是确定的-有时在列表达到最大容量(100k个样本)之前会失败,然后它的off会变小,并且有时错误发生在(例如)500k步骤之后,因此大小是正常的。但是您让我记住了一个重要的细节……self._memory
实际上是 deque (from collections import deque
)类型的(它继承自父类,并且可以像与列表,这就是为什么我忘记了它)。并且作为双端队列,保存“未满”对象可能是一个问题,这将解释EOFError的含义。我将做一些测试并报告结果。
答案 0 :(得分:0)
两天没有错误,所以我猜它已经解决了。最后,我使用了一些不同的东西,因为我在保存时遇到了MemoryError
,同时在32GB RAM上运行64位python版本,其中一半以上可用。
此实现似乎在加载时解决了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