<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
如下圖所示:小朋友一個人做4份作業,假設1份需要60min,共需要240min。
這裡的作業就是pytorch中要處理的data。
與此同時,他也可以先花3min把作業分配給3個同夥,大家一起60min做完。最後他再花3min把作業收起來,一共需要66min。
這個小朋友就是主GPU。他的過程是:分發 ->並行運算->結果回收。
這就是pytorch要使用的第一種並行方法:torch.nn.DataParallel
這種方法也稱為單程序多GPU訓練模式:DP模式,這種並行模式下並行的多卡都是由一個程序進行控制。換句話說,在進行梯度的傳播時,是在主GPU上進行的。
採用torch.nn.DataParallel進行多GPU並行訓練時,與其搭配的資料讀取程式碼是:torch.utils.data.DataLoader
train_datasets = customData(train_txt) #建立datasettrain_dataloaders = torch.utils.data.DataLoader(train_datasets,opt.batch_size,num_workers=train_num_workers,shuffle=True) #建立dataloadermodel = efficientnet_b0(num_classes = opt.num_class) #建立modeldevice_list = list(map(int,list(opt.device_id)))print("Using gpu"," ".join([str(v) for v in device_list]))device = device_list[0] #主GPU,也就是分發任務和結果回收的GPU,也是梯度傳播更新的GPUmodel = torch.nn.DataParallel(model,device_ids=device_list)model.to(device)for data in train_dataloaders: model.train(True) inputs, labels = data inputs = Variable(inputs.to(device)) #將資料放到主要GPU labels = Variable(labels.to(device))
這個方法本來是用於多機器多卡(多節點多卡)訓練的,但是也可以用於單機多卡(即將節點數設定為1)訓練。
初始化的程式碼如下,這個一定要寫在最前面。
from torch.utils.data.distributed import 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("Let's 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
這裡需要說明一下引數:
(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訓練內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45