【分布式训练】基于PyTorch进行多GPU分布式模型训练(补充)

这篇具有很好参考价值的文章主要介绍了【分布式训练】基于PyTorch进行多GPU分布式模型训练(补充)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


简介: 在PyTorch中使用DistributedDataParallel进行多GPU分布式模型训练。
原文链接:https://towardsdatascience.com/distributed-model-training-in-pytorch-using-distributeddataparallel-d3d3864dc2a7

随着以ChatGPT为代表的大模型的不断涌现,如何在合理的时间内训练大模型逐渐成为一个重要的研究课题。为了解决这个问题,越来越多的从业者转向分布式训练。分布式训练是使用多个GPU和/或多个机器训练深度学习模型的技术。分布式训练作业能够克服单GPU内存瓶颈,通过同时利用多个GPU来开发更大,功能更强大的模型。

本文介绍使用torch.nn.parallel.DistributedDataParallel API在纯PyTorch中进行分布式训练的简介。主要内容有:

  • 讨论一般的分布式训练方式,尤其是数据并行化
  • 介绍torch.distDistributedDataParallel的相关功能,并举例说明如何使用它们
  • 测试真实的训练脚本,以节省时间

背景知识

在研究分布式和数据并行之前,需要先了解一些关于分布式训练的背景知识。目前普遍使用的分布式训练基本上有两种不同形式数据并行化模型并行化

  1. 数据并行化中,模型训练作业是在数据上进行分割的。作业中的每个GPU接收到自己独立的数据批处理切片。每个GPU使用这些数据来独立计算梯度更新。例如,如果要使用两个GPU和32的批处理大小,一个GPU将处理前16条记录的向前和向后传播,第二个处理后16条记录的向后和向前传播。这些梯度更新然后在GPU之间同步,一起平均,最后应用到模型(同步步骤在技术上是可选的,但理论上更快的异步更新策略仍是一个活跃的研究领域)。

  2. 模型并行化中,模型训练作业是在模型上进行分割的。工作中的每个GPU接收模型的一个切片,例如它的层的一个子集。例如,一个GPU负责它的输出头,另一个负责输入层,另一个负责中间的隐藏层。

虽然这两种技术各有优缺点,但数据并行化在这两种技术中更容易实现(它不需要了解底层网络架构),因此通常首先尝试这种策略(也可以结合使用这些技术,例如同时使用模型和数据并行化,但这是一个高级主题,不在这里介绍)。

注意:本文是对DistributedDataParallel并行API的介绍,所以不再进一步讨论模型并行化的细节。

数据并行工作原理

第一个被广泛采用的数据并行技术是TensorFlow中的参数服务器策略。这个功能实际上早于TensorFlow的第一个版本,早在2012年google内部的前身DistBelief中就已经实现了。这一策略在下图中得到了很好的说明:
【分布式训练】基于PyTorch进行多GPU分布式模型训练(补充),深度学习与人工智能,分布式,pytorch,多GPU训练,数据并行化,模型并行化
在参数服务器策略中,worker和parameter进程的数量是可变的,每个worker进程在GPU内存中维护自己的模型独立副本。梯度更新计算如下:

  1. 在接收到开始信号后,每个worker process为其特定的批处理slice积累梯度。
  2. 这些worker以扇出的方式将update发送到参数服务器。
  3. 参数服务器会一直等待,直到它们拥有所有worker更新,然后对它们负责的梯度更新参数空间的那部分梯度求平均
  4. 梯度更新被分散到worker上,然后将它们加起来,应用到内存中模型权重的副本上(从而保持worker模型同步)。
  5. 一旦每个worker都应用了更新,新的一批训练就可以开始了。

虽然很容易实现,但是这个策略有一些主要的限制。最重要的一点是每个附加的参数服务器在每个同步步骤中都需要n_workers额外的网络调用——一个O(n)复杂度代价。计算的总体速度取决于最慢的连接,因此基于大参数服务器的模型训练作业在实践中效率非常低,将网络GPU利用率推到50%或以下。

更现代的分布式训练策略废除了参数服务器在DistributedDataParallel并行策略中,每个进程都是一个work进程。每个进程仍然在内存中维护模型权重的完整副本,但是批处理slice梯度更新现在是同步的,并且直接在工作进程本身上平均。这是使用从高性能计算领域借来的技术来实现的:全归约算法all-reduce algorithm
【分布式训练】基于PyTorch进行多GPU分布式模型训练(补充),深度学习与人工智能,分布式,pytorch,多GPU训练,数据并行化,模型并行化
该图显示了全归约算法的一种特定实现方式,即循环全归约。 该算法提供了一种优雅的方式来同步一组进程之间的一组变量(在本例中为张量)的状态。 向量在直接的worker到worker连接的序列中直接传递。 这消除了worker与参数服务器之间的连接所造成的网络瓶颈,从而大大提高了性能。在该方案中,梯度更新计算如下:

  1. 每个 worker 维护它自己的模型权重副本它自己的数据集副本
  2. 在接收到开始信号后,每个工作进程从数据集中提取一个分离的批处理,并为该批处理计算一个梯度。
  3. worker使用all-reduce算法来同步他们各自的梯度,本地计算所有节点上相同的平均梯度
  4. 每个worker都将梯度更新应用到它的本地模型副本上。
  5. 下一批训练开始。

在2017年百度的一篇论文《Bringing HPC Techniques to Deep Learning》中,这种全精简策略被提出。它的重要之处在于它基于众所周知的HPC技术以及长期存在的开源实现。All-reduce包含在消息传递接口(MPI)的标准中,这就是为什么PyTorch不少于三个不同的后端实现: Open MPI、NVIDIA NCCL和Facebook Gloo(一般情况下建议使用NVIDIA NCCL)

数据分发流程

1. 流程初始化

必须要知道的一点是将训练脚本修改为使用DistributedDataParallel并行策略并不是简单的一行更改。具体可以参考另外一篇博客:基于Pytorch的分布式数据并行训练

因此,需要处理的第一个也是最复杂的新事情是进程初始化。普通的PyTorch训练脚本在单个进程中执行其代码的单一副本。使用数据并行模型,情况就更加复杂了:现在训练脚本的同步副本与训练集群中的GPU数量一样多,每个GPU运行在不同的进程中。示例脚本如下:

import os

import torch
import torch.distributed as dist
import torch.multiprocessing as mp


def init_process(rank, size, backend='gloo'):
    """ Initialize the distributed environment. """
    os.environ['MASTER_ADDR'] = '127.0.0.1'
    os.environ['MASTER_PORT'] = '29500'
    dist.init_process_group(backend, rank=rank, world_size=size)


def train(rank, num_epochs, world_size):
    init_process(rank, world_size)
    print(f"Rank {rank + 1}/{world_size} process initialized.\n")


# rest of the training script goes here!WORLD_SIZE = torch.cuda.device_count()
if __name__ == "__main__":
    mp.spawn(train, args=(NUM_EPOCHS, WORLD_SIZE), nprocs=WORLD_SIZE, join=True)

其中WORLD_SIZE是编排的进程数量,(全局)rank是当前进程在该MPI中的位置。如果这个脚本要在一个有4个GPU的机器上执行,WORLD_SIZE应该是4(因为torch.cuda.device_count() == 4),所以是mp.spawn会产生4个不同的进程,它们的rank分别是0、1、2或3。rank为0的进程被赋予一些额外的职责,因此被称为主进程。

当前进程的rank将作为派生入口点(在本例中为train function)作为其第一个参数传递。 在训练时可以执行任何工作之前,它需要首先建立与对等点对点的连接。 这是dist.init_process_group的工作。 在主进程中运行时,此方法在MASTER_ADDR:MASTER_PORT上设置套接字侦听器,并开始处理来自其他进程的连接一旦所有进程都已连接,此方法将处理建立对等连接,以允许进程进行通信

请注意,此代码仅适用于在一台多GPU机器上进行训练! 同一台机器用于启动作业中的每个流程,因此训练只能利用连接到该特定机器的GPU。 这使事情变得容易:设置IPC就像在localhost上找到一个空闲端口一样容易,该端口对于该计算机上的所有进程都是立即可见的。 跨计算机的IPC更为复杂,因为它需要配置一个对所有计算机可见的外部IP地址

2. 流程同步

了解了初始化过程,现在可以开始完成所有worker的train方法的主体。

def train(rank, num_epochs, world_size):
    init_process(rank, world_size)
    for epoch in range(num_epochs):
        print(f"Rank {rank + 1}/{world_size} process initialized.\n")

四个训练过程中的每一个都会运行此函数直到完成,然后在完成时退出。 如果现在(通过python multi_init.py)运行此代码,将在控制台上看到类似以下内容:

$ python multi_init.py
Rank 4/4 process initialized.
Rank 2/4 process initialized.
Rank 4/4 process initialized.
Rank 2/4 process initialized.
Rank 3/4 process initialized.
Rank 4/4 process initialized.
Rank 2/4 process initialized.
Rank 3/4 process initialized.
Rank 4/4 process initialized.
Rank 2/4 process initialized.
Rank 4/4 process initialized.
Rank 3/4 process initialized.
Rank 2/4 process initialized.
Rank 3/4 process initialized.
Rank 3/4 process initialized.
Rank 1/4 process initialized.
Rank 1/4 process initialized.
Rank 1/4 process initialized.
Rank 1/4 process initialized.
Rank 1/4 process initialized.

这些过程是独立执行的,并且不能保证训练循环中任一点处于什么状态。 所以这里需要对初始化过程进行一些仔细的更改。
(1)任何下载数据的方法都应隔离到主进程中
否则的话将在所有过程之间复制数据下载过程,从而导致四个过程同时写入同一文件,这是造成数据损坏的原因。

def train(rank, num_epochs, world_size):
    init_process(rank, world_size)
    for epoch in range(num_epochs):
        if rank == 0:
            downloading_dataset()
            downloading_model_weights()
            dist.barrier()
            print(f"Rank {rank + 1}/{world_size} training process passed data download barrier.\n")

示例中的dist.barrier将阻塞调用,直到完成主进程(rank == 0)downloading_datasetdownloading_model_weights为止。 这样可以将所有网络I / O隔离到一个进程中,并防止其他进程继续前进。
(2)数据加载器需要使用DistributedSampler

def get_dataloader(rank, world_size):
    dataset = PascalVOCSegmentationDataset()
    sampler = DistributedSampler(dataset, rank=rank, num_replicas=world_size, shuffle=True)
    dataloader = DataLoader(dataset, batch_size=8, sampler=sampler)

DistributedSampler使用rank和world_size找出如何将整个过程中的数据集拆分为不重叠的批次。 worker进程的每个训练步骤都从其本地数据集副本中检索batch_size观测值。 在四个GPU的示例情况下,这意味着有效批大小为8 * 4 = 32。
(3)在正确的设备中加载张量
请使用该进程正在管理的设备的rank来参数化.cuda()调用,例如:

batch = batch.cuda(rank)
segmap = segmap.cuda(rank)
model = model.cuda(rank)

(4)必须禁用模型初始化中的任何随机性
在整个训练过程中,模型必须启动并保持同步,这一点非常重要。 否则,将获得不正确的梯度并导致模型无法收敛。可以使用以下代码使torch.nn.init.kaiming_normal_之类的随机初始化方法具有确定性:

torch.manual_seed(0)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
np.random.seed(0)

(5)任何执行文件I / O的方法都应与主进程隔离
由于并发写入同一文件而导致的效率低下和潜在的数据损坏。 同样,使用简单的条件逻辑很容易做到这一点:

if rank == 0:
	if not os.path.exists('/spell/checkpoints/'):
		os.mkdir('/spell/checkpoints/')
		torch.save(model.state_dict(), f'/spell/checkpoints/model_{epoch}.pth')

(6)将model包装在DistributedDataParallel中

model = DistributedDataParallel(model, device_ids=[rank])

这一步是必须的,也是最后一步,之后模型就可以在分布式数据并行模式下训练。

数据并行

PyTorch中还有另一种数据并行化策略,即torch.nn.DataParallel。 该API易于使用。 要做的就是包装模型初始化,如下所示:

model = nn.DataParallel(model)

所有的改动只有一行! 为什么不使用它呢?因为在程序的后台,DataParallel使用多线程而不是多进程来管理其GPU工作器。 这极大地简化了实现:由于工作进程是同一进程的所有不同线程,因此它们都可以访问相同的共享状态,而无需任何其他同步步骤。但是,由于存在全局解释器锁GIL,在Python中将多线程用于计算作业的效果很差。 如下一节中的基准测试所示,使用DataParallel并行化的模型比使用DistributedDataParallel并行化的模型要慢得多。尽管如此,如果不想花费额外的时间和精力使用多GPU训练,DataParallel是可以考虑的。

基准测试

【分布式训练】基于PyTorch进行多GPU分布式模型训练(补充),深度学习与人工智能,分布式,pytorch,多GPU训练,数据并行化,模型并行化DistributedDataParallel的效率明显高于DataParallel,但还远远不够完美。 从V100x1切换到V100x4是原始GPU功耗的4倍,但模型训练速度仅为3倍。 通过升级到V100x8使计算进一步加倍,只会使训练速度提高约30%,但是DataParallel的效率几乎达到了DistributedDataParallel的水平。文章来源地址https://www.toymoban.com/news/detail-601603.html

相关资料

  1. 分布式TensorFlow入门教程
  2. 使用 Horovod 估算器和 PyTorch 进行分布式训练
  3. Distributed Parallel Training: Data Parallelism and Model Parallelism
  4. Distributed Parallel Training — Model Parallel Training
  5. torch.nn.parallel.DistributedDataParallel: 快速上手
  6. GETTING STARTED WITH DISTRIBUTED DATA PARALLEL
  7. Distributed Communication Package PyTorch文档
  8. randomness

到了这里,关于【分布式训练】基于PyTorch进行多GPU分布式模型训练(补充)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【金猿案例展】智谱AI——基于全闪分布式并行文件存储打造高速大模型训练平台...

    ‍ 焱融科技案例 本项目案例由焱融科技投递并参与“数据猿年度金猿策划活动——2023大数据产业年度创新服务企业榜单/奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 · 改变商业 自 ChatGPT 爆火以来,中国的 AI 产业已经进入名副其实的“百模大战”。《中国人工智能

    2024年02月02日
    浏览(51)
  • 【VSCode调试技巧】Pytorch分布式训练调试

    最近遇到个头疼的问题,对于单机多卡的训练脚本,不知道如何使用VSCode进行Debug。 解决方案: 1、找到控制分布式训练的启动脚本,在自己的虚拟环境的/lib/python3.9/site-packages/torch/distributed/launch.py中 2、配置launch.josn文件,按照正确的参数顺序,填入args参数,注意区分位置参

    2024年04月27日
    浏览(40)
  • pytorch中分布式训练DDP教程(新手快速入门!)

    PyTorch是深度学习领域广泛使用的开源深度学习框架之一。随着深度学习模型的不断增大和数据集的不断增长,单机训练往往不能满足我们的需求。为了加速训练过程,我们可以使用分布式训练技术。在PyTorch中,分布式数据并行(Distributed Data Parallel,简称DDP)是一种常见的分

    2024年02月16日
    浏览(45)
  • pytorch分布式训练报错RuntimeError: Socket Timeout

    出错背景:在我的训练过程中,因为任务特殊性,用的是多卡训练单卡测试策略。模型测试的时候,由于数据集太大且测试过程指标计算量大,因此测试时间较长。 报错信息: 从报错信息中可以看到是数据加载的时候,创建进程引起的超时,解决方法就是将“进程”的“存

    2024年02月13日
    浏览(49)
  • 【深度学习】【分布式训练】Collective通信操作及Pytorch示例

    相关博客 【Megatron-DeepSpeed】张量并行工具代码mpu详解(一):并行环境初始化 【Megatron-DeepSpeed】张量并行工具代码mpu详解(二):Collective通信操作的封装mappings 【深度学习】【分布式训练】DeepSpeed:AllReduce与ZeRO-DP 【深度学习】混合精度训练与显存分析 【深度学习】【分布式训练

    2023年04月13日
    浏览(39)
  • 【分布式】大模型分布式训练入门与实践 - 04

    【分布式】NCCL部署与测试 - 01 【分布式】入门级NCCL多机并行实践 - 02 【分布式】小白看Ring算法 - 03 【分布式】大模型分布式训练入门与实践 - 04 数据并行(Distributed Data Parallel)是一种用于加快深度学习模型训练速度的技术。在过去,训练大型模型往往受限于单卡训练的瓶颈

    2024年02月08日
    浏览(39)
  • PyTorch Lightning:通过分布式训练扩展深度学习工作流

              欢迎来到我们关于 PyTorch Lightning 系列的第二篇文章!在上一篇文章中,我们向您介绍了 PyTorch Lightning,并探讨了它在简化深度学习模型开发方面的主要功能和优势。我们了解了 PyTorch Lightning 如何为组织和构建 PyTorch 代码提供高级抽象,使研究人员和从业者能够

    2024年02月11日
    浏览(45)
  • 1、pytorch分布式数据训练结合学习率周期及混合精度

    正如标题所写,我们正常的普通训练都是单机单卡或单机多卡。而往往一个高精度的模型需要训练时间很长,所以DDP分布式数据并行和混合精度可以加速模型训练。混精可以增大batch size. 如下提供示例代码,经过官网查阅验证的。原始代码由百度文心一言提供。 问题:pytor

    2024年02月07日
    浏览(39)
  • 大语言模型的分布式训练

    什么是大语言模型 训练方式 面临的挑战 什么是分布式计算 如何实现 拆分逻辑 分发逻辑 大语言模型的分布式训练 数据并行 模型并行 流水线并行 张量并行 通信 PS NCCL是Nvidia Collective multi-GPU Communication Library的简称,它是一个实现多GPU的collective communication通信(all-gather, red

    2024年02月10日
    浏览(46)
  • 大模型学习笔记08——分布式训练

    模型规模的扩大,对硬件(算力、内存)的发展提出要求。然而,因为内存墙的存在,单一设备的算力及容量,受限于物理定律,持续提高芯片的集成越来越困难,难以跟上模型扩大的需求。 为了解决算力增速不足的问题,人们考虑用多节点集群进行分布式训练,以提升算力

    2024年01月23日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包