当前位置:   article > 正文

目标检测 YOLOv5 - 多机多卡训练_yolo分布式训练 多机多卡

yolo分布式训练 多机多卡

目标检测 YOLOv5 - 多机多卡训练

flyfish

环境:

Python>=3.6.0 
PyTorch>=1.7
YOLOv5:v5
  • 1
  • 2
  • 3

1 CUDA_VISIBLE_DEVICES环境变量

通过设置CUDA_VISIBLE_DEVICES环境变量来限制PyTorch所能使用的GPU设备,GPU设备从0开始编号。
在命令行中设置

CUDA_VISIBLE_DEVICES='0,1,2,3,4,5,6,7'
  • 1

在代码设置,该代码需要写在调用GPU资源之前

os.environ["CUDA_VISIBLE_DEVICES"] = '0,1,2,3,4,5,6,7'
  • 1

2 多机多卡的使用

分两种类型机器一个master,其他都是slave

master机器运行的命令
python -m torch.distributed.launch --nproc_per_node G --nnodes N --node_rank 0 --master_addr "192.168.1.2" --master_port 1234 train.py --batch 64 --data coco.yaml --cfg yolov5s.yaml --weights ''
  • 1
第R台slave机器运行的命令
python -m torch.distributed.launch --nproc_per_node G --nnodes N --node_rank R --master_addr "192.168.1.2" --master_port 1234 train.py --batch 64 --data coco.yaml --cfg yolov5s.yaml --weights ''
  • 1

假设有两台机器,每台机器都有两张卡

实际master机器运行的命令
python -m torch.distributed.launch --nproc_per_node 2 --nnodes 2 --node_rank 0 --master_addr "192.168.1.2" --master_port 1234 train.py --batch 64 --data coco.yaml --cfg yolov5s.yaml --weights ''
  • 1
实际第R台slave机器运行的命令
python -m torch.distributed.launch --nproc_per_node 2 --nnodes 2 --node_rank 1 --master_addr "192.168.1.2" --master_port 1234 train.py --batch 64 --data coco.yaml --cfg yolov5s.yaml --weights ''
  • 1

nnodes 表示一共有多少机器参与训练
node_rank 表示当前机器的序号从0开始
nproc_per_node 表示每台机器有多少张显卡
master_addr和master_port表示master机器的IP和端口

正常情况,当两台机器都运行完命令,训练就开始了,否则master处于等待状态。
一般情况一台机器GPU的数量等于进程的数量,二般情况是不等于,下面描述的是一般情况

Node 0
    Process0 [Global Rank=0, Local Rank=0] -> GPU 0
    Process1 [Global Rank=1, Local Rank=1] -> GPU 1
    Process2 [Global Rank=2, Local Rank=2] -> GPU 2
    Process3 [Global Rank=3, Local Rank=3] -> GPU 3
Node 1
    Process4 [Global Rank=4, Local Rank=0] -> GPU 0
    Process5 [Global Rank=5, Local Rank=1] -> GPU 1
    Process6 [Global Rank=6, Local Rank=2] -> GPU 2
    Process7 [Global Rank=7, Local Rank=3] -> GPU 3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这里用Node表述,没有使用Host,Node不限定是物理机器,还有可能是容器例如docker,简单理解就是一个Node节点就是一台机器。

两台机器(节点0和节点1),每个节点上使用2张卡 ,world_size就是 2 * 2 = 4
两台机器(节点0和节点1),每个节点上使用4张卡 ,world_size就是 2 * 4 = 8
一共有3个node(nnodes=3),每个node包含8个GPU,设置nproc_per_node=4,
,world_size就是3 * 4 =12,为什么不是3*8=24呢?因为每个node虽然有8个GPU,但是命令设置只使用其中4个(nproc_per_node=4),有而不使用是不算数的。
world_size的大小=节点数 x 每个节点使用的GPU数量

Global Rank计算范围是在world_size范围之内
Local Rank计算范围是在当前node范围之内

单独说rank,前面没有global或者local,一般指的是global rank
global rank就是在多机多卡时对分布式进程的编号。比如global rank=0 表示0号进程
Local Rank指在一个node内的进程序号

3 快速训练的方案

3.1 快速读取数据

期望程序在访问硬盘时都取访问内存,不访问硬盘
方式1
训练的命令行加入参数 --cache-images
方式2

sudo mount tmpfs /media/data/cache/ -t tmpfs -o size=128G
  • 1

然后把数据集拷贝到/media/data/cache/,这样/media/data/cache/文件夹的数据全部装入内存
数据集放在这里是临时存放的,计算机重启后会消失。

3.2 多台机器,不同GPU数量的使用

假如有3台机器,如果每台机器的GPU数量是相同,可以按照上面多机多卡的使用说明来做
模拟出4台机器,每台机器2个GPU。

将4个GPU的机器上程序再拷贝一份,放置到不同的目录。

master的机器,2个GPU

CUDA_VISIBLE_DEVICES='0,1' python -m torch.distributed.launch --nproc_per_node 2 --nnodes 4 --node_rank 0 --master_addr "192.168.1.100" --master_port 5678 train.py --batch 128 --data ./data/coco.yaml --cfg yolov5s.yaml
  • 1

slave的机器,2个GPU

CUDA_VISIBLE_DEVICES='0,1' python -m torch.distributed.launch --nproc_per_node 2 --nnodes 4 --node_rank 1 --master_addr "192.168.1.100" --master_port 5678 train.py --batch 128 --data ./data/coco.yaml --cfg yolov5s.yaml
  • 1

slave的机器,4个GPU,使用其中2个GPU

CUDA_VISIBLE_DEVICES='0,1' python -m torch.distributed.launch --nproc_per_node 2 --nnodes 4 --node_rank 2 --master_addr "192.168.1.100" --master_port 5678 train.py --batch 128 --data ./data/coco.yaml --cfg yolov5s.yaml
  • 1

slave的机器,4个GPU,使用其中2个GPU

CUDA_VISIBLE_DEVICES='2,3' python -m torch.distributed.launch --nproc_per_node 2 --nnodes 4 --node_rank 3 --master_addr "192.168.1.100" --master_port 5678 train.py --batch 128 --data ./data/coco.yaml --cfg yolov5s.yaml
  • 1

4 异常情况的处理

会产生如下错误
情况1

store = TCPStore(master_addr, master_port, world_size, start_daemon, timeout)
RuntimeError: Address already in use
  • 1
  • 2

解决方法是 一种是更改下端口号,重新运行命令。另一种时进程里有之前运行的训练进程占用了此地址和端口,可以把该进程结束

查看包含python的进行

ps -aux | grep 进程服务名
ps -aux | grep python
  • 1
  • 2

杀死进程

sudo kill 进程号(PID)
sudo kill 1111
  • 1
  • 2

情况2
类似如下错误提示

(1) dist.init_process_group(backend='nccl')
(2) NCCL WARN Connect to 192.168.1.2<> failed : No route to host
(3) dist.init_process_group(backend='nccl', init_method='env://')  # distributed backend
site-packages/torch/distributed/distributed_c10d.py", line 442, in init_process_group
barrier()
in barrier
work = _default_pg.barrier()
RuntimeError: NCCL error in: /pytorch/torch/lib/c10d/ProcessGroupNCCL.cpp:784, unhandled system error, NCCL version 2.7.8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
4.1 查看日志

遇到这种错误需要把nccl日志打开,查看IP绑定网卡是否正确,按照如下操作
(NVIDIA Collective Communications Library (NCCL))
查看网卡
终端执行 ifconfig
找到IP 192.168.1.2 对应的网络

eno1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.2  netmask 255.255.255.0  broadcast 192.168.1.255
  • 1
  • 2

该示例中是eno1,填写NCCL_SOCKET_IFNAME=eno1

终端执行

export NCCL_DEBUG=INFO
export NCCL_IB_DISABLE=1
export NCCL_SOCKET_IFNAME=eno1
  • 1
  • 2
  • 3

对多网卡的机器一定要设置环境变量NCCL_SOCKET_IFNAME,这样可以减少不必要的错误。

这时候再执行命令就显示日志了,通过日志就能找到是什么地方出现了问题
日志内容

NCCL INFO Call to connect returned Connection refused, retrying
  • 1

或者

machinename:33983:34116 [2] include/socket.h:403 NCCL WARN Connect to 192.168.1.2<50565> failed : Connection refused
machinename:33983:34116 [2] NCCL INFO bootstrap.cc:95 -> 2
machinename:33983:34116 [2] NCCL INFO bootstrap.cc:309 -> 2
machinename:33983:34116 [2] NCCL INFO init.cc:555 -> 2
machinename:33983:34116 [2] NCCL INFO init.cc:840 -> 2
machinename:33983:34116 [2] NCCL INFO group.cc:73 -> 2 [Async thread]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
4.2 查看两台机器是否互通

master的机器运行

nc -l 5678 -v
Listening on [0.0.0.0] (family 0, port 5678)
Connection from 192.168.1.3 39788 received!
  • 1
  • 2
  • 3

slave的机器运行

nc 192.168.1.2 5678
  • 1

或者执行ping也可以
如果不成功表明问题出在防火墙,把防火墙关闭或者把允许的机器加到防火墙的白名单里

执行添加白名单命令

sudo firewall-cmd --zone=trusted --add-source=192.168.1.2
sudo firewall-cmd --zone=trusted --add-source=192.168.1.3
sudo firewall-cmd --zone=trusted --add-source=192.168.1.4
  • 1
  • 2
  • 3

192.168.1.2是master的机器,把自己的IP也加进去

执行查看trusted区域设置是否正确的命令

firewall-cmd --zone=trusted --list-all
  • 1
4.3 firewalld防火墙操作

查看防火墙状态

systemctl status firewalld
  • 1

暂时关闭防火墙

systemctl stop firewalld
  • 1

永久关闭 firewalld防火墙(重启有效)

systemctl disable firewalld 
  • 1
4.4 ufw防火墙操作

查看防火墙状态

sudo ufw status
  • 1

永久关闭防火墙

sudo ufw disable
  • 1

开启防火墙

sudo ufw enable
  • 1

当正确执行后slave有如下日志

machinename:37519:37519 [0] NCCL INFO Bootstrap : Using [0]eno1:192.168.1.3<0>
machinename:37519:37519 [0] NCCL INFO NET/Plugin : No plugin found (libnccl-net.so), using internal implementation
machinename:37519:37519 [0] NCCL INFO NCCL_IB_DISABLE set by environment to 1.
machinename:37519:37519 [0] NCCL INFO NET/Socket : Using [0]eno1:192.168.1.3<0>
machinename:37519:37519 [0] NCCL INFO Using network Socket
machinename:37520:37520 [1] NCCL INFO Bootstrap : Using [0]eno1:192.168.1.3<0>
machinename:37520:37520 [1] NCCL INFO NET/Plugin : No plugin found (libnccl-net.so), using internal implementation
machinename:37520:37520 [1] NCCL INFO NCCL_IB_DISABLE set by environment to 1.
machinename:37520:37520 [1] NCCL INFO NET/Socket : Using [0]eno1:192.168.1.3<0>
machinename:37520:37520 [1] NCCL INFO Using network Socket
machinename:37520:38065 [1] NCCL INFO threadThresholds 8/8/64 | 48/8/64 | 8/8/64
machinename:37520:38065 [1] NCCL INFO Trees [0] 2/-1/-1->5->4|4->5->2/-1/-1 [1] 0/-1/-1->5->4|4->5->0/-1/-1
machinename:37519:38064 [0] NCCL INFO threadThresholds 8/8/64 | 48/8/64 | 8/8/64
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

训练过程中master的机器可以看到训练过程

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/478949
推荐阅读
相关标签
  

闽ICP备14008679号