Python “如何将数据加载到内存中”;“提前”;避免从磁盘读取?
我正在用笔记本电脑的GPU(GeForce GTX 1050)在一些自定义图像数据集上直接训练一个ConvNet(Keras,python)。在培训期间监控我的GPU时,我注意到它的使用率仅为其容量的10%左右,甚至更低。进一步调查使我了解到,通过访问存储磁盘中的数据,培训遇到了瓶颈(我正在使用数据生成器) 我还注意到,虽然磁盘的使用率为100%,但我的内存却没有(使用率约为65%)。我想:让我们“提前”将下一批数据加载到内存中(或下几个批),同时GPU在当前批上进行训练,,然后直接从内存访问加载的批,避免昂贵的磁盘读取。我在stack overflow和其他平台上查找了一些文档或代码,但没有找到任何相关内容 我找到了一个临时解决方案来避免这种磁盘读取瓶颈,那就是将数据粘贴到我的操作系统磁盘(SSD)上。它运行得非常好,将训练时间减少了10-15倍。但由于SSD磁盘上的存储容量有限(100 Gb),当我要处理更重的数据时(通常,我现在正在使用重采样图像(64,64),但我计划将其放大到(128,128)甚至更多),此解决方案将不起作用 下面是我的发电机的代码,以便您更好地了解情况:Python “如何将数据加载到内存中”;“提前”;避免从磁盘读取?,python,memory-management,data-generation,Python,Memory Management,Data Generation,我正在用笔记本电脑的GPU(GeForce GTX 1050)在一些自定义图像数据集上直接训练一个ConvNet(Keras,python)。在培训期间监控我的GPU时,我注意到它的使用率仅为其容量的10%左右,甚至更低。进一步调查使我了解到,通过访问存储磁盘中的数据,培训遇到了瓶颈(我正在使用数据生成器) 我还注意到,虽然磁盘的使用率为100%,但我的内存却没有(使用率约为65%)。我想:让我们“提前”将下一批数据加载到内存中(或下几个批),同时GPU在当前批上进行训练,,然后直接从内存访问加
def生成器(self,passs=np.inf):
#初始化历元计数
db=self.db
纪元=0
#继续无限循环——一旦我们完成了,模型就会停止
#达到所需的纪元数
随着时代的流逝:
#随机性的随机数据集索引
如果self.shuffle==True:np.random.shuffle(self.dataset\u索引)
#在HDF5数据集索引上循环
对于np.arange中的i(0,self.numImages,self.batchSize):
十、 Y=[],[]
如果self.gaussian_test==True:#TODO:添加高斯测试
对于self.dataset_索引中的j[i:i+self.batchSize]:
y=db[db[self.gen_type+“_index”][j][“label”][()]
X.append(np.random.normal(loc=y,scale=0.2,size=(1,64,64)))
Y.append(Y)
其他:
对于self.dataset_索引中的j[i:i+self.batchSize]:
附加(db[db[self.gen_type+“_index”][j][“array”][()]))
Y.append(db[db[self.gen_type+“_index”][j][“label”][()]))
X=np.数组(X)
Y=np.数组(Y)
Y=到_分类(Y,num_类=6)
#生成图像和标签的元组
产量(X,Y)
#增加历代的总数
纪元+=1
我不知道如何继续,但我非常确定这应该是可能的…因为我现在还没有收到任何答案,我将把我的发现分享给任何对这个话题感兴趣的人。实际上,我想要的想法是使用多重处理 (I):经过一些研究,我发现Keras fit_generator()通过参数use_multiprocessing=True和workers=n允许这种多重处理。但这种方法有其局限性:
- 首先,生成器必须是线程安全的。如果生成器是从Keras.utils.Sequence类继承的,则它已经是线程安全的。否则,请参阅本文,您将学习如何创建一个装饰器,使生成器线程安全
- 其次,如果您使用的是Windows计算机,则无法设置use\u multiprocessing=True,因为它没有实现。尽管如此,我意识到您仍然可以设置workers=n>1,但我认为您的生成器将不会是线程安全的,这是一个问题李>