pytorch-gpu,pytorch如何使用gpu加速

  pytorch-gpu,pytorch如何使用gpu加速

  本文主要介绍两种方式来详细讲解pytorch的多GPU训练。通过实例代码详细介绍,具有一定的参考价值。感兴趣的朋友可以参考一下。

  00-1010方法一:torch.nn.DataParallel1 .原理二。常见的支持代码如下。3.优缺点方法二:torch.distributed1 .代码描述

  

目录

  

方法一:torch.nn.DataParallel

  如下图所示:孩子自己做四个作业,假设一个作业需要60分钟,总共需要240分钟。

  这里的作业是要在pytorch中处理的data

  同时他也可以花3分钟把作业分配给三个同伙,大家60分钟一起完成。最后,他又花了3分钟才放下作业,总共花了66分钟。

  这个小朋友就是主GPU.他的过程是:分发 -并行运算-结果回收.

  这是pytorch使用的第一个并行方法:torch.nn.DataParallel.

  这种方法也叫单进程多GPU训练模式:DP模式。在这种并行模式下,所有并行卡都由一个进程控制。换句话说,梯度传播是在主GPU上执行的。

  torch.nn.DataParallel用于多GPU并行训练时,其数据读取代码为:torch.utils.data.DataLoader.

  

1. 原理

  train _ datasets=custom data(train _ txt)# Create dataset train _ data loaders=torch . utils . data . data loader(train _ datasets,opt.batch _ size,Num _ workers=train _ num _ workers,shuffle=true)# Create dataloader model=efficient net _ B0(Num _ classes=opt . Num _ class)# Create model device _ List=List(map(int,List (opt .device _ id))) print(使用GPU , 。join([str(v)for v in device _ list])device=device _ list[0]# main GPU,即分配任务和恢复结果的GPU,它也是GPU model=torch . nn . data parallel(model,device _ ids=device _ list)model . to(device)for train _ data loaders 3360 model . train(true)通过梯度传播更新的输入。Labels=数据输入=变量(inputs.to (device)) #将数据放入主GPU Labels=变量(labels.to (device))

  

2. 常用的配套代码如下

  优点:配置非常方便。缺点:GPU负载不均衡,主GPU负载很大,其他GPU负载很小。

  

3. 优缺点

  

方法二:torch.distributed

  这种方法原本用于多机多卡(多节点多卡)训练,但也可以用于单机多卡(即节点数设为1)训练。

  初始化代码如下。这个一定要写在前面。

  来自torch . utils . data . distributed imp

  ort DistributedSampler

  torch.distributed.init_process_group(backend="nccl")

  这里给出一个简单的demo.py作为说明:

  

import torch

  import torch.nn as nn

  from torch.autograd import Variable

  from torch.utils.data import Dataset, DataLoader

  import os

  from torch.utils.data.distributed import DistributedSampler

  # 1) 初始化

  torch.distributed.init_process_group(backend="nccl")

  input_size = 5

  output_size = 2

  batch_size = 30

  data_size = 90

  # 2) 配置每个进程的gpu

  local_rank = torch.distributed.get_rank()

  print(local_rank,local_rank)

  torch.cuda.set_device(local_rank)

  device = torch.device("cuda", local_rank)

  class RandomDataset(Dataset):

   def __init__(self, size, length):

   self.len = length

   self.data = torch.randn(length, size).to(cuda)

   def __getitem__(self, index):

   return self.data[index]

   def __len__(self):

   return self.len

  dataset = RandomDataset(input_size, data_size)

  # 3)使用DistributedSampler

  rand_loader = DataLoader(dataset=dataset,

   batch_size=batch_size,

   sampler=DistributedSampler(dataset))

  class Model(nn.Module):

   def __init__(self, input_size, output_size):

   super(Model, self).__init__()

   self.fc = nn.Linear(input_size, output_size)

   def forward(self, input):

   output = self.fc(input)

   print(" In Model: input size", input.size(),

   "output size", output.size())

   return output

  model = Model(input_size, output_size)

  # 4) 封装之前要把模型移到对应的gpu

  model.to(device)

  if torch.cuda.device_count() > 1:

   print("Lets use", torch.cuda.device_count(), "GPUs!")

   # 5) 封装

   model = torch.nn.parallel.DistributedDataParallel(model,

   device_ids=[local_rank],

   output_device=local_rank)

  for data in rand_loader:

   if torch.cuda.is_available():

   input_var = data

   else:

   input_var = data

   output = model(input_var)

   print("Outside: input size", input_var.size(), "output_size", output.size())

  (1)启动方式:在torch.distributed当中提供了一个用于启动的程序torch.distributed.launch,此帮助程序可用于为每个节点启动多个进程以进行分布式训练,它在每个训练节点上产生多个分布式训练进程。

  (2)启动命令:

  

CUDA_VISIBLE_DEVICES=1,2,3,4 python -m torch.distributed.launch --nproc_per_node=2 torch_ddp.py

  这里需要说明一下参数:

  

  • CUDA_VISIBLE_DEVICES:设置我们可用的GPU的id
  • torch.distributed.launch:用于启动多节点多GPU的训练
  • nproc_per_node:表示设置的进程数量一般情况设置为可用的GPU数量,即有多少个可用的GPU就设置多少个进程。
  • local rank:关于这个参数的意义,我们将在后面的情形中进行说明。

  (3)一些情形的说明:

  情形1:直接运行上述的命令

  运行的结果如下:

  

local_rank 1
local_rank 0
Let's use 4 GPUs!
Let's use 4 GPUs!
In Model: input size torch.Size([30, 5]) output size torch.Size([30, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([15, 5]) output_size torch.Size([15, 2])
In Model: input size torch.Size([30, 5]) output size torch.Size([30, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([15, 5]) output_size torch.Size([15, 2])

  

  可以看到local rank的输出为0和1,其数量与我们设置的nproc_per_node是一样的,与我们设置的可用GPU的数量是无关的。这里就要说明一下local rank的意义。

  

local rank:表示的是当前的进程在当前节点的编号,因为我们设置了2个进程,因此进程的编号就是0和1

  在很多博客中都直接说明local_rank等于进程内的GPU编号,这种说法实际上是不准确的。这个编号并不是GPU的编号!!

  

  在使用启动命令时,torch.distributed.launch工具会默认地根据nproc_per_node传入local_rank参数,之后再通过下面的代码可以得到local_rank.

  

local_rank = torch.distributed.get_rank()

  因为是默认传入参数local_rank,所以还可以这么写,其输出与torch.distributed.get_rank()相同

  

import argparse

  parser = argparse.ArgumentParser()

  # 注意这个参数,必须要以这种形式指定,即使代码中不使用。因为 launch 工具默认传递该参数

  parser.add_argument("--local_rank", type=int)

  args = parser.parse_args()

  local_rank = args.local_rank

  print(local_rank,args.local_rank)

  情形2:将nproc_per_node设置为4,即将进程数设置为可用的GPU数

  运行结果如下:

  

local_rank 2
local_rank 3
local_rank 1
local_rank 0
Let's use 4 GPUs!
Let's use 4 GPUs!
Let's use 4 GPUs!
Let's use 4 GPUs!
In Model: input size torch.Size([23, 5]) output size torch.Size([23, 2])
Outside: input size torch.Size([23, 5]) output_size torch.Size([23, 2])
In Model: input size torch.Size([23, 5]) output size torch.Size([23, 2])
Outside: input size torch.Size([23, 5]) output_size torch.Size([23, 2])
In Model: input size torch.Size([23, 5]) output size torch.Size([23, 2])
Outside: input size torch.Size([23, 5]) output_size torch.Size([23, 2])
In Model: input size torch.Size([23, 5]) output size torch.Size([23, 2])
Outside: input size torch.Size([23, 5]) output_size torch.Size([23, 2])

  

  可以看到,此时的local_rank共有4个,与进程数相同。并且我们设置的可用GPU的id是1,2,3,4,而local_rank的输出为0,1,2,3,可见local_rank并不是GPU的编号。

  虽然在代码中模型并行的device_ids设置为local_rank,而local_rank为0,1,2,3,但是实际上还是采用可用的GPU:1,2,3,4。可以通过nvidia-smi来查看,PID为86478,86479,86480,864782。

  

model = torch.nn.parallel.DistributedDataParallel(model,

   device_ids=[local_rank],

   output_device=local_rank)

  

  情形3:将nproc_per_node设置为4,但是不设置可用的GPU ID

  

python -m torch.distributed.launch --nproc_per_node=4 ddp.py

  此时我们再使用nvidia-smi来查看GPU的使用情况,如下。可以看到此时使用的GPU就是local rank的id。相比于情形2,我们可以总结:

  

当没有设置可用的GPU ID时,所采用的GPU id就等于local rank的id。本质上是将进程的编号作为GPU编号使用,因此local_rank等于进程的编号这个定义是不变的。

  当设置可用的GPU ID,所采用的GPU id就等于GPU id。

  

  

  情形4:将nproc_per_node设置为5,即超出了可以用的GPU数

  输出结果如下,可以看到是报错的,因为进程数超出了可以用的GPU数量

  

local_rank 3
local_rank 2
local_rank 4
local_rank 1
local_rank 0
THCudaCheck FAIL file=/pytorch/torch/csrc/cuda/Module.cpp line=59 error=101 : invalid device ordinal
Traceback (most recent call last):
File "ddp.py", line 18, in <module>
torch.cuda.set_device(local_rank)
File "/home/yckj3822/anaconda3/lib/python3.6/site-packages/torch/cuda/__init__.py", line 281, in set_device
torch._C._cuda_setDevice(device)
RuntimeError: cuda runtime error (101) : invalid device ordinal at /pytorch/torch/csrc/cuda/Module.cpp:59

  

  到此这篇关于详解pytorch的多GPU训练的两种方式的文章就介绍到这了,更多相关pytorch的多GPU训练内容请搜索盛行IT软件开发工作室以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT软件开发工作室!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: