从零搭建Pytorch模型教程(七)单机多卡和多机多卡训练

前言

本文主要介绍单机多卡训练和多机多卡训练的实现方法和一些注意事项。其中单机多卡训练介绍两种实现方式,一种是DP方式,一种是DDP方式。多机多卡训练主要介绍两种实现方式,一种是通过horovod库,一种是DDP方式。

单机单卡训练

前面我们已经介绍了一个完整的训练流程,但这里由于要介绍单机多卡和多机多卡训练的代码,为了能更好地理解它们之间的区别,这里先放一个单机单卡也就是一般情况下的代码流程。

import torch

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
train_dataset = ...
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=...)

model = ...
optimizer = optim.SGD(model.parameters())

for epoch in range(opt.num_epoch):
   for i, (input, target) in enumerate(train_loader):
      input= input.to(device)
      target = target.to(device)
      ...
      output = model(input)
      loss = criterion(output, target)
      ...
      optimizer.zero_grad()
      loss.backward()
      optimizer.step()

单机多卡训练

单机多卡训练的部分有两种实现方式,一种是DP方式,一种是DDP方式。

nn.DataParallel(DP)
DP方式比较简单,仅仅通过nn.DataParallel对网络进行处理即可。

其它部分基本与单机单卡训练流程相同。

import torch

train_dataset = ...
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=...)

model = ...
model = nn.DataParallel(model.to(device), device_ids=None, output_device=None)
optimizer = optim.SGD(model.parameters())

for epoch in range(opt.num_epoch):
for i, (input, target) in enumerate(train_loader):
input= input.cuda()
target = target.cuda()
...
output = model(input)
loss = criterion(output, target)
...
optimizer.zero_grad()
loss.backward()
optimizer.step()

上面唯一关键的一句是在定义model后,使用nn.DataParallel把模型放到各个GPU上。

其中,device_dis有几种设置方式,如果设置为None, 如下几行源码所示,默认使用所有gpu

#nn.DataParallel中的源码
if device_ids is None:
device_ids = list(range(torch.cuda.device_count()))
if output_device is None:
output_device = device_ids[0
也可以手动指定用哪几个gpu。如下所示

gpus = [0, 1, 2, 3]
torch.cuda.set_device('cuda:{}'.format(gpus[0]))
model = nn.DataParallel(model.to(device), device_ids=None, output_device=gpus[0]

DDP方式

上面DP是比较简单的单机多卡的实现方式,但DDP是更高效的方式,不过实现要多几行代码。

import torch
import argparse
import torch.distributed as dist

parser = argparse.ArgumentParser()
parser.add_argument('--local_rank', default=-1, type=int,
help='node rank for distributed training')
opt = parser.parse_args()

初始化GPU通信方式(NCCL)和参数的获取方式(env代表通过环境变量)。

dist.init_process_group(backend='nccl', init_method='env://')

torch.cuda.set_device(opt.local_rank)

train_dataset = ...
train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=..., sampler=train_sampler)

#使用 DistributedDataParallel 包装模型,
#它能帮助我们为不同 GPU 上求得的梯度进行 all reduce
#(即汇总不同 GPU 计算所得的梯度,并同步计算结果)。
#all reduce 后不同 GPU 中模型的梯度均为 all reduce 之前各 GPU 梯度的均值。
model = ...
model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank])

optimizer = optim.SGD(model.parameters())

for epoch in range(opt.num_epoch):
for i, (input, target) in enumerate(train_loader):
input= input.cuda()
target = target.cuda()
...
output = model(input)
loss = criterion(output, target)
...
optimizer.zero_grad()
loss.backward()
optimizer.step()

#运行命令
CUDA_VISIBLE_DEVICES=0,1,2,3 python -m torch.distributed.launch --nproc_per_node=4 train.py

下面对这段代码进行解析。

  1. 设置local_rank参数,可以把这个参数理解为进程编号。该参数在运行上面这条指令时就会确定,每块GPU上的该参数都会不一样。

  2. 配置初始化方式,一般有tcp方式和env方式。上面是用的env,下面是用tcp方式用法。

dist.init_process_group(backend='nccl', init_method='tcp://localhost:23456'
  1. 通过local_rank来确定该进程的设备:torch.cuda.set_device(opt.local_rank)

  2. 数据加载部分我们在该教程的第一篇里介绍过,主要时通过torch.utils.data.distributed.DistributedSampler来获取每个gpu上的数据索引,每个gpu根据索引加载对应的数据,组合成一个batch,与此同时Dataloader里的shuffle必须设置为None。

多机多卡训练

多机多卡训练的一般有两种实现方式,一种是上面这个DDP方式,这里我们就不再介绍了,另一种是使用一个额外的库horovod。

Horovod

Horovod是基于Ring-AllReduce方法的深度分布式学习插件,以支持多种流行架构包括TensorFlow、Keras、PyTorch等。这样平台开发者只需要为Horovod进行配置,而不是对每个架构有不同的配置方法。

import torch
import horovod.torch as hvd

hvd.init()

torch.cuda.set_device(hvd.local_rank())

train_dataset = ...
train_sampler = torch.utils.data.distributed.DistributedSampler(
train_dataset, num_replicas=hvd.size(), rank=hvd.rank)

train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=..., sampler=train_sampler)

model = ...
model.cuda()

optimizer = optim.SGD(model.parameters())
optimizer = hvd.DistributedOptimizer(optimizer, named_parameters=model.named_parameters())

hvd.broadcast_parameters(model.state_dict(), root_rank=0)

for epoch in range(opt.num_epoch):
for i, (input, target) in enumerate(train_loader):
input= input.cuda()
target = target.cuda()
...
output = model(input)
loss = criterion(output, target)
...
optimizer.zero_grad()
loss.backward()
optimizer.step()
if hvd.rank()==0print("loss: ")

下面对以上代码进行简单的介绍。

  1. 与DDP相同的是,先初始化,再根据进程设置当前设备,然后使用torch.utils.data.distributed.DistributedSampler来产生每个GPU读取数据的索引。

  2. 不同的是接下来几个操作,horovod不需要使用torch.nn.parallel.DistributedDataParallel,而是通过使用horovod的两个库,通过hvd.DistributedOptimizer和hvd.broadcast_parameters分别对优化器和模型参数进行处理。

  3. 除了训练以外,其它操作基本都在主进程上完成,例如打印信息,保存模型等。通过最后if hvd.rank()==0来判定。

除了DDP和horovod这两种方式实现多机多卡以外,实际上在混合精度训练里的库apex也有对应的多机多卡训练实现方式,但这个我们就留到下一篇混合精度训练和半精度训练中来介绍。

最后

感谢你们的阅读和喜欢,我收藏了很多技术干货,可以共享给喜欢我文章的朋友们,如果你肯花时间沉下心去学习,它们一定能帮到你。

因为这个行业不同于其他行业,知识体系实在是过于庞大,知识更新也非常快。作为一个普通人,无法全部学完,所以我们在提升技术的时候,首先需要明确一个目标,然后制定好完整的计划,同时找到好的学习方法,这样才能更快的提升自己。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

四、AI大模型商业化落地方案

img

五、面试资料

我们学习AI大模型必然是想找到高薪的工作,下面这些面试题都是总结当前最新、最热、最高频的面试题,并且每道题都有详细的答案,面试前刷完这套面试题资料,小小offer,不在话下。
在这里插入图片描述

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

你可以使用PyTorch的`DataParallel`来实现单机多卡训练模型。`DataParallel`会自动将模型复制到每个可用的GPU并行计算,并在反向传播时进行梯度的累积和同步。 下面是一个简单的示例代码,展示了如何使用`DataParallel`来进行单机多卡训练模型: ```python import torch import torch.nn as nn from torch.utils.data import DataLoader # 定义模型 class MyModel(nn.Module): def __init__(self): super(MyModel, self).__init__() self.fc = nn.Linear(10, 1) def forward(self, x): return self.fc(x) # 创建模型实例 model = MyModel() # 设置设备 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = model.to(device) # 多卡训练 if torch.cuda.device_count() > 1: model = nn.DataParallel(model) # 使用DataParallel包装模型 # 定义数据集和数据加载器 dataset = YourDataset() # 自定义数据集 dataloader = DataLoader(dataset, batch_size=64, shuffle=True) # 定义优化器和损失函数 optimizer = torch.optim.SGD(model.parameters(), lr=0.001) criterion = nn.MSELoss() # 训练过程 for epoch in range(num_epochs): for inputs, labels in dataloader: inputs = inputs.to(device) labels = labels.to(device) # 前向传播 outputs = model(inputs) loss = criterion(outputs, labels) # 反向传播和优化 optimizer.zero_grad() loss.backward() optimizer.step() print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item()}") # 保存模型 torch.save(model.state_dict(), "model.pth") ``` 在上述示例中,如果有多个可用的GPU,则`DataParallel`会自动将模型复制到每个可用的GPU并行计算。你可以通过`torch.cuda.device_count()`函数来检查可用的GPU数量。在训练过程中,你只需要像单卡训练一样使用模型即可,`DataParallel`会自动处理数据和梯度的同步。 请确保你的代码在使用`DataParallel`之前将模型移动到正确的设备上,并在训练过程中将数据和标签移动到相同的设备上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值