文章目录[隐藏]
目标检测 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
暂无评论