【背景】
训练神经网络,需要大量样本数据。内存空间显然是不够的,需要考虑一些其他办法来储存和训练数据
1.网络框架用的是keras,keras正好 有 fit_generator,所以只用写一个迭代器就可以用于大量数据的训练
2.剩下的就是数据的储存和持久化。keras自带HDF5Matrix,但是这个比较残,貌似只支持读。
还能用的就是h5py了,第三方库。
【h5py】
h5py的一些基本操作就不说了,比如新建group、dataset的相关文章挺多的。
但是,由于需求特殊,样本不是一次采集完成。
只能一点一点的更新,因此需要分步来写。
在csdn上看到一种方法是先a)读出旧的;b)删除旧的;c)写入旧+新
显然,对于这种方法是不屑的。
快要放弃h5py的时候,查stackoverflow。发现有一种方法可以增量写【参考链接】,要点如下:
1.新建dataset时一定要指定maxshape和chunks,指定chunks需要指定shape(第二个参数)
dset = f.create_dataset('voltage284', (10**5,), maxshape=(None,),
dtype='i8', chunks=(10**4,))
2.增量写时需要对dataset先resize到合适的大小,然后在扩展后的空间中写入增量数据
dset.resize(dset.shape[0]+10**4, axis=0)
dset[-10**4:] = np.random.random(10**4)
print(dset.shape)
【keras数据生成器】
keras在训练大量数据时,如果不能一次性加载全部数据(内存不够),需要使用其他方法生成数据。
按keras官方推荐,是使用fit_generator和sequence。相关教程很多,如【教程1】【教程2】【教程3】【教程4】
但是,使用下来效果并不理想。配合hdf5速度非常之慢(内存确实节约了),同时也没法使用多进程读取hdf5,训练时间相比于内存中的数据,满了近乎百倍。
遇到问题肯定要解决,解决方案:
手动从数据集中加载一定数量的样本。特别值得注意的是,读取时最好按照预先设定的chunk的大小来读取(速度最快)
def load_data(dset, size, chunk_size):
# 判断文件是否存在
if not os.path.exists(dset):
return False
# 用只读的方式打开
with h5py.File(dset, 'r') as dset:
# 按chunk的大小分块读取
indexs_chunk = numpy.random.permutation(math.ceil(dset['x'].shape[0]/chunk_size))
total_chunks = math.ceil(size/chunk_size)
res = []
for i in indexs_chunk[:total_chunks]:
res.append(dset['x'][i*chunk_size:(i+1)*chunk_size])
return numpy.concanate(res)
由于每次生成的都是固定数据,所以训练函数也需要进行一定的修改
start_epoch = 0
batch_epochs = 10
while True:
x = load_data(x_path, 100000, 10000)
y = load_data(y_path, 100000, 10000)
model.fit(x=x, y=y, epochs = start_epoch + batch_epochs, initial_epoch=start_epoch)
start_epoch += batch_epochs