Pytorch 高效使用GPU的操作

前言

深度学习涉及很多向量或多矩阵运算,如矩阵相乘、矩阵相加、矩阵-向量乘法等。深层模型的算法,如BP,Auto-Encoder,CNN等,都可以写成矩阵运算的形式,无须写成循环运算。然而,在单核CPU上执行时,矩阵运算会被展开成循环的形式,本质上还是串行执行。GPU(Graphic Process Units,图形处理器)的众核体系结构包含几千个流处理器,可将矩阵运算并行化执行,大幅缩短计算时间。随着NVIDIA、AMD等公司不断推进其GPU的大规模并行架构,面向通用计算的GPU已成为加速可并行应用程序的重要手段。得益于GPU众核(many-core)体系结构,程序在GPU系统上的运行速度相较于单核CPU往往提升几十倍乃至上千倍。

目前,GPU已经发展到了较为成熟的阶段。利用GPU来训练深度神经网络,可以充分发挥其数以千计计算核心的能力,在使用海量训练数据的场景下,所耗费的时间大幅缩短,占用的服务器也更少。如果对适当的深度神经网络进行合理优化,一块GPU卡相当于数十甚至上百台CPU服务器的计算能力,因此GPU已经成为业界在深度学习模型训练方面的首选解决方案。

如何使用GPU?现在很多深度学习工具都支持GPU运算,使用时只要简单配置即可。Pytorch支持GPU,可以通过to(device)函数来将数据从内存中转移到GPU显存,如果有多个GPU还可以定位到哪个或哪些GPU。Pytorch一般把GPU作用于张量(Tensor)或模型(包括torch.nn下面的一些网络模型以及自己创建的模型)等数据结构上。

单GPU加速

使用GPU之前,需要确保GPU是可以使用,可通过torch.cuda.is_available()的返回值来进行判断。返回True则具有能够使用的GPU。

通过torch.cuda.device_count()可以获得能够使用的GPU数量。

如何查看平台GPU的配置信息?在命令行输入命令nvidia-smi即可 (适合于Linux或Windows环境)。图5-13是GPU配置信息样例,从中可以看出共有2个GPU。

图 GPU配置信息

把数据从内存转移到GPU,一般针对张量(我们需要的数据)和模型。 对张量(类型为FloatTensor或者是LongTensor等),一律直接使用方法.to(device)或.cuda()即可。

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#或device = torch.device("cuda:0")
device1 = torch.device("cuda:1")
for batch_idx, (img, label) in enumerate(train_loader):
  img=img.to(device)
  label=label.to(device)

对于模型来说,也是同样的方式,使用.to(device)或.cuda来将网络放到GPU显存。

#实例化网络
model = Net()
model.to(device)  #使用序号为0的GPU
#或model.to(device1) #使用序号为1的GPU

多GPU加速

这里我们介绍单主机多GPUs的情况,单机多GPUs主要采用的DataParallel函数,而不是DistributedParallel,后者一般用于多主机多GPUs,当然也可用于单机多GPU。

使用多卡训练的方式有很多,当然前提是我们的设备中存在两个及以上的GPU。

使用时直接用model传入torch.nn.DataParallel函数即可,如下代码:

#对模型

net = torch.nn.DataParallel(model)

这时,默认所有存在的显卡都会被使用。

如果你的电脑有很多显卡,但只想利用其中一部分,如只使用编号为0、1、3、4的四个GPU,那么可以采用以下方式:

#假设有4个GPU,其id设置如下
device_ids =[0,1,2,3]
#对数据
input_data=input_data.to(device=device_ids[0])
#对于模型
net = torch.nn.DataParallel(model)
net.to(device)

或者

os.environ["CUDA_VISIBLE_DEVICES"] = ','.join(map(str, [0,1,2,3]))

net = torch.nn.DataParallel(model)

其中CUDA_VISIBLE_DEVICES 表示当前可以被Pytorch程序检测到的GPU。

下面为单机多GPU的实现代码。

背景说明

这里使用波士顿房价数据为例,共506个样本,13个特征。数据划分成训练集和测试集,然后用data.DataLoader转换为可批加载的方式。采用nn.DataParallel并发机制,环境有2个GPU。当然,数据量很小,按理不宜用nn.DataParallel,这里只是为了说明使用方法。

加载数据

boston = load_boston()
X,y  = (boston.data, boston.target)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
#组合训练数据及标签
myset = list(zip(X_train,y_train))

把数据转换为批处理加载方式批次大小为128,打乱数据

from torch.utils import data
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
dtype = torch.FloatTensor
train_loader = data.DataLoader(myset,batch_size=128,shuffle=True)

定义网络

class Net1(nn.Module):
  """
  使用sequential构建网络,Sequential()函数的功能是将网络的层组合到一起
  """
  def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
    super(Net1, self).__init__()
    self.layer1 = torch.nn.Sequential(nn.Linear(in_dim, n_hidden_1))
    self.layer2 = torch.nn.Sequential(nn.Linear(n_hidden_1, n_hidden_2))
    self.layer3 = torch.nn.Sequential(nn.Linear(n_hidden_2, out_dim))

  def forward(self, x):
    x1 = F.relu(self.layer1(x))
    x1 = F.relu(self.layer2(x1))
    x2 = self.layer3(x1)
    #显示每个GPU分配的数据大小
    print("\tIn Model: input size", x.size(),"output size", x2.size())
    return x2

把模型转换为多GPU并发处理格式

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#实例化网络
model = Net1(13, 16, 32, 1)
if torch.cuda.device_count() > 1:
  print("Let's use", torch.cuda.device_count(), "GPUs")
  # dim = 0 [64, xxx] -> [32, ...], [32, ...] on 2GPUs
  model = nn.DataParallel(model)
model.to(device)

运行结果

Let's use 2 GPUs
DataParallel(
(module): Net1(
(layer1): Sequential(
(0): Linear(in_features=13, out_features=16, bias=True)
)
(layer2): Sequential(
(0): Linear(in_features=16, out_features=32, bias=True)
)
(layer3): Sequential(
(0): Linear(in_features=32, out_features=1, bias=True)
)
)
)

选择优化器及损失函数

optimizer_orig = torch.optim.Adam(model.parameters(), lr=0.01)

loss_func = torch.nn.MSELoss()

模型训练,并可视化损失值

from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter(log_dir='logs')
for epoch in range(100):
  model.train()
  for data,label in train_loader:
    input = data.type(dtype).to(device)
    label = label.type(dtype).to(device)
    output = model(input)
    loss = loss_func(output, label)
    # 反向传播
    optimizer_orig.zero_grad()
    loss.backward()
    optimizer_orig.step()
    print("Outside: input size", input.size() ,"output_size", output.size())
  writer.add_scalar('train_loss_paral',loss, epoch)

运行的部分结果

In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1])
In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1])
Outside: input size torch.Size([128, 13]) output_size torch.Size([128, 1])
In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1])
In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1])
Outside: input size torch.Size([128, 13]) output_size torch.Size([128, 1])

从运行结果可以看出,一个批次数据(batch-size=128)拆分成两份,每份大小为64,分别放在不同的GPU上。此时用GPU监控也可发现,两个GPU都同时在使用。

8. 通过web查看损失值的变化情况

图 并发运行训练损失值变化情况

图形中出现较大振幅,是由于采用批次处理,而且数据没有做任何预处理,对数据进行规范化应该更平滑一些,大家可以尝试一下。

单机多GPU也可使用DistributedParallel,它多用于分布式训练,但也可以用在单机多GPU的训练,配置比使用nn.DataParallel稍微麻烦一点,但是训练速度和效果更好一点。具体配置为:

#初始化使用nccl后端
torch.distributed.init_process_group(backend="nccl")
#模型并行化
model=torch.nn.parallel.DistributedDataParallel(model)

单机运行时使用下面方法启动

python -m torch.distributed.launch main.py

使用GPU注意事项

使用GPU可以提升我们训练的速度,如果使用不当,可能影响使用效率,具体使用时要注意以下几点:

GPU的数量尽量为偶数,奇数的GPU有可能会出现异常中断的情况;

GPU很快,但数据量较小时,效果可能没有单GPU好,甚至还不如CPU;

如果内存不够大,使用多GPU训练的时候可通过设置pin_memory为False,当然使用精度稍微低一点的数据类型有时也效果。

以上这篇Pytorch 高效使用GPU的操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • PyTorch-GPU加速实例

    硬件:NVIDIA-GTX1080 软件:Windows7.python3.6.5.pytorch-gpu-0.4.1 一.基础知识 将数据和网络都推到GPU,接上.cuda() 二.代码展示 import torch import torch.nn as nn import torch.utils.data as Data import torchvision # torch.manual_seed(1) EPOCH = 1 BATCH_SIZE = 50 LR = 0.001 DOWNLOA

  • pytorch中 gpu与gpu、gpu与cpu 在load时相互转化操作

    问题描述 有时在加载已训练好的模型时,会出现 out of memory 的错误提示,但仔细检测使用的GPU卡并没有再用且内存也没有超出. 经查阅发现原来是训练模型时使用的GPU卡和加载时使用的GPU卡不一样导致的.个人感觉,因为pytorch的模型中是会记录有GPU信息的,所以有时使用不同的GPU加载时会报错. 解决方法 gpu之间的相互转换.即,将训练时的gpu卡转换为加载时的gpu卡. torch.load('modelparameters.pth', map_location={'cud

  • pytorch 指定gpu训练与多gpu并行训练示例

    一. 指定一个gpu训练的两种方法: 1.代码中指定 import torch torch.cuda.set_device(id) 2.终端中指定 CUDA_VISIBLE_DEVICES=1 python 你的程序 其中id就是你的gpu编号 二. 多gpu并行训练: torch.nn.DataParallel(module, device_ids=None, output_device=None, dim=0) 该函数实现了在module级别上的数据并行使用,注意batch size要大于G

  • 解决pytorch多GPU训练保存的模型,在单GPU环境下加载出错问题

    背景 在公司用多卡训练模型,得到权值文件后保存,然后回到实验室,没有多卡的环境,用单卡训练,加载模型时出错,因为单卡机器上,没有使用DataParallel来加载模型,所以会出现加载错误. 原因 DataParallel包装的模型在保存时,权值参数前面会带有module字符,然而自己在单卡环境下,没有用DataParallel包装的模型权值参数不带module.本质上保存的权值文件是一个有序字典. 解决方法 1.在单卡环境下,用DataParallel包装模型. 2.自己重写Load函数,灵活.

  • Pytorch 多块GPU的使用详解

    注:本文针对单个服务器上多块GPU的使用,不是多服务器多GPU的使用. 在一些实验中,由于Batch_size的限制或者希望提高训练速度等原因,我们需要使用多块GPU.本文针对Pytorch中多块GPU的使用进行说明. 1. 设置需要使用的GPU编号 import os os.environ["CUDA_VISIBLE_DEVICES"] = "0,4" ids = [0,1] 比如我们需要使用第0和第4块GPU,只用上述三行代码即可. 其中第二行指程序只能看到第1

  • Pytorch 高效使用GPU的操作

    前言 深度学习涉及很多向量或多矩阵运算,如矩阵相乘.矩阵相加.矩阵-向量乘法等.深层模型的算法,如BP,Auto-Encoder,CNN等,都可以写成矩阵运算的形式,无须写成循环运算.然而,在单核CPU上执行时,矩阵运算会被展开成循环的形式,本质上还是串行执行.GPU(Graphic Process Units,图形处理器)的众核体系结构包含几千个流处理器,可将矩阵运算并行化执行,大幅缩短计算时间.随着NVIDIA.AMD等公司不断推进其GPU的大规模并行架构,面向通用计算的GPU已成为加速可并

  • pytorch使用指定GPU训练的实例

    本文适合多GPU的机器,并且每个用户需要单独使用GPU训练. 虽然pytorch提供了指定gpu的几种方式,但是使用不当的话会遇到out of memory的问题,主要是因为pytorch会在第0块gpu上初始化,并且会占用一定空间的显存.这种情况下,经常会出现指定的gpu明明是空闲的,但是因为第0块gpu被占满而无法运行,一直报out of memory错误. 解决方案如下: 指定环境变量,屏蔽第0块gpu CUDA_VISIBLE_DEVICES = 1 main.py 这句话表示只有第1块

  • pytorch 使用单个GPU与多个GPU进行训练与测试的方法

    如下所示: device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")#第一行代码 model.to(device)#第二行代码 首先是上面两行代码放在读取数据之前. mytensor = my_tensor.to(device)#第三行代码 然后是第三行代码.这句代码的意思是将所有最开始读取数据时的tersor变量copy一份到device所指定的GPU上去,之后的运算都在GPU上

  • pytorch快速搭建神经网络_Sequential操作

    之前用Class类来搭建神经网络 class Neuro_net(torch.nn.Module): """神经网络""" def __init__(self, n_feature, n_hidden_layer, n_output): super(Neuro_net, self).__init__() self.hidden_layer = torch.nn.Linear(n_feature, n_hidden_layer) self.outp

  • Tensorflow全局设置可见GPU编号操作

    笔者需要tensorflow仅运行在一个GPU上(机器本身有多GPU),而且需要依据系统参数动态调节,故无法简单使用CUDA_VISIBLE_DEVICES. 一种方式是全局使用tf.device函数生成的域,但设备号需要在绘制Graph前指定,仍然不够灵活. 查阅文档发现config的GPUOptions中的visible_device_list可以定义GPU编号从visible到virtual的映射,即可以设置tensorflow可见的GPU device,从而全局设置了tensorflow

  • pytorch 两个GPU同时训练的解决方案

    使用场景 我有两个GPU卡.我希望我两个GPU能并行运行两个网络模型. 代码 错误代码1: #对于0号GPU os.environ['CUDA_VISIBLE_DEVICES']='0,1' device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") #对于1号GPU os.environ['CUDA_VISIBLE_DEVICES']='0,1' device = torch.de

  • 详解pytorch的多GPU训练的两种方式

    目录 方法一:torch.nn.DataParallel 1. 原理 2. 常用的配套代码如下 3. 优缺点 方法二:torch.distributed 1. 代码说明 方法一:torch.nn.DataParallel 1. 原理 如下图所示:小朋友一个人做4份作业,假设1份需要60min,共需要240min. 这里的作业就是pytorch中要处理的data. 与此同时,他也可以先花3min把作业分配给3个同伙,大家一起60min做完.最后他再花3min把作业收起来,一共需要66min. 这个

  • Pytorch 统计模型参数量的操作 param.numel()

    param.numel() 返回param中元素的数量 统计模型参数量 num_params = sum(param.numel() for param in net.parameters()) print(num_params) 补充:Pytorch 查看模型参数 Pytorch 查看模型参数 查看利用Pytorch搭建模型的参数,直接看程序 import torch # 引入torch.nn并指定别名 import torch.nn as nn import torch.nn.functio

  • pytorch 实现变分自动编码器的操作

    本来以为自动编码器是很简单的东西,但是也是看了好多资料仍然不太懂它的原理.先把代码记录下来,有时间好好研究. 这个例子是用MNIST数据集生成为例子 # -*- coding: utf-8 -*- """ Created on Fri Oct 12 11:42:19 2018 @author: www """ import os import torch from torch.autograd import Variable import tor

随机推荐