比较深度学习中数据加载方法的效率
Compare the efficiency of the data loading methods in deep learning
我需要加载时间序列数据集来训练网络。当我从原始数据中提取这些 .npy
文件时,由于内存问题,数据集被分成许多块 train_x_0.npy
、train_x_1.npy
、...、train_x_40.npy
(41 个块) .但是,它们的大小太大(大约 1000 GB),我无法将所有内容加载到 RAM 中。我一直在考虑两种方法来解决这个问题。
- 使用带有参数
mmap_mode='r+'
的 np.load()
加载数据块。内存映射块存储在 Python 列表 self.data
中。在Pytorch的__getitem__(self, idx)
方法Dataset
class中,我将idx
转换为chunk_idx
和sample_idx
,然后通过[=22=得到样本].
- 再次从原始数据中提取
.npy
文件,并逐个样本保存数据,即一个.npy
文件现在是一个样本,而不是数据块。在 __getitem__(self, idx)
方法中,我将通过使用 np.load(sample_path)
. 加载它来获得一个样本
假设 Pytorch DataLoader
将用于遍历所有样本,那么哪种方法会更快?
如果您对提取原始数据或加载 .npy
文件有其他建议,请分享您的意见。
这两种建议的方法都将受到文件系统 IO 的限制,因为每个样本都将从磁盘加载 on-demand(内存映射不会加速实际加载,一旦请求了给定的补丁)。
特别是当您计划训练多个 epoch 时,您可以通过加载原始块 train_x_0.npy
、train_x_1.npy
等一个(或尽可能多的块)来实现强大的加速在 RAM 中)一次并在切换到下一个之前在此块上训练多个时期。
为此,您需要控制 dataloader
请求的样本索引。为此,您可以定义一个采样器,该采样器传递相应缓存数据块中可用的样本索引。在伪代码中,当一次缓存一个块时,您的训练循环可能看起来像这样:
from yourproject import Dataset
from torch.utils.data import DataLoader
from torch.utils.data.sampler import SubsetRandomSampler
dataset = Dataset(train_data_path, ...)
for chunk_idx in range(num_chunks):
dataset.cache_chunk(chunk_idx)
chunk_sample_inds = dataset.get_chunk_sample_inds(chunk_idx)
chunk_sampler = SubsetRandomSampler(chunk_sample_inds)
chunk_loader = DataLoader(dataset=dataset, sampler=chunk_sampler)
for chunk_epoch in range(num_chunk_epoch):
for sample_idx, sample in enumerate(chunk_loader):
output = model(sample)
特此,您的Dataset
class需要注意
- 缓存(加载到 RAM)指定的块,给定块 idx(由
cache_chunk
方法指示)
- 返回给定块 idx 的有效样本索引列表(由
get_chunk_sample_inds
方法指示)
如果您使用快速 GPU(这通常受到在 RAM 和 VRAM 之间来回移动数据的限制,即使是 RAM-cached 数据),您可以预期使用这种方法可以提高几个数量级的速度(而不是尝试为每个样本从 HDD 填充 VRAM。
我需要加载时间序列数据集来训练网络。当我从原始数据中提取这些 .npy
文件时,由于内存问题,数据集被分成许多块 train_x_0.npy
、train_x_1.npy
、...、train_x_40.npy
(41 个块) .但是,它们的大小太大(大约 1000 GB),我无法将所有内容加载到 RAM 中。我一直在考虑两种方法来解决这个问题。
- 使用带有参数
mmap_mode='r+'
的np.load()
加载数据块。内存映射块存储在 Python 列表self.data
中。在Pytorch的__getitem__(self, idx)
方法Dataset
class中,我将idx
转换为chunk_idx
和sample_idx
,然后通过[=22=得到样本]. - 再次从原始数据中提取
.npy
文件,并逐个样本保存数据,即一个.npy
文件现在是一个样本,而不是数据块。在__getitem__(self, idx)
方法中,我将通过使用np.load(sample_path)
. 加载它来获得一个样本
假设 Pytorch DataLoader
将用于遍历所有样本,那么哪种方法会更快?
如果您对提取原始数据或加载 .npy
文件有其他建议,请分享您的意见。
这两种建议的方法都将受到文件系统 IO 的限制,因为每个样本都将从磁盘加载 on-demand(内存映射不会加速实际加载,一旦请求了给定的补丁)。
特别是当您计划训练多个 epoch 时,您可以通过加载原始块 train_x_0.npy
、train_x_1.npy
等一个(或尽可能多的块)来实现强大的加速在 RAM 中)一次并在切换到下一个之前在此块上训练多个时期。
为此,您需要控制 dataloader
请求的样本索引。为此,您可以定义一个采样器,该采样器传递相应缓存数据块中可用的样本索引。在伪代码中,当一次缓存一个块时,您的训练循环可能看起来像这样:
from yourproject import Dataset
from torch.utils.data import DataLoader
from torch.utils.data.sampler import SubsetRandomSampler
dataset = Dataset(train_data_path, ...)
for chunk_idx in range(num_chunks):
dataset.cache_chunk(chunk_idx)
chunk_sample_inds = dataset.get_chunk_sample_inds(chunk_idx)
chunk_sampler = SubsetRandomSampler(chunk_sample_inds)
chunk_loader = DataLoader(dataset=dataset, sampler=chunk_sampler)
for chunk_epoch in range(num_chunk_epoch):
for sample_idx, sample in enumerate(chunk_loader):
output = model(sample)
特此,您的Dataset
class需要注意
- 缓存(加载到 RAM)指定的块,给定块 idx(由
cache_chunk
方法指示) - 返回给定块 idx 的有效样本索引列表(由
get_chunk_sample_inds
方法指示)
如果您使用快速 GPU(这通常受到在 RAM 和 VRAM 之间来回移动数据的限制,即使是 RAM-cached 数据),您可以预期使用这种方法可以提高几个数量级的速度(而不是尝试为每个样本从 HDD 填充 VRAM。