Pytorch 加速读取数据之 prefetch_factor

博客分享了提高GPU训练效率的两种方法。一是利用NVIDIA DALI模块加速数据预处理,通过并行处理减少训练延迟。二是升级PyTorch到1.7以上版本,利用新增的`prefetch_factor`参数,预先加载更多批次的数据,显著缩短数据读取时间,提高显卡利用率。作者实测将加载时间从3s降至0.5s,效果明显。
部署运行你感兴趣的模型镜像

最近使用四卡训练图片,发现总有卡的效率突变到0,大致就是在读取以及处理数据了
怎么能加速读取呢?一个方法是用NVIDIA的DALI模块,可以加速,具体可以参考 英伟达DALI加速技巧:让数据预处理速度比原生PyTorch快4倍
主要就是通过并行训练和预处理过程,减少了延迟及训练时间
在这里插入图片描述

但是今天我发现一个更简单的方法
就是升级pytorch到1.7以上,目前是1.8.1,最好的1.8.1吧
为什么会这么说呢,因为在dataloader中加入了一个参数 prefetch_factor,这个就是提前加载多少个batch的数据,具体更改看github ,具体说如下,现在默认prefetch_factor =2 ,就是意味着预先加载 prefetch 2 * num_workers 个data

fix #40604
Add parameter to Dataloader to configure the per-worker prefetch number.
Before this edit, the prefetch process always prefetch 2 * num_workers data items, this commit help us make this configurable, e.x. you can specify to prefetch 10 * num_workers data items

我在我这里试了一下,升级以后,有从3s到0.5s,速度还是很明显的,而且显卡利用率都上来了。大家可以自己试试~

您可能感兴趣的与本文相关的镜像

PyTorch 2.5

PyTorch 2.5

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

<think>我们正在讨论PyTorch中如何使用多线程加载数据集。根据引用内容,主要涉及`DataLoader`中的`num_workers`参数。 引用[1]和[3]都提到了`DataLoader`的`num_workers`参数用于设置多线程加载数据。引用[4]的标题提到了Dataset多线程加载,但具体内容似乎与DataLoader相关。 关键点: 1. 在PyTorch中,多线程加载数据是通过`DataLoader`的`num_workers`参数实现的。 2. `num_workers`表示使用多少个子进程来加载数据。设置为0表示只在主进程中加载(没有多线程),大于0则表示使用多个子进程。 步骤: 1. 定义数据集(继承自`torch.utils.data.Dataset`)。 2. 创建`DataLoader`实例,并设置`num_workers`参数。 注意: - 在Windows系统中,多进程加载可能会遇到问题,因为Windows使用spawn而不是fork来创建进程。因此,在Windows下,需要将主要代码放在`if __name__ == '__main__':`中,以避免多进程问题。 - 设置`num_workers`的数量通常根据CPU核心数来定,一般设置为CPU核心数或2倍,但具体需要根据实际情况调整。 示例代码(基于引用[3]): ```python from torch.utils.data import Dataset, DataLoader # 自定义数据集类,继承自Dataset class MyDataset(Dataset): def __init__(self, data, targets): self.data = data self.targets = targets def __len__(self): return len(self.data) def __getitem__(self, idx): sample = self.data[idx] label = self.targets[idx] return sample, label # 假设我们有一些数据和标签 data = ... # 你的数据 targets = ... # 你的标签 # 创建数据集实例 dataset = MyDataset(data, targets) # 创建DataLoader,设置num_workers为2(表示使用2个子进程加载数据) dataloader = DataLoader(dataset, batch_size=32, shuffle=True, num_workers=2) ``` 引用[1]中提供的torchvision.datasets加载MNIST的示例也使用了`num_workers=2`。 另外,引用[4]提到“Dataset多线程加载数据,而不是在DataLoader”,但根据其内容,似乎还是在讨论DataLoader的配置。实际上,在PyTorch中,多线程加载是在DataLoader中实现的,而不是在Dataset内部。Dataset类本身是单线程的,但是DataLoader通过多个worker(每个worker是一个进程)来并行调用Dataset的`__getitem__`方法,从而加速数据加载。 因此,总结如下: - 使用`DataLoader`并设置`num_workers`大于0即可实现多线程(实际上是多进程)加载数据。 - 每个worker进程会独立地加载数据,然后将批处理数据通过进程间通信传递给主进程。 注意事项: - 当使用多进程加载时,Dataset对象会被复制到每个worker进程中。因此,如果数据集很大,可能会占用较多内存。 - 在Unix-like系统(如Linux)上,由于使用fork创建进程,所以通常不会出现问题。但在Windows上,由于使用spawn,需要确保Dataset的定义是可以被pickle的,并且将主要代码放在main块中。 示例(适用于Windows): ```python if __name__ == '__main__': # 创建DataLoader等代码 dataloader = DataLoader(dataset, batch_size=32, shuffle=True, num_workers=2) # 训练循环等 ``` 性能优化: - 如果数据加载是瓶颈(比如从磁盘读取大量小文件),可以增加`num_workers`的数量。 - 但注意,过多的worker可能会因为进程间通信的开销而降低性能,也可能导致内存不足。 因此,用户需要根据硬件配置和数据集特点调整`num_workers`的值。 引用文献: [^1]: 使用torchvision.datasets加载MNIST数据集,并设置num_workers=2 [^3]: DataLoader的参数num_workers用于多线程加载 [^4]: 标题提到Dataset多线程加载,但内容与DataLoader相关 相关问题: 1. 如何确定PyTorch中DataLoader的num_workers的最佳值? 2. 在Windows系统下使用PyTorch多进程加载数据有哪些注意事项? 3. PyTorch多进程加载数据时如何避免内存泄漏? 4. 除了num_workers,还有哪些方法可以优化PyTorch数据加载速度?</think>在 PyTorch 中,使用多线程加载数据集主要通过 `DataLoader` 的 `num_workers` 参数实现。以下是详细方法和步骤: ### 1. 使用 `DataLoader` 的 `num_workers` 参数(推荐方法) 这是最常用的多线程加载方式,通过设置 `num_workers` 参数指定并行加载数据的子进程数量: ```python from torch.utils.data import DataLoader, Dataset # 1. 创建自定义数据集类(继承自Dataset) class MyDataset(Dataset): def __init__(self, data, targets): self.data = data self.targets = targets def __len__(self): return len(self.data) def __getitem__(self, idx): return self.data[idx], self.targets[idx] # 2. 实例化数据集 dataset = MyDataset(data, targets) # 3. 创建DataLoader并启用多线程加载 dataloader = DataLoader( dataset, batch_size=32, # 每批数据量 shuffle=True, # 是否打乱数据顺序 num_workers=4, # 关键参数:使用4个子进程加载数据 pin_memory=True # 加速GPU数据传输(如果使用GPU) ) ``` **关键参数说明**: - `num_workers`:指定并行加载数据的子进程数量(设为0表示主进程单线程加载) - 最佳值通常为CPU核心数(如4核CPU设为4)或2倍核心数 - `pin_memory=True` 可加速GPU数据传输(当使用CUDA时) ### 2. 使用 `torchvision.datasets` 内置数据集 对于常见数据集(如MNIST、CIFAR),可直接使用内置方法: ```python import torchvision.datasets as datasets import torchvision.transforms as transforms # 1. 定义数据预处理 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) # 2. 加载数据集(自动下载) trainset = datasets.MNIST( root='./data', # 存储路径 train=True, # 训练集 download=True, # 自动下载 transform=transform # 数据预处理 ) # 3. 创建多线程DataLoader trainloader = DataLoader( trainset, batch_size=64, shuffle=True, num_workers=4, # 使用4个线程 pin_memory=True ) ``` ### 3. 高级优化技巧 1. **预取数据**(Prefetching): ```python dataloader = DataLoader( dataset, num_workers=4, prefetch_factor=2 # 每个worker预取2个批次 ) ``` 2. **持久化worker**(避免重复创建进程): ```python dataloader = DataLoader( dataset, num_workers=4, persistent_workers=True # 保持worker进程活跃 ) ``` 3. **自定义多线程加载逻辑**(高级用法): ```python from torch.utils.data import DataLoader, Dataset import concurrent.futures class ParallelDataset(Dataset): def __init__(self, data): self.data = data self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=4) def __getitem__(self, idx): # 在线程池中执行加载任务 future = self.executor.submit(self._load_item, idx) return future.result() def _load_item(self, idx): # 实际数据加载逻辑 return self.data[idx] ``` ### 注意事项 1. **Windows系统限制**: - 需将主要代码放在 `if __name__ == '__main__':` 中 - 避免使用 `fork` 启动方式(PyTorch默认使用 `spawn`) 2. **资源管理**: - `num_workers` 过大可能导致内存溢出 - 监控CPU利用率(目标:80-90%) 3. **数据顺序保证**: - 当 `shuffle=True` 时,每个epoch会自动重置采样器 - 使用 `worker_init_fn` 可为每个worker设置独立随机种子 ```python def set_worker_seed(worker_id): worker_seed = torch.initial_seed() % 2**32 numpy.random.seed(worker_seed) random.seed(worker_seed) dataloader = DataLoader( dataset, num_workers=4, worker_init_fn=set_worker_seed ) ``` ### 性能对比 | 配置方式 | 数据加载速度 | CPU利用率 | 内存占用 | |---------|------------|----------|---------| | `num_workers=0` | 基准速度 | 20-30% | 低 | | `num_workers=4` | 3-5倍加速 | 70-90% | 中等 | | `num_workers=8` | 可能下降 | 100%+ | 高 | > **最佳实践**:从 `num_workers=CPU核心数` 开始测试,逐步增加直到性能不再提升[^1][^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值