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

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

flyfish

环境:

Python>=3.6.0 
PyTorch>=1.7
YOLOv5:v5

1 CUDA_VISIBLE_DEVICES环境变量

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

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

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

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

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 ''

第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 ''

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

实际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 ''

实际第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 ''

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

这里用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

然后把数据集拷贝到/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

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

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

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

4 异常情况的处理

会产生如下错误
情况1

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

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

查看包含python的进行

ps -aux | grep 进程服务名
ps -aux | grep python

杀死进程

sudo kill 进程号(PID)
sudo kill 1111

情况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

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

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

终端执行

export NCCL_DEBUG=INFO
export NCCL_IB_DISABLE=1
export NCCL_SOCKET_IFNAME=eno1

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

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

NCCL INFO Call to connect returned Connection refused, retrying

或者

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]

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!

slave的机器运行

nc 192.168.1.2 5678

或者执行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

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

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

firewall-cmd --zone=trusted --list-all

4.3 firewalld防火墙操作

查看防火墙状态

systemctl status firewalld

暂时关闭防火墙

systemctl stop firewalld

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

systemctl disable firewalld 

4.4 ufw防火墙操作

查看防火墙状态

sudo ufw status

永久关闭防火墙

sudo ufw disable

开启防火墙

sudo ufw enable

当正确执行后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

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

版权声明:本文为CSDN博主「TheOldManAndTheSea」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/flyfish1986/article/details/119786227

TheOldManAndTheSea

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

深度学习之目标检测YOLOv5

一.简介 YOLOV4出现之后不久,YOLOv5横空出世。YOLOv5在YOLOv4算法的基础上做了进一步的改进,检测性能得到进一步的提升。虽然YOLOv5算法并没有与YOLOv4算法进行性能比较与分析&#xff0

YOLO-V3-SPP详细解析

YOLO-V3-SPP 继前两篇简单的YOLO博文 YOLO-V1 论文理解《You Only Look Once: Unified, Real-Time Object Detection》YOLO-V2论文理解《YOLO9000: Bet