关于集群分布式torchrun命令踩坑记录(自用)

这篇具有很好参考价值的文章主要介绍了关于集群分布式torchrun命令踩坑记录(自用)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

项目场景:

在训练或者微调模型的过程中,单节点的显存溢出,或者单节点的显卡较少,算力有限。需要跨节点用多个节点多块显卡来运行这项任务。这里就需要使用分布式命令,将这项任务分布到多个节点上来处理。


问题描述

在此我仅记录我在运行分布式过程中遇到的一些问题。

首先,对于pytorch深度学习框架的分布式进程是有一套标准的流程的,简单来讲就是先通过dist进行初始化,再将模型进行分布式分配。具体所用的API为:

import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP

对于预训练(或者微调)的脚本,我参考了官方文档中的测试代码,测试代码实际非常简单,搭建了一个非常小的网络,同时对其使用分布式进程,非常适合拿来做测试。链接为:官方文档

dist.init_process_group()是PyTorch中用于初始化分布式训练的函数之一。它用于设置并行训练环境,连接多个进程以进行数据和模型的分布式处理。我们通过init_process_group()函数这个方法来进行初始化,其参数包括以下内容

  1. backend(必需参数):指定分布式后端的类型,可以是以下选项之一:

    ‘tcp’:使用TCP协议进行通信。
    ‘gloo’:使用Gloo库进行通信。
    ‘mpi’:使用MPI(Message Passing Interface)进行通信。
    ‘nccl’:使用NCCL库进行通信(适用于多GPU的分布式训练)。
    ‘hccl’:使用HCCL库进行通信(适用于华为昇腾AI处理器的分布式训练)。

  2. init_method(可选参数):指定用于初始化分布式环境的方法。它可以是以下选项之一:
    ‘env://’:使用环境变量中指定的方法进行初始化。
    ‘file://

    ’:使用本地文件进行初始化。
    ‘tcp://

    :’:使用TCP地址和端口进行初始化。
    ‘gloo://
    :’:使用Gloo地址和端口进行初始化。
    ‘mpi://
    :’:使用MPI地址和端口进行初始化。
  3. rank(可选参数):指定当前进程的排名(从0开始)。

  4. world_size(可选参数):指定总共使用的进程数。

  5. timeout(可选参数):指定初始化的超时时间。

  6. group_name(可选参数):指定用于连接的进程组名称。

这里由于服务器采用的slurm系统,我们开始计划使用mpi去实现分布式分发,同时torch的初始化也支持mpi,原始想法是通过mpirun来进行分布式计算。但是,如果要使用mpi来实现分布式功能,必须要通过github上的源代码进行编译,通过conda和pip进行下载的pytorch自身是不携带mpi的
通过上面的参数,可以看到backend是有多重通信方式的,常用的有gloo和mpi和nccl,但是这三者是有区别的,这里我们可以参考官方文档:官方文档
关于集群分布式torchrun命令踩坑记录(自用),分布式,pytorch,深度学习
这里我们直接放出结论,以供参考:

  • 对于分布式 GPU 训练,使用 NCCL 后端。
  • 对于分布式 CPU 训练,使用 Gloo 后端。
  • 如果你的主机是 GPU 主机并且具有 InfiniBand 互连: 使用 NCCL,因为它是目前唯一支持 InfiniBand 和
    GPUDirect 的后端。
  • 如果你的主机是 GPU 主机并且具有以太网互连: 使用 NCCL,因为它目前提供了最好的分布式 GPU
    训练性能,特别是对于多进程单节点或多节点分布式训练。
  • 如果你遇到 NCCL 的任何问题,使用 Gloo 作为备选选项。(注意,Gloo 目前运行速度比 NCCL 慢)
  • 如果你的主机是 CPU 主机并且具有 InfiniBand 互连: 如果你的 InfiniBand 启用了 IP over IB,使用
    Gloo,否则,使用 MPI。我们计划在即将发布的版本中为 Gloo 添加 InfiniBand 支持。
  • 如果你的主机是 CPU 主机并且具有以太网互连: 使用 Gloo,除非你有特定的理由使用 MPI​。

我们可以根据文档的提示,得出,MPI是最不推荐使用的一种方法,对于英伟达的显卡,最优先的还是使用NCCL方法。和Mpi相匹配的有一种torch官方自带的方法,在torch2.0之前使用的API叫:torch.distributed.launch在使用时显示未来的版本将会弃用这个API,取而代之的是torchrun。因此我们将命令由mpi改为torchrun方法,在dist初始化使用nccl后端通信。

这里我们可以参考torchrun的官方运行方法:官方文档
经过近两周的调试与踩坑,先是在测试节点上对官方测试脚本进行分布式测试,运行成功后再将相同的环境和文件迁移到计算节点上,再在计算节点上对分布式命令进行测试,期间还测试了root用户和子用户对torchrun命令是否会有影响。

假设我们有三个节点,node02,node03,node04,每个节点上有四张GPU。现在我们将官方测试文档中的代码写为test_mpi.py。最终通过torchrun实现的命令如下:

torchrun --nproc_per_node=4 --nnodes=3 --node_rank=0 --master_addr=192.168.0.101 --master_port=29500 test_mpi.py

我们没有必要和torchrun的官方文档一样去设置**–rdzv-backend** 和**–rdzv-id**,因为这不是必须的,用默认的即可。我们只需要设置的参数只有上面这几个。具体参数介绍如下:
–nproc_per_node=4:指定每个节点(机器)上的进程数,这里是4个。意味着每个机器将启动4个进程来参与分布式训练。

  • –nnodes=3:指定总共的节点数,这里是3个。意味着总共有3个机器参与分布式训练。
  • –node_rank=0:指定当前节点(机器)的排名,这里是0。排名从0开始,用于在分布式环境中区分不同的节点。
  • –master_addr=192.168.0.101:指定主节点的IP地址,这里是192.168.0.101。主节点用于协调分布式训练过程。
  • –master_port=29500:指定主节点的端口号,这里是29500。主节点使用指定的端口来与其他节点进行通信。

通过设置这些参数,该命令将在3个节点的分布式环境中启动4个进程,并指定192.168.0.101作为主节点进行协调和通信。
这里的主节点地址我随便写的,可以根据实际情况进行修改。主节点的地址的- --node_rank必须设置为0,也就是上述这行命令,必须要先在主节点上线运行。

举个例子,假如我的主节点是node02,那么我就要先在node02节点的终端上运行上述torchrun命令,同时–master_addr要为node02的ip地址(查看IP地址可以通过:ip addr),然后node03,node04的顺序就不重要了,在其节点的终端上将–node_rank=0改为–node_rank=1和–node_rank=2运行即可。

这里出现第一个问题,即是,通讯超时(具体表现为:ERROR:torch.distributed.elastic.multiprocessing.api:failed (exitcode: -11))。假如我们的节点之前ping方法没有问题,同时节点并没有处于被占用的情况,那么分析超时就比较困难了。我会在之后的解决方法中,提供我是如何解决的。
关于集群分布式torchrun命令踩坑记录(自用),分布式,pytorch,深度学习

在命令确认无误之后,我们需要将这个命令,写成脚本提交到后台,挂在服务器上运行,而不是在终端上一直在线处理。

由于我们服务器使用的slurm系统,slurm系统自带一套可以提交作业的方法。于是就要将这个命令进行sbatch脚本打包。打包的bash脚本如下所示:

#!/bin/bash
#SBATCH --job-name=pytorch_job    # 创建一个任务名
#SBATCH -N 3                      # 需要使用的节点数
#SBATCH --ntasks-per-node=4       # 每个节点上的任务数
#SBATCH --output=job_output.out   # 标准输出文件
#SBATCH --error=job_error.err     # 标准错误文件
#SBATCH --nodelist=node02,node03,node04  # 指定节点列表

# 加载任何必要的模块,例如:
# module load python
# module load pytorch
# source ……

export TORCH_DISTRIBUTED_DEBUG=INFO
export NCCL_IB_DISABLE=1



# 设置主节点
# 节点列表
NODELIST=$(scontrol show hostname $SLURM_JOB_NODELIST)
# 对第一个节点赋值为主节点
MASTER_NODE=$(head -n 1 <<< "$NODELIST")
# 计数器
NODE_COUNT=0
# 一共的节点数
NODE_NUM=($(echo $NODELIST | tr " " "\n" | wc -l))

# 打印
echo $SLURM_NODEID
echo $NODELIST
echo $MASTER_NODE
echo $NODE_NUM

for NODE in $NODELIST; do
    if [ "$NODE" == "$MASTER_NODE" ]; then
        srun --nodes=1 --ntasks=1 -w $NODE torchrun --nproc_per_node=4 --nnodes=$NODE_NUM --node_rank=0 --master_addr=192.168.0.101 --master_port=29500 test_mpi.py &
    else
        ((NODE_COUNT++))
        srun --nodes=1 --ntasks=1 -w $NODE torchrun --nproc_per_node=4 --nnodes=$NODE_NUM --node_rank=$NODE_COUNT --master_addr=192.168.0.101 --master_port=29500 test_mpi.py &
    fi
done
wait

脚本的逻辑为:通过srun在启动的每个节点上运行torchrun命令,运行的同时还需要进行判断,判断提交的节点是不是主节点,如果是主节点则node_rank的值要为0,如果不是主节点则node_rank的值为1,2……其实并不推荐使用sbatch嵌套srun()

这里出现第二个问题,假如不是不是在主节点第一个运行命令,则会发生超时,具体情况如下:
关于集群分布式torchrun命令踩坑记录(自用),分布式,pytorch,深度学习
我会在之后的解决方法中,提供我是如何解决的。


原因分析:

对于上述的两种超时问题,首先要做的是在节点之间进行ping操作确认,确认不是服务器本身的问题,则考虑是不是节点之间的通信问题。因为NCCL也是有内部通信的,NVIDIA的NCCL库支持多种传输方式,以便在不同的硬件和网络配置中实现最优的通信性能。以下是一些主要的传输方式:

InfiniBand (IB):如前所述,InfiniBand是一种高性能、低延迟的网络传输技术,常用于高性能计算(HPC)和数据中心。

TCP/IP:这是最常见的网络通信协议,可以在任何支持TCP/IP的网络(包括常见的以太网)上运行。

Shared Memory (SHM):在同一台机器上的GPU之间,NCCL可以使用共享内存进行通信。这通常比通过网络传输更快。

CUDA Inter-Process Communication (IPC):对于同一节点上的多个GPU,NCCL可以使用CUDA IPC进行通信。这是一种允许不同CUDA进程共享GPU内存的机制,可以提高通信效率。

NVLink:NVLink是NVIDIA的一种高速互连技术,用于连接GPU和GPU,或GPU和CPU。它提供了比传统PCIe更高的带宽,适用于需要高速GPU间通信的应用。

这些传输方式可以根据具体的硬件配置和通信需求进行选择和配置。
关于集群分布式torchrun命令踩坑记录(自用),分布式,pytorch,深度学习


解决方案:

我们可以在之前的脚本中,添加环境变量,进入调试模型,查看具体的原因:

export NCCL_DEBUG=INFO
export NCCL_DEBUG_SUBSYS=ALL
export TORCH_DISTRIBUTED_DEBUG=INFO

对于第一个问题,再次运行我们的命令,即可获得NCCL的INFO信息,我们详细对比信息可以发现,在主节点上,我们使用的通信方式是NET/IB,如下图所示:
关于集群分布式torchrun命令踩坑记录(自用),分布式,pytorch,深度学习
而在其他节点,我们使用的方式是 NET/Socket
关于集群分布式torchrun命令踩坑记录(自用),分布式,pytorch,深度学习
NET/IB 和 NET/Socket 是两种不同的网络通信接口。NET/IB 通常指的是 InfiniBand,这是一种高性能、低延迟的网络通信接口,常用于高性能计算和数据中心。而 NET/Socket 则是一种更常见的网络接口,它在各种网络环境中都可以使用。如果你的两个节点一个使用 NET/IB,另一个使用 NET/Socket,那么这两个节点之间的通信可能会受到影响。因为 NCCL 默认使用最快的可用传输方法,如果两个节点的网络接口不同,那么可能无法建立有效的通信。具体情况可能需要根据你的网络环境和配置进行测试。这里建议使用同一种通信方式。
我们将IB禁用即可:

export NCCL_IB_DISABLE=1

对于第二个问题,我们只需要写判断语句,确保主节点运行node_rank=0的命令即可,在上述给出的代码我已经写好了判断语句。文章来源地址https://www.toymoban.com/news/detail-516880.html

到了这里,关于关于集群分布式torchrun命令踩坑记录(自用)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 分布式、集群、微服务

    分布式是以缩短单个任务的执行时间来提升效率的;而集群则是通过提高单位时间内执行的任务数来提升效率。 分布式是指将不同的业务分布在不同的地方。 集群指的是将几台服务器集中在一起,实现同一业务。 分布式中的每一个节点,都可以做集群。而集群并不一定就是

    2024年02月08日
    浏览(53)
  • 分布式与集群区别

    1、提供服务是否相同 分布式:不同的机器上部署的是不同的服务模块,对外提供不同的服务 集群:不同机器上部署的是同样的模块,对外提供同样的服务 2、目的 分布式:分解任务,用来应对高并发。 集群:用来容错,可靠性,高可用。 3、是否依赖其他模块 分布式:各节

    2024年04月22日
    浏览(38)
  • 浅析集群、分布式、负载均衡

    平时开发或者面试中进场听到集群、分布式、负载均衡等系列的名词,他们之间有什么联系呢,本文就简要的抛砖引玉一下。 1.什么是集群 集群一般指的是服务器集群。集群其实就是一组相互独立的计算机,通过高速的网络组成一个计算机系统。而很多服务器集中起来一起进

    2024年02月13日
    浏览(45)
  • 部署SeaTunnel分布式集群

    深入理解SeaTunnel:易用、高性能、支持实时流式和离线批处理的海量数据集成平台 SeaTunnel Engine 是 SeaTunnel 的默认引擎。SeaTunnel的安装包中已经包含了SeaTunnel Engine的所有内容。 在/etc/profile.d/seatunnel.sh中配置环境变量 SeaTunnel Engine 支持两种设置 jvm 选项的方式。 将 JVM 选项添加

    2024年02月09日
    浏览(48)
  • Redis分布式系统:集群

    \\\"还不如留给花园,多一瞬色彩~\\\"          当我们聊到“集群”这一个词,我们脑中构想出的画面,一定是多台机器,构成的分布式系统,这可以被称为一个“集群”。其实,在前篇的哨兵机制下,奇数个监控哨兵,以及多组主从结构的数节点所构成的大的环境,就是一个“

    2024年01月24日
    浏览(43)
  • 搭建HBase分布式集群

    0. Prerequisite There are 3 VMs - hadoop3/hadoop4/hadoop5 for fully-distributed HBase cluster, the setup plan looks like: hadoop3 hadoop4 hadoop5 Hadoop hdfs NameNode:8020 DateNode:50010 JobHistoryServer:19888 DataNode:50010 SecondaryNameNode:50090 DateNode:50010 Hadoop yarn NodeManger:8040 ResourceMananger:8088 NodeManger:8040 NodeManger:8040 Zookeeper Quor

    2024年02月08日
    浏览(36)
  • 单机,集群和分布式概念

    1.受限于硬件资源,单机所能承受的用户并发量太少; 2.一个系统有多个模块,任意模块的修改都会导致整个项目代码重新编译、部署; 3.系统中,有些模块是CPU密集型,有些模块是I/O密集型,造成各个模块对于硬件资源的需求是不一样的。 负载均衡        集群的优点

    2024年02月14日
    浏览(48)
  • Hadoop分布式集群搭建

    集群以三台电脑搭建,每台电脑创建一个UbuntuKylin虚拟机,集群以三台UbuntuKylin虚拟机为基础搭建,虚拟机主机名分别为hadoop101、hadoop111和hadoop121。IP地址分别为192.168.214.101、192.168.214.111和192.168.214.121。 主机名 IP地址: hadoop101 192.168.214.101 hadoop111 192.168.214.111 hadoop121 192.168.214

    2024年02月03日
    浏览(48)
  • LVS集群和分布式

    LVS 在计算机领域,集群早在 1960 年就出现,随着互联网和计算机相关技术的发展,现在 集群这一技术已经在各大互联网公司普及。 1.1.1 集群概念 计算机集群指一组通过计算机网络连接的计算机,它们一起工作,在许多方面,它们可以 被视为一个单一的系统。与网格计算机

    2024年02月13日
    浏览(40)
  • Hadoop分布式集群安装

            上一篇大数据文章讲解了在单机上搭建Hadoop-Yarn 伪分布式集群的安装方法,方便大家学习,真实环境不可能只有一台机器,肯定是多节点的集群,大单位还会建设很多Hadoop集群,比如各个大部门有自己的集群,或者按热、温、冷来划分建立集群,反正都是很多台服

    2024年01月19日
    浏览(51)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包