PyTorch中常用的工具(5)使用GPU加速:CUDA

文章目录

  • 前言
  • 4 使用GPU加速:CUDA
  • 5 小结

前言

在训练神经网络的过程中需要用到很多的工具,最重要的是数据处理、可视化和GPU加速。本章主要介绍PyTorch在这些方面常用的工具模块,合理使用这些工具可以极大地提高编程效率。

由于内容较多,本文分成了五篇文章(1)数据处理(2)预训练模型(3)TensorBoard(4)Visdom(5)CUDA与小结。

整体结构如下:

  • 1 数据处理
    • 1.1 Dataset
    • 1.2 DataLoader
  • 2 预训练模型
  • 3 可视化工具
  • 3.1 TensorBoard
  • 3.2 Visdom
  • 4 使用GPU加速:CUDA
  • 5 小结

全文链接:

  1. PyTorch中常用的工具(1)数据处理
  2. PyTorch常用工具(2)预训练模型
  3. PyTorch中常用的工具(3)TensorBoard
  4. PyTorch中常用的工具(4)Visdom
  5. PyTorch中常用的工具(5)使用GPU加速:CUDA

4 使用GPU加速:CUDA

这部分内容在前面介绍Tensornn.Module时已经有所涉及,这里做一个总结,并深入介绍它的相关应用。

在PyTorch中以下数据结构分为CPU和GPU两个版本。

  • Tensor
  • nn.Module(包括常用的layer、损失函数以及容器Sequential等)。

这些数据结构都带有一个.cuda方法,调用该方法可以将它们转为对应的GPU对象。注意,tensor.cuda会返回一个新对象,这个新对象的数据已经转移到GPU,之前的Tensor还在原来的设备上(CPU)module.cuda会将所有的数据都迁移至GPU,并返回自己。所以module = module.cuda()module.cuda()效果一致。

除了.cuda方法,它们还支持.to(device)方法,通过该方法可以灵活地转换它们的设备类型,同时这种方法也更加适合编写设备兼容的代码,这部分内容将在后文详细介绍。

nn.Module在GPU与CPU之间的转换,本质上还是利用了Tensor在GPU和CPU之间的转换。nn.Module.cuda方法是将nn.Module下的所有参数(包括子module的参数)都转移至GPU,而参数本质上也是Tensor。

下面对.cuda方法举例说明,这部分代码需要读者具有两块GPU设备。

注意:为什么将数据转移至GPU的方法叫做.cuda而不是.gpu,就像将数据转移至CPU调用的方法是.cpu呢?这是因为GPU的编程接口采用CUDA,而目前不是所有的GPU都支持CUDA,只有部分NVIDIA的GPU才支持。PyTorch1.8目前已经支持AMD GPU,并提供了基于ROCm平台的GPU加速,感兴趣的读者可以自行查询相关文档。

In: tensor = t.Tensor(3, 4)# 返回一个新的Tensor,保存在第1块GPU上,原来的Tensor并没有改变tensor.cuda(0)tensor.is_cuda # False
Out: False
In: # 不指定所使用的GPU设备,默认使用第1块GPUtensor = tensor.cuda()tensor.is_cuda # True
Out: True
In: module = nn.Linear(3, 4)module.cuda(device = 1)module.weight.is_cuda # True
Out: True
In: # 使用.to方法,将Tensor转移至第1块GPU上tensor = t.Tensor(3, 4).to('cuda:0')tensor.is_cuda
Out: True
In: class VeryBigModule(nn.Module):def __init__(self):super().__init__()self.GiantParameter1 = t.nn.Parameter(t.randn(100000, 20000)).to('cuda:0')self.GiantParameter2 = t.nn.Parameter(t.randn(20000, 100000)).to('cuda:1')def forward(self, x):x = self.GiantParameter1.mm(x.cuda(0))x = self.GiantParameter2.mm(x.cuda(1))return x

在最后一段代码中,两个Parameter所占用的内存空间都非常大,大约是8GB。如果将这两个Parameter同时放在一块显存较小的GPU上,那么显存将几乎被占满,无法再进行任何其他运算。此时可以通过.to(device_i)将不同的计算划分到不同的GPU中。

下面是在使用GPU时的一些建议。

  • GPU运算很快,但对于很小的运算量来说,它的优势无法被体现。因此,对于一些简单的操作可以直接利用CPU完成。
  • 数据在CPU和GPU之间的传递比较耗时,应当尽量避免。
  • 在进行低精度的计算时,可以考虑使用HalfTensor,它相比于FloatTensor可以节省一半的显存,但是需要注意数值溢出的情况。

注意:大部分的损失函数都属于nn.Module,在使用GPU时,用户经常会忘记使用它的.cuda方法,这在大多数情况下不会报错,因为损失函数本身没有可学习参数(learnable parameters),但在某些情况下会出现问题。为了保险起见,同时也为了代码更加规范,用户应记得调用criterion.cuda,下面举例说明:

In: # 交叉熵损失函数,带权重criterion = t.nn.CrossEntropyLoss(weight=t.Tensor([1, 3]))input = t.randn(4, 2).cuda()target = t.Tensor([1, 0, 0, 1]).long().cuda()# 下面这行会报错,因weight未被转移至GPU# loss = criterion(input, target)# 下面的代码则不会报错criterion.cuda()loss = criterion(input, target)criterion._buffers
Out: OrderedDict([('weight', tensor([1., 3.], device='cuda:0'))])

除了调用对象的.cuda方法,还可以使用torch.cuda.device指定默认使用哪一块GPU,或使用torch.set_default_tensor_type让程序默认使用GPU,不需要手动调用.cuda方法:

In: # 如果未指定使用哪块GPU,则默认使用GPU 0x = t.cuda.FloatTensor(2, 3)# x.get_device() == 0y = t.FloatTensor(2, 3).cuda()# y.get_device() == 0# 指定默认使用GPU 1with t.cuda.device(1):    # 在GPU 1上构建Tensora = t.cuda.FloatTensor(2, 3)# 将Tensor转移至GPU 1b = t.FloatTensor(2, 3).cuda()assert a.get_device() == b.get_device() == 1c = a + bassert c.get_device() == 1z = x + yassert z.get_device() == 0# 手动指定使用GPU 0d = t.randn(2, 3).cuda(0)assert d.get_device() == 0
In: t.set_default_tensor_type('torch.cuda.FloatTensor') # 指定默认Tensor的类型为GPU上的FloatTensora = t.ones(2, 3)a.is_cuda
Out: True

如果服务器具有多个GPU,那么tensor.cuda()方法会将Tensor保存到第一块GPU上,等价于tensor.cuda(0)。如果想要使用第二块GPU,那么需要手动指定tensor.cuda(1),这需要修改大量代码,较为烦琐。这里有以下两种替代方法。

  • 先调用torch.cuda.set_device(1)指定使用第二块GPU,后续的.cuda()都无需更改,切换GPU只需修改这一行代码。

  • 设置环境变量CUDA_VISIBLE_DEVICES,例如export CUDA_VISIBLE_DEVICE=1(下标从0开始,1代表第二块物理GPU),代表着只使用第2块物理GPU,但在程序中这块GPU会被看成是第1块逻辑GPU,此时调用tensor.cuda()会将Tensor转移至第二块物理GPU。CUDA_VISIBLE_DEVICES还可以指定多个GPU,例如export CUDA_VISIBLE_DEVICES=0,2,3,第1、3、4块物理GPU会被映射为第1、2、3块逻辑GPU,此时tensor.cuda(1)会将Tensor转移到第三块物理GPU上。

设置CUDA_VISIBLE_DEVICES有两种方法,一种是在命令行中执行CUDA_VISIBLE_DEVICES=0,1 python main.py,一种是在程序中编写import os;os.environ["CUDA_VISIBLE_DEVICES"] = "2"。如果使用IPython或者Jupyter notebook,那么还可以使用%env CUDA_VISIBLE_DEVICES=1,2设置环境变量。

基于PyTorch本身的机制,用户可能需要编写设备兼容(device-agnostic)的代码,以适应不同的计算环境。在第3章中已经介绍到,可以通过Tensor的device属性指定它加载的设备,同时利用to方法可以很方便地将不同变量加载到不同的设备上。然而,如果要保证同样的代码在不同配置的机器上均能运行,那么编写设备兼容的代码是至关重要的,本节将详细介绍如何编写设备兼容的代码。

首先介绍一下如何指定Tensor加载的设备,这一操作往往通过torch.device()实现,其中device类型包含cpucuda,下面举例说明:

In: # 指定设备,使用CPUt.device('cpu')# 另外一种写法:t.device('cpu',0)
Out: device(type='cpu')
In: # 指定设备,使用第1块GPUt.device('cuda:0')# 另外一种写法:t.device('cuda',0)
Out: device(type='cuda', index=0)
In: # 更加推荐的做法(同时也是设备兼容的):如果用户具有GPU设备,那么使用GPU,否则使用CPUdevice = t.device("cuda" if t.cuda.is_available() else "cpu")print(device)
Out: cuda
In: # 在确定了设备之后,可以将数据与模型利用to方法加载到指定的设备上。x = t.empty((2,3)).to(device)x.device
Out: device(type='cuda', index=0)

对于最常见的数据结构Tensor,它封装好的大部分操作也支持指定加载的设备。当拥有加载在一个设备上的Tensor时,通过torch.Tensor.new_*以及torch.*_like操作可以创建与该Tensor相同类型、相同设备的Tensor,举例说明如下:

In: x_cpu = t.empty(2, device='cpu')print(x_cpu, x_cpu.is_cuda)x_gpu = t.empty(2, device=device)print(x_gpu, x_gpu.is_cuda)
Out: tensor([-3.6448e+08,  4.5873e-41]) Falsetensor([0., 0.], device='cuda:0') True
In: # 使用new_*操作会保留原Tensor的设备属性y_cpu = x_cpu.new_full((3,4), 3.1415)print(y_cpu, y_cpu.is_cuda)y_gpu = x_gpu.new_zeros(3,4)print(y_gpu, y_gpu.is_cuda)
Out: tensor([[3.1415, 3.1415, 3.1415, 3.1415],[3.1415, 3.1415, 3.1415, 3.1415],[3.1415, 3.1415, 3.1415, 3.1415]]) Falsetensor([[0., 0., 0., 0.],[0., 0., 0., 0.],[0., 0., 0., 0.]], device='cuda:0') True
In: # 使用ones_like或zeros_like可以创建与原Tensor大小类别均相同的新Tensorz_cpu = t.ones_like(x_cpu)print(z_cpu, z_cpu.is_cuda)z_gpu = t.zeros_like(x_gpu)print(z_gpu, z_gpu.is_cuda)
Out: tensor([1., 1.]) Falsetensor([0., 0.], device='cuda:0') True

在一些实际应用场景下,代码的可移植性是十分重要的,读者可根据上述内容继续深入学习,在不同场景中灵活运用PyTorch的不同特性编写代码,以适应不同环境的工程需要。

本节主要介绍了如何使用GPU对计算进行加速,同时介绍了如何编写设备兼容的PyTorch代码。在实际应用场景中,仅仅使用CPU或一块GPU是很难满足网络的训练需求的,因此能否使用多块GPU来加速训练呢?

答案是肯定的。自PyTorch 0.2版本后,PyTorch新增了分布式GPU支持。分布式是指有多个GPU在多台服务器上,并行一般指一台服务器上的多个GPU。分布式涉及到了服务器之间的通信,因此比较复杂。幸运的是,PyTorch封装了相应的接口,可以用简单的几行代码实现分布式训练。在训练数据集较大或者网络模型较为复杂时,合理地利用分布式与并行可以加快网络的训练。关于分布式与并行的更多内容将在本书第7章进行详细的介绍。

5 小结

本章介绍了一些工具模块,这些工具有的已经封装在PyTorch之中,有的是独立于PyTorch的第三方模块。这些模块主要涉及数据加载、可视化与GPU加速的相关内容,合理使用这些模块能够极大地提升编程效率。
3,4)
print(y_gpu, y_gpu.is_cuda)


Out: tensor([[3.1415, 3.1415, 3.1415, 3.1415],
[3.1415, 3.1415, 3.1415, 3.1415],
[3.1415, 3.1415, 3.1415, 3.1415]]) False
tensor([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]], device=‘cuda:0’) True


```python
In: # 使用ones_like或zeros_like可以创建与原Tensor大小类别均相同的新Tensorz_cpu = t.ones_like(x_cpu)print(z_cpu, z_cpu.is_cuda)z_gpu = t.zeros_like(x_gpu)print(z_gpu, z_gpu.is_cuda)
Out: tensor([1., 1.]) Falsetensor([0., 0.], device='cuda:0') True

在一些实际应用场景下,代码的可移植性是十分重要的,读者可根据上述内容继续深入学习,在不同场景中灵活运用PyTorch的不同特性编写代码,以适应不同环境的工程需要。

本节主要介绍了如何使用GPU对计算进行加速,同时介绍了如何编写设备兼容的PyTorch代码。在实际应用场景中,仅仅使用CPU或一块GPU是很难满足网络的训练需求的,因此能否使用多块GPU来加速训练呢?

答案是肯定的。自PyTorch 0.2版本后,PyTorch新增了分布式GPU支持。分布式是指有多个GPU在多台服务器上,并行一般指一台服务器上的多个GPU。分布式涉及到了服务器之间的通信,因此比较复杂。幸运的是,PyTorch封装了相应的接口,可以用简单的几行代码实现分布式训练。在训练数据集较大或者网络模型较为复杂时,合理地利用分布式与并行可以加快网络的训练。关于分布式与并行的更多内容将在本书第7章进行详细的介绍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/590736.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023年“中银杯”安徽省网络安全B模块(部分解析)

前言 以下是2023年中银杯安徽省网络安全B模块题目,镜像可以私聊我 B模块安全事件响应/网络安全数据取证/应用安全(400 分) B-1:CMS网站渗透测试 任务环境说明: √服务器场景:Server2206(关…

java SSM拖拉机售后管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM拖拉机售后管理系统是一套完善的web设计系统(系统采用SSM框架进行设计开发,springspringMVCmybatis),对理解JSP java编程开发语言有帮助,系统具有完整的源 代码和数据库,系统主要…

【Python百宝箱】音韵探奇:探索Python中的音频与信号魔法

数字音符:畅游Python音频与信号处理的科技奇境 前言 在数字时代,音频与信号处理不仅仅是专业领域的关键,也成为了科技创新和艺术创作的核心。本文将带领您深入探索Python中多个强大的音频处理库和信号处理工具,从Librosa到Tenso…

raid解析

raid原理是把各个硬盘组成一个组,是磁盘的集合,按照排列组合的方法给raid去不同的名字。 raid 0磁盘 读写性能都提高 在什么情况下使用1快盘raid 0 ? 实际利用率 100% 系统中要不然都做raid 要不然都不做raid 当前6快盘都是raid 但是…

es简单入门

星光下的赶路人star的个人主页 努力努力再努力 文章目录 1、简介2、使用场景3、基本知识4、中文文档和官网链接5、增删改查(php代码)6、基本查询7、HTTP操作7.1 索引操作7.1.1 创建索引 7.2 文档操作7.2.1 创建文档7.2.2 查看文档7.2.3 修改文档7.2.4 修…

NLP:预测新闻类别 - 自然语言处理中嵌入技术

简介 在数字时代,在线新闻内容呈指数级增长,需要有效的分类以增强可访问性和用户体验。先进机器学习技术的出现,特别是在自然语言处理(NLP)领域,为文本数据的自动分类开辟了新的领域。本文[1]探讨了在 NLP …

基于EMD的滚动轴承故障诊断算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1EMD的基本原理 固有模态函数(IMF) 筛分过程 4.2 基于EMD的滚动轴承故障诊断算法 信号预处理 EMD分解 特征提取 故障诊断 5.算法完整程序工程 1.算法运行效…

SpringBoot 实现Execl 导入导出

1、引包 <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>3.0.3</version></dependency><dependency><groupId>cn.afterturn</groupId><artifactId>easy…

A星寻路算法

A星寻路算法简介 A星寻路算法&#xff08;A* Search Algorithm&#xff09;是一种启发式搜索算法&#xff0c;它在图形平面上进行搜索&#xff0c;寻找从起始点到终点的最短路径。A星算法结合了广度优先搜索&#xff08;BFS&#xff09;和最佳优先搜索&#xff08;Best-First S…

MyBatis-注解的方式实现接口声明的方法

基本说明&#xff1a; 说明&#xff1a;我们可以将MonsterMapperjava接口方法在对应的MonsterlMapper.xml文件中实现外&#xff0c;也可以直接组织MonsterMappere.java接口中声明的方法&#xff0c;直接使用注解来实现&#xff0c;可以作为一种补充的机制在项目中使用.…

5-Docker实例-安装redis

1.拉取redis镜像 命令: docker search redis docker pull redis:3.2 [root@centos79 ~]# docker search redis NAME DESCRIPTION STARS OFFICIAL AUTOMATED redis …

【复现】FreeU以及结合stable diffusion

code&#xff1a;GitHub - ChenyangSi/FreeU: FreeU: Free Lunch in Diffusion U-Net 才发现AnimateDiff更新v3了&#xff0c;以及又发了篇CVPR的改进工作&#xff1a; 在这个版本中&#xff0c;我们通过域适配器LoRA对图像模型进行了微调&#xff0c;以便在推理时具有更大的灵…

如何使用 PyTorch 训练 LLM

一、引言 语言模型&#xff08;LLM&#xff09;是一种重要的自然语言处理&#xff08;NLP&#xff09;技术&#xff0c;它通过对大量文本数据进行训练&#xff0c;学习语言的内在结构和语义信息。PyTorch作为一种流行的深度学习框架&#xff0c;具有灵活性和易用性&#xff0c…

MySQL 高级(进阶) SQL 语句

目录 一、实验环境准备 二、MySQL高阶查询 1、语句与命令 2、实验实操 三、MySQL函数 1、语句与命令 2、实验操作 一、实验环境准备 #创建两个数据表&#xff0c;为实验提供环境&#xff1a; use kgc; #选择数据库&#xff0c;有则直接使用 无则按照以下步骤自建即可…

WPF+Halcon 培训项目实战(8-9):WPF+Halcon初次开发

文章目录 前言相关链接项目专栏运行环境匹配图片WPF Halcon组件HSmartWindowControlWPF绑定读取图片运行代码运行结果 抖动问题解决运行结果 绘制矩形绘制图像会消失 绘制对象绑定事件拖动事件 前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原因无非是想…

nginx安装和配置

目录 1.安装 2.配置 3.最小配置说明 4. nginx 默认访问路径 1.安装 使用 epel 源安装 先安装 yum 的扩展包 yum install epel-release -y 再安装 nginx yum install nginx -y 在启动nginx 前先关闭防火墙 systemctl stop firewalld 取消防火墙开机自启 systemctl di…

Self-attention学习笔记(Self Attention、multi-head self attention)

李宏毅机器学习Transformer Self Attention学习笔记记录一下几个方面的内容 1、Self Attention解决了什么问题2、Self Attention 的实现方法以及网络结构Multi-head Self Attentionpositional encoding 3、Self Attention 方法的应用4、Self Attention 与CNN以及RNN对比 1、Se…

基于grpc从零开始搭建一个准生产分布式应用(8) - 01 - 附:GRPC公共库源码

开始前必读&#xff1a;​​基于grpc从零开始搭建一个准生产分布式应用(0) - quickStart​​ common包中的源码&#xff0c;因后续要用所以一次性全建好了。 一、common工程完整结构 二、引入依赖包 <?xml version"1.0" encoding"UTF-8"?> <p…

【linux】cat的基本使用

cat是一个常用的命令&#xff0c;用来显示文本的内容&#xff0c;合并和创建文本文件 类似命令还有显示文件开头的内容&#xff1a; 【linux】head的用法 输出文件开头的内容-CSDN博客 显示文件末尾的内容&#xff1a; 【linux】tail的基本使用-CSDN博客 当我们想到了想要…

Zookeeper-Zookeeper选举源码

看源码方法&#xff1a; 1、先使用&#xff1a;先看官方文档快速掌握框架的基本使用 2、抓主线&#xff1a;找一个demo入手&#xff0c;顺藤摸瓜快速静态看一遍框架的主线源码&#xff0c;画出源码主流程图&#xff0c;切勿一开始就陷入源码的细枝末节&#xff0c;否则会把自…