PyTorch DataLoader运行速度过慢问题咨询:同输入下耗时远超直接调用Tensor
问题成因
- DataLoader默认采用单样本逐次采样逻辑:即使将batch_size设置为全量数据大小,默认采样器仍会生成273468个独立单元素索引,逐次调用
__getitem__方法27万次,每次从CUDA张量中取单个元素,产生27万次CUDA设备同步开销(CPU调用GPU数据需要等待同步返回)。 - 存在冗余数据移动与拼接开销:逐次取出的单元素张量会先被收集到CPU内存,再通过默认
collate_fn拼接为完整batch,产生大量CPU-GPU小数据传输开销,若拼接后的batch需要送入GPU模型,还会额外产生一次大张量的设备移动开销。 - 直接传入全量张量无额外开销:直接传入全量CUDA张量仅需一次API调用,没有逐次同步、小数据传输和冗余拼接过程,因此耗时仅为2ms。
优化方案
- 方案1:关闭单样本采样逻辑,直接返回全量batch
如果不需要切分小batch,仅需通过DataLoader返回全量数据,直接将batch_size设为None即可,DataLoader会跳过单样本采样流程,仅调用一次__getitem__返回整个数据集,耗时和直接传入张量基本一致:
test_loader = DataLoader(test_set, batch_size=None)
- 方案2:自定义批量采样逻辑,适配小batch加载场景
如果需要用DataLoader切分小batch训练/推理,自定义BatchSampler每次返回批量索引列表,同时搭配无操作的collate_fn避免冗余拼接,每个batch仅调用一次__getitem__,不会产生逐次采样开销:
from torch.utils.data import BatchSampler, SequentialSampler # 批量采样器,每次返回对应batch大小的索引组 sampler = BatchSampler(SequentialSampler(test_set), batch_size=1024, drop_last=False) test_loader = DataLoader( test_set, batch_sampler=sampler, collate_fn=lambda x: x # 直接返回批量张量,无需额外拼接 )
- 方案3:适配大数据量加载场景,利用DataLoader原生优化能力
如果数据量过大无法全部放入GPU显存,将原始数据放在CPU内存中,开启DataLoader的内存锁定和多进程加载能力,实现数据加载和模型推理并行,大幅提升加载效率:
# 数据提前加载到CPU内存 data = torch.FloatTensor(np.load('slices.npy').reshape(-1, 1225)) test_set = UnlabeledTensorDataset(data) test_loader = DataLoader( test_set, batch_size=1024, num_workers=4, # 可根据CPU核心数调整 pin_memory=True, # 锁定内存减少CPU到GPU的传输延迟 pin_memory_device='cuda' ) # 取数时开启异步传输,和模型推理并行 for batch in test_loader: batch = batch.to('cuda', non_blocking=True) # 后续推理逻辑
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

