详解如何使用Pytorch进行多卡训练

作者:实力 时间:2023-08-02 06:43:29 

Python PyTorch深度学习框架

PyTorch是一个基于Python的深度学习框架,它支持使用CPU和GPU进行高效的神经网络训练。

在大规模任务中,需要使用多个GPU来加速训练过程。

数据并行

“数据并行”是一种常见的使用多卡训练的方法,它将完整的数据集拆分成多份,每个GPU负责处理其中一份,在完成前向传播和反向传播后,把所有GPU的误差累积起来进行更新。数据并行的代码结构如下:

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
# 定义网络模型
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
# 定义训练函数
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))
# 主函数
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)

首先,我们需要在主进程中使用torch.distributed.launch启动多个子进程。每个子进程被分配一个GPU,并调用train函数进行训练。

在train函数中,我们初始化进程组,并将模型以及优化器包装成DistributedDataParallel对象,然后像CPU上一样训练模型即可。在数据并行的过程中,模型和优化器都会被复制到每个GPU上,每个GPU只负责处理一部分的数据。所有GPU上的模型都参与误差累积和梯度更新。

模型并行

“模型并行”是另一种使用多卡训练的方法,它将同一个网络分成多段,不同段分布在不同的GPU上。每个GPU只运行其中的一段网络,并利用前后传播相互连接起来进行训练。代码结构如下:

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)
# 定义整个模型
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
# 定义训练函数
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)  # 梯度保留,用于后续误差传播
           optimizer.step()
           epoch_loss += loss.item()
       if subnet_id == 0:
           print('Epoch %d Loss: %.3f' % (epoch, epoch_loss))
# 主函数
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()

在模型并行中,网络被分成多个子网络,并且每个GPU运行一个子网络。在训练期间,每个子网络的输出会作为下一个子网络的输入。这需要在误差反向传播时,将不同GPU上计算出来的梯度加起来,并再次分发到各个GPU上。

在代码实现中,我们定义了三个子网(SubNet),每个子网有不同的输入输出规模。在train函数中,我们初始化进程组和模型,然后像CPU上一样进行多次迭代训练即可。在反向传播时,将梯度保留并设置retain_graph为True,用于后续误差传播。

来源:https://juejin.cn/post/7223728273007558712

标签:Pytorch,多卡训练,训练
0
投稿

猜你喜欢

  • 用CSS3和HTML5五步打造便签效果

    2012-04-25 20:47:51
  • Vue3中的setup语法糖、computed函数、watch函数详解

    2024-04-29 13:09:33
  • ASP获取远程文件大小信息(通过header头信息)

    2010-03-11 21:25:00
  • python如何获取服务器硬件信息

    2023-05-10 18:28:06
  • xmlhttp中运行getResponseHeader出错,提示:The requested header was not found

    2010-03-27 21:47:00
  • CentOS8安装SQLServer2019的过程

    2024-01-21 15:58:01
  • Python实现在tkinter中使用matplotlib绘制图形的方法示例

    2022-12-16 03:43:37
  • sql注入过程详解_动力节点Java学院整理

    2024-01-12 19:43:59
  • python爬虫实战之最简单的网页爬虫教程

    2022-02-06 17:03:36
  • python如何生成密码字典

    2021-12-23 23:08:24
  • python中利用Future对象异步返回结果示例代码

    2021-09-10 06:59:52
  • Python利用wxPython制作股票价格查询工具

    2021-11-25 19:09:52
  • Python脚本实现自动登录校园网

    2023-01-26 09:37:56
  • SQL SERVER调用存储过程小结

    2024-01-23 18:52:27
  • Java开发之Spring连接数据库方法实例分析

    2024-01-26 02:00:54
  • ADSI+ASP添加IP到IIS禁止访问列表中

    2011-04-02 10:42:00
  • SQL Server误区30日谈 第20天 破坏日志备份链之后,需要一个完整备份来重新开始日志链

    2024-01-22 15:39:53
  • python函数的两种嵌套方法使用

    2022-01-14 08:06:58
  • Python数据结构之二叉排序树的定义、查找、插入、构造、删除

    2022-03-03 08:19:51
  • margin双倍边距问题:ie和firefox显示

    2008-09-07 15:05:00
  • asp之家 网络编程 m.aspxhome.com