在进行多卡训练的时候,经常会出现GPU利用率上不来的情况,无法发挥硬件的最大实力。 造成这种现象最有可能的原因是,CPU生成数据的能力,已经跟不上GPU处理数据的能力。


方法一


常见的方法为修改Dataloader里面的线程数量,利用多线程技术提高数据生产能力,但是这种方法提速并不是特别明显。

train_loader = DataLoader(dataset, batch_size,shuffle=True, num_worker=4)

而且windows机器上,num_worker大于0时,有时会出现卡死的情况,这应该是pytorch的bug,因此不是特别建议这种方法。

不过这种方法最简单,还是可以尝试一下更改线程数能否缓解你遇到的问题。nun_worker一般设置为处理器的物理线程数,不宜过大,因为会导致额外的线程开销。

方法二


本文主要介绍第二种方法,也就是Data Prefetcher,最早见于NVIDIA APEX

这里我把代码抠出来了,删除掉了一些不必要的注释,可以将其复用到自己的项目里来。

import torch

class data_prefetcher():
def __init__(self, loader):
self.loader = iter(loader)
self.stream = torch.cuda.Stream()
self.mean = torch.tensor([0.485 * 255, 0.456 * 255, 0.406 * 255]).cuda().view(1,3,1,1)
self.std = torch.tensor([0.229 * 255, 0.224 * 255, 0.225 * 255]).cuda().view(1,3,1,1)
self.preload() def preload(self):
try:
self.next_input, self.next_target = next(self.loader)
except StopIteration:
self.next_input = None
self.next_target = None
return with torch.cuda.stream(self.stream):
self.next_input = self.next_input.cuda(non_blocking=True)
self.next_target = self.next_target.cuda(non_blocking=True)
self.next_input = self.next_input.float()
self.next_input = self.next_input.sub_(self.mean).div_(self.std) def next(self):
torch.cuda.current_stream().wait_stream(self.stream)
input = self.next_input
target = self.next_target
if input is not None:
input.record_stream(torch.cuda.current_stream())
if target is not None:
target.record_stream(torch.cuda.current_stream())
self.preload()
return input, target

首先我们来看初始化函数,在初始化函数中,会直接调用preload,所以当这个对象初始化时,就会生成第一份的输入数据。

核心逻辑也就在预加载函数preload中,其中第13行是从原来的dataloader中取数,这一步和常规数据加载没有差别。有差别的是第19行,这里出现了Stream的概念。

一般来说,CUDA程序默认都运行在同一个Stream上,因此CPU->GPU,GPU->GPU以及GPU->CPU的一系列计算都是在同一个Stream里面串行运行的。 深度学习一般流程是先从dataloader中取数,这里是内存->CPU的运算,然后执行to_device操作,让数据从CPU->GPU,再是GPU->GPU的神经网络计算。

代码19行,使得data_prefetecher这个类是单独运行在一个Stream上的,因此它让数据加载和神经网络计算可以并行执行,也就加速了整体的运行速度。这样做带来的负面结果就是GPU同时在做两项任务,所以显存占用会增加。

这里不知道解释清楚没有,建议去看一下原作者的回答link

另外,重要的是,使用这个方法的时候一定要将Dataloader里面的pin_memory设置为True。

使用方法如下,非常简单,改造前是从dataloader里取数,改造后是将dataloader包在prefetecher里面,从prefetecher里面取数。

train_loader = DataLoader(dataset, batch_size,shuffle=True, num_worker=4,pin_memory=True)
prefetcher = data_prefetcher(train_loader)
input, target = prefetcher.next() while input is not None:
##
前后向计算...
###
input, target = prefetcher.next()

Pytorch Dataloader加速的更多相关文章

  1. pytorch :: Dataloader中的迭代器和生成器应用

    在使用pytorch训练模型,经常需要加载大量图片数据,因此pytorch提供了好用的数据加载工具Dataloader. 为了实现小批量循环读取大型数据集,在Dataloader类具体实现中,使用了迭 ...

  2. [Pytorch]PyTorch Dataloader自定义数据读取

    整理一下看到的自定义数据读取的方法,较好的有一下三篇文章, 其实自定义的方法就是把现有数据集的train和test分别用 含有图像路径与label的list返回就好了,所以需要根据数据集随机应变. 所 ...

  3. pytorch dataloader num_workers

    https://discuss.pytorch.org/t/guidelines-for-assigning-num-workers-to-dataloader/813/5 num_workers 影 ...

  4. pytorch dataloader 取batch_size时候 出现bug

    1.RuntimeError: invalid argument 0: Sizes of tensors must match except in dimension 0. Got 342 and 2 ...

  5. PyTorch DataLoader NumberWorkers Deep Learning Speed Limit Increase

    这意味着训练过程将按顺序在主流程中工作. 即:run.num_workers.   ,此外, ,因此,主进程不需要从磁盘读取数据:相反,这些数据已经在内存中准备好了. 这个例子中,我们看到了20%的加 ...

  6. 【深度学习】Pytorch 学习笔记

    目录 Pytorch Leture 05: Linear Rregression in the Pytorch Way Logistic Regression 逻辑回归 - 二分类 Lecture07 ...

  7. [源码解析] PyTorch 分布式(9) ----- DistributedDataParallel 之初始化

    [源码解析] PyTorch 分布式(9) ----- DistributedDataParallel 之初始化 目录 [源码解析] PyTorch 分布式(9) ----- DistributedD ...

  8. [源码解析] PyTorch 分布式(10)------DistributedDataParallel 之 Reducer静态架构

    [源码解析] PyTorch 分布式(10)------DistributedDataParallel之Reducer静态架构 目录 [源码解析] PyTorch 分布式(10)------Distr ...

  9. [源码解析] PyTorch 分布式(11) ----- DistributedDataParallel 之 构建Reducer

    [源码解析] PyTorch 分布式(11) ----- DistributedDataParallel 之 构建Reducer 目录 [源码解析] PyTorch 分布式(11) ----- Dis ...

随机推荐

  1. [AcWing 795] 前缀和

    点击查看代码 #include<iostream> using namespace std; const int N = 1e5 + 10; int a[N], s[N]; int mai ...

  2. 一次IOS通知推送问题排查全过程

    原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 发现问题 在上周一个将要下班的夜晚,测试突然和我打招呼,说IOS推送的修复更新上线后存在问题,后台报错. 连忙跑到测试那 ...

  3. 一篇文章教你搞懂日志采集利器 Filebeat

    关注「开源Linux」,选择"设为星标" 回复「学习」,有我为您特别筛选的学习资料~ 本文使用的Filebeat是7.7.0的版本,文章将从如下几个方面说明: Filebeat是什 ...

  4. arthas学习图文记录

    Arthas 是阿里开源的 Java 诊断工具.在线排查问题,无需重启:动态跟踪 Java 代码:实时监控 JVM 状态.Arthas 支持 JDK 6+,支持 Linux/Mac/Windows,采 ...

  5. 组织:ISO

    国际标准化组织(ISO)是一个全球性的非政府组织,成立于1947年,总部位于瑞士日内瓦. 该组织负责绝大部分领域(包括军工.石油.船舶等垄断行业)的标准化活动,中国是其正式成员,代表中国参加的国家机构 ...

  6. 无线:SSID

    BSSID,SSID,ESSID区别   SSID(Service Set Identifier)   SSID,AP唯一的ID码,许多人认为可以将SSID写成ESSID,其实不然,SSID是个笼统的 ...

  7. vue设计模式

    vm 的设计模式. mvvm 是 model-view-viewModel 的简写. model 是数据模块,view 是渲染视图,viewModel 是沟通视图和数据模块的桥梁. vue 中使用了哪 ...

  8. python面向对象(封装、多态、反射)

    目录 面向对象之封装 @property 面向对象之多态 面向对象之反射 面向对象之封装 含义 将类中的某些名字按照特殊的书写方式"隐藏"起来,不让外界直接调用,目的是为了不然外界 ...

  9. 每天一个 HTTP 状态码 204

    204 No Content 204 No Content 表示服务器成功地处理了客户端的请求,但是没有任何要响应的内容.API 设计上,在用 PUT 请求更新某个资源成功后,后端可以在 HTTP 响 ...

  10. Java开发学习(二)----IOC、DI入门案例

    一.IOC入门案例 1.1 思路分析 (1)Spring是使用容器来管理bean对象的,那么管什么? 主要管理项目中所使用到的类对象,比如(Service和Dao) (2)如何将被管理的对象告知IOC ...