【发布时间】:2020-07-04 04:46:58
【问题描述】:
我正在测试使用 h5py 有效保存和检索数据的方法。但是在没有用完所有内存的情况下运行时间有问题。
在我的第一个方法中,我只是创建了一个静态 h5py 文件
with h5py.File(fileName, 'w') as f:
f.create_dataset('data_X', data = X, dtype = 'float32')
f.create_dataset('data_y', data = y, dtype = 'float32')
在第二种方法中,我设置了参数maxshape,以便将来附加更多的训练数据。 (见How to append data to one specific dataset in a hdf5 file with h5py)
with h5py.File(fileName2, 'w') as f:
f.create_dataset('data_X', data = X, dtype = 'float32',maxshape=(None,4919))
f.create_dataset('data_y', data = y, dtype = 'float32',maxshape=(None,6))
我正在使用 PyTorch,并且正在设置我的数据加载器:
class H5Dataset_all(torch.utils.data.Dataset):
def __init__(self, h5_path):
# super(dataset_h5, self).__init__()
self.h5_path = h5_path
self._h5_gen = None
def __getitem__(self, index):
if self._h5_gen is None:
self._h5_gen = self._get_generator()
next(self._h5_gen)
return self._h5_gen.send(index)
def _get_generator(self):
with h5py.File( self.h5_path, 'r') as record:
index = yield
while True:
X = record['data_X'][index]
y = record['data_y'][index]
index = yield X, y
def __len__(self):
with h5py.File(self.h5_path,'r') as record:
length = record['data_X'].shape[0]
return length
loader = Data.DataLoader(
dataset=H5Dataset_all(filename),
batch_size=BATCH_SIZE,
shuffle=True, num_workers=0)
为这些方法中的每一个保存了相同的数据后,我希望它们在运行时间上相似,但事实并非如此。我使用的数据大小为X.shape=(200722,4919) 和y.shape=(200772,6)。每个文件大约 3.6 GB。
我使用以下方法测试运行时间:
import time
t0 = time.time()
for i, (X_batch, y_batch) in enumerate(loader):
# assign a dummy value
a = 0
t1 = time.time()-t0
print(f'time: {t1}')
第一种方法的运行时间是83 s,第二种方法是1216 s,这在我看来是没有意义的。谁能帮我弄清楚为什么?
此外,我还尝试使用torch.save 和torch.load 将其保存/加载为torch 文件,并将数据传递给Data.TensorDataset,然后再设置加载程序。此实现运行速度明显更快(大约 3.7 秒),但缺点是必须在训练之前加载文件,这可能很快就会被我的内存限制。
有没有更好的方法可以让我训练得更快一些,而不必在训练前加载所有数据?
【问题讨论】:
-
在我看来,第一种方法的数据集大小是固定的。 (这是存储
data = X和data = Y所需的大小。)此外,您如何扩展数据集的大小?我希望看到对Dataset.resize()的调用以增加原始大小/形状分配的大小/形状。以Dataset.resize()为例,请查看此答案。 resizing-and-storing-dataset-using-h5py -
是的,第一种方法的大小是固定的,我在第二种方法中扩展数据集的大小,例如:
python f['data_X'].resize(f['data_X'].shape[0]+X.shape[0],axis = 0)然后python f['data_X'][-X.shape[0]:] = X但在我报告的运行时间中,这从来没有叫 -
调用加载程序多少次?加载程序是否在每次调用时写入相同的 HDF5 文件和数据集?如果是这样,在方法 1 中,加载器只是用新数据覆盖现有数据。您将在文件和数据集大小中看到这一点——使用方法 1 多次调用加载程序后它们不会改变。
-
我不确定你的意思。我只调用一次加载器并使用它来遍历 filename 中保存的数据。在方法 1 中,文件被覆盖 - 因此最大数据量受我一次可以节省多少内存的限制。第二种方法的想法是能够不断地将数据添加到文件中。问题是,当每个方法只调用一次(相同数量的数据)时,第二种方法的加载器需要比第一种方法更长的时间来迭代。