詳解如何使用Pytorch進(jìn)行多卡訓(xùn)練
Python PyTorch深度學(xué)習(xí)框架
PyTorch是一個(gè)基于Python的深度學(xué)習(xí)框架,它支持使用CPU和GPU進(jìn)行高效的神經(jīng)網(wǎng)絡(luò)訓(xùn)練。
在大規(guī)模任務(wù)中,需要使用多個(gè)GPU來加速訓(xùn)練過程。
數(shù)據(jù)并行
“數(shù)據(jù)并行”是一種常見的使用多卡訓(xùn)練的方法,它將完整的數(shù)據(jù)集拆分成多份,每個(gè)GPU負(fù)責(zé)處理其中一份,在完成前向傳播和反向傳播后,把所有GPU的誤差累積起來進(jìn)行更新。數(shù)據(jù)并行的代碼結(jié)構(gòu)如下:
import torch.nn as nn import torch.optim as optim import torch.utils.data as data import torch.distributed as dist import torch.multiprocessing as mp # 定義網(wǎng)絡(luò)模型 class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(3, 32, kernel_size=5) self.relu = nn.ReLU() self.pool = nn.MaxPool2d(kernel_size=2, stride=2) self.fc1 = nn.Linear(4608, 64) self.fc2 = nn.Linear(64, 10) def forward(self, x): x = self.conv1(x) x = self.relu(x) x = self.pool(x) x = x.view(-1, 4608) x = self.fc1(x) x = self.relu(x) x = self.fc2(x) return x # 定義訓(xùn)練函數(shù) def train(gpu, args): rank = gpu dist.init_process_group(backend='nccl', init_method='env://', world_size=args.world_size, rank=rank) torch.cuda.set_device(gpu) train_loader = data.DataLoader(...) model = Net() model = nn.parallel.DistributedDataParallel(model, device_ids=[gpu]) criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(model.parameters(), lr=0.01) for epoch in range(args.epochs): epoch_loss = 0.0 for i, (inputs, labels) in enumerate(train_loader): inputs, labels = inputs.cuda(), labels.cuda() optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() epoch_loss += loss.item() print('GPU %d Loss: %.3f' % (gpu, epoch_loss)) # 主函數(shù) if __name__ == '__main__': mp.set_start_method('spawn') args = parser.parse_args() args.world_size = args.num_gpus * args.nodes mp.spawn(train, args=(args,), nprocs=args.num_gpus, join=True)
首先,我們需要在主進(jìn)程中使用torch.distributed.launch啟動(dòng)多個(gè)子進(jìn)程。每個(gè)子進(jìn)程被分配一個(gè)GPU,并調(diào)用train函數(shù)進(jìn)行訓(xùn)練。
在train函數(shù)中,我們初始化進(jìn)程組,并將模型以及優(yōu)化器包裝成DistributedDataParallel對(duì)象,然后像CPU上一樣訓(xùn)練模型即可。在數(shù)據(jù)并行的過程中,模型和優(yōu)化器都會(huì)被復(fù)制到每個(gè)GPU上,每個(gè)GPU只負(fù)責(zé)處理一部分的數(shù)據(jù)。所有GPU上的模型都參與誤差累積和梯度更新。
模型并行
“模型并行”是另一種使用多卡訓(xùn)練的方法,它將同一個(gè)網(wǎng)絡(luò)分成多段,不同段分布在不同的GPU上。每個(gè)GPU只運(yùn)行其中的一段網(wǎng)絡(luò),并利用前后傳播相互連接起來進(jìn)行訓(xùn)練。代碼結(jié)構(gòu)如下:
import torch.nn as nn import torch.optim as optim import torch.multiprocessing as mp import torch.distributed as dist # 定義模型段 class SubNet(nn.Module): def __init__(self, in_features, out_features): super(SubNet, self).__init__() self.linear = nn.Linear(in_features, out_features) def forward(self, x): return self.linear(x) # 定義整個(gè)模型 class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.subnets = nn.ModuleList([ SubNet(1024, 512), SubNet(512, 256), SubNet(256, 100) ]) def forward(self, x): for subnet in self.subnets: x = subnet(x) return x # 定義訓(xùn)練函數(shù) def train(subnet_id, args): dist.init_process_group(backend='nccl', init_method='env://', world_size=args.world_size, rank=subnet_id) torch.cuda.set_device(subnet_id) train_loader = data.DataLoader(...) model = Net().cuda() criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(model.parameters(), lr=0.01) for epoch in range(args.epochs): epoch_loss = 0.0 for i, (inputs, labels) in enumerate(train_loader): inputs, labels = inputs.cuda(), labels.cuda() optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward(retain_graph=True) # 梯度保留,用于后續(xù)誤差傳播 optimizer.step() epoch_loss += loss.item() if subnet_id == 0: print('Epoch %d Loss: %.3f' % (epoch, epoch_loss)) # 主函數(shù) if __name__ == '__main__': mp.set_start_method('spawn') args = parser.parse_args() args.world_size = args.num_gpus * args.subnets tasks = [] for i in range(args.subnets): tasks.append(mp.Process(target=train, args=(i, args))) for task in tasks: task.start() for task in tasks: task.join()
在模型并行中,網(wǎng)絡(luò)被分成多個(gè)子網(wǎng)絡(luò),并且每個(gè)GPU運(yùn)行一個(gè)子網(wǎng)絡(luò)。在訓(xùn)練期間,每個(gè)子網(wǎng)絡(luò)的輸出會(huì)作為下一個(gè)子網(wǎng)絡(luò)的輸入。這需要在誤差反向傳播時(shí),將不同GPU上計(jì)算出來的梯度加起來,并再次分發(fā)到各個(gè)GPU上。
在代碼實(shí)現(xiàn)中,我們定義了三個(gè)子網(wǎng)(SubNet),每個(gè)子網(wǎng)有不同的輸入輸出規(guī)模。在train函數(shù)中,我們初始化進(jìn)程組和模型,然后像CPU上一樣進(jìn)行多次迭代訓(xùn)練即可。在反向傳播時(shí),將梯度保留并設(shè)置retain_graph為True,用于后續(xù)誤差傳播。
以上就是詳解如何使用Pytorch進(jìn)行多卡訓(xùn)練的詳細(xì)內(nèi)容,更多關(guān)于Pytorch進(jìn)行多卡訓(xùn)練的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Pytorch轉(zhuǎn)onnx、torchscript方式
- Pytorch通過保存為ONNX模型轉(zhuǎn)TensorRT5的實(shí)現(xiàn)
- Pytorch模型轉(zhuǎn)onnx模型實(shí)例
- 利用Pytorch實(shí)現(xiàn)ResNet網(wǎng)絡(luò)構(gòu)建及模型訓(xùn)練
- Pytorch實(shí)現(xiàn)ResNet網(wǎng)絡(luò)之Residual Block殘差塊
- PyTorch常用函數(shù)torch.cat()中dim參數(shù)使用說明
- PyTorch模型轉(zhuǎn)換為ONNX格式實(shí)現(xiàn)過程詳解
相關(guān)文章
11行Python代碼實(shí)現(xiàn)解密摩斯密碼
摩爾斯電碼是一種時(shí)通時(shí)斷的信號(hào)代碼,通過不同的排列順序來表達(dá)不同的英文字母、數(shù)字和標(biāo)點(diǎn)符號(hào)。本文將通過Python代碼來實(shí)現(xiàn)解密摩斯密碼,感興趣的可以學(xué)習(xí)一下2022-04-04Python代理抓取并驗(yàn)證使用多線程實(shí)現(xiàn)
這里沒有使用隊(duì)列只是采用多線程分發(fā)對(duì)代理量不大的網(wǎng)頁還行但是幾百幾千性能就很差了,感興趣的朋友可以了解下,希望對(duì)你有所幫助2013-05-05Python實(shí)現(xiàn)向PPT中插入表格與圖片的方法詳解
這篇文章將帶大家學(xué)習(xí)一下如何在PPT中插入表格與圖片以及在表格中插入內(nèi)容,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-05-05一篇文章搞懂Python Unittest測(cè)試方法的執(zhí)行順序
unittest是Python標(biāo)準(zhǔn)庫自帶的單元測(cè)試框架,是Python版本的JUnit,下面這篇文章主要給大家介紹了如何通過一篇文章搞懂Python Unittest測(cè)試方法的執(zhí)行順序,需要的朋友可以參考下2021-09-09PyQt5實(shí)現(xiàn)界面(頁面)跳轉(zhuǎn)的示例代碼
這篇文章主要介紹了PyQt5實(shí)現(xiàn)界面跳轉(zhuǎn)的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04Python新手們?nèi)菀追傅膸讉€(gè)錯(cuò)誤總結(jié)
python語言里面有一些小的坑,特別容易弄混弄錯(cuò),初學(xué)者若不注意的話,很容易坑進(jìn)去,下面我給大家深入解析一些這幾個(gè)坑,希望對(duì)初學(xué)者有所幫助,需要的朋友可以參考學(xué)習(xí),下面來一起看看吧。2017-04-04