参考资料:Framework(二):分布式训练、【table master mmocr】Windows下模型训练的配置、PyTorch分布式训练简明教程(2022更新版)、【pytorch记录】pytorch的分布式 torch.distributed.launch 命令在做什么呢
1. 一些概念
- 分布式训练:将模型的训练交给多张GPU完成。分布式训练有多种模式,其中最常见的应该是数据并行模式、也是mmdetection3d和pytorch使用的模式。数据并行,就是将一个批次(batch)的输入数据分成 N N N份输入 N N N个GPU中,模型也复制 N N N份存入这些GPU中,在每个GPU中进行前向传播后,在反向传播时,使用 各卡上的平均梯度 更新网络参数。
- 节点:可看作独立的计算机系统,可通过网络连接到其它节点。
2. dist_train.sh简介
mmdetection3d提供了分布式训练的代码,位于tools/dist_train.sh
文件中,如下所示:
#!/usr/bin/env bash
CONFIG=$1 # 配置文件路径;值为第1个命令行参数
GPUS=$2 # 每个节点上的GPU数量;值为输第2个命令行参数
NNODES=${NNODES:-1} # 节点数;若输入命令不指定NNODES,则取默认值1
NODE_RANK=${NODE_RANK:-0} # 当前节点位次;若输入命令不指定NODE_RANK,则取默认值0
PORT=${PORT:-29500} # 主节点端口号;若输入命令不指定PORT,则取默认值29500
MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"} # 主节点地址;若输入命令不指定MASTER_ADDR,则取默认值"127.0.0.1"
PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ # 将当前脚本所在目录的父目录添加到PYTHONPATH环境变量中,确保导入的模块能够正确找到
python -m torch.distributed.launch \ # 调用库,启动分布式训练
--nnodes=$NNODES \ # 节点数
--node_rank=$NODE_RANK \ # 当前节点的位次
--master_addr=$MASTER_ADDR \ # 主节点地址
--nproc_per_node=$GPUS \ # 每个节点上的GPU数量
--master_port=$PORT \ # 主节点端口号
$(dirname "$0")/train.py \ # 运行当前脚本所在目录下的train.py训练脚本
$CONFIG \ # 配置文件路径
--seed 0 \ # 随机数种子
--launcher pytorch ${@:3} # 使用pytorch的分布式训练方式,并将剩余的命令行参数传递给训练脚本
3. dist_train.sh涉及到的Shell语法
$
+ 数字:$
后的数字为几就表示第几个命令行参数(从1开始)。如$1
表示第1个命令行参数。${变量名:-默认值}
:表示变量名
的值为空时,返回默认值
;否则返回变量名
的值。$0
:返回此脚本文件的文件路径(包含文件名),如对dist_train.sh
来说即mmdetection3d所在目录/tools/dist_train.sh
。$(dirname $0)
:表示此脚本文件的所在目录(如对dist_train.sh
来说即mmdetection3d所在目录/tools
)。$(dirname $0)/..
:表示所在目录的上一级目录(如对dist_train.sh
来说即mmdetection3d所在目录
)。PYTHONPATH
:环境变量,表示python导入模块时的搜索路径。:
:用于分隔两个路径。如PYTHONPATH=路径1:路径2
即,将路径1和路径2都包含到环境变量PYTHONPATH中,以便python脚本导入各路径下的模块。python -m 模块名
:表示把库中的模块当做脚本运行(即执行__main__()
函数或__main__.py
文件)。${@:3}
表示第三个及以后的命令行参数。在运行dist_train.sh
的命令中,这些参数需要能跟在tools/train.py
的python运行命令python tools/train.py ${CONFIG}
之后(取决于train.py
的args配置)。
4. 运行dist_train.sh的方法
在终端输入bash 此文件路径/dist_train.py 配置文件路径 GPU数量 其它参数
格式的命令,就可以开始进行分布式训练。
4.1 单机多卡训练
当分布式训练的范围为一台计算机上的多个GPU时,无需修改NNODES
,NODE_RANK
,PORT
或MASTER_ADDR
。
例如单机4卡训练,设配置文件为/xxx/mmdetection3d/configs/project/model_cfg.py
,期望的工作目录为/xxx/project/work_dir/
,此时的运行路径(终端上显示的目前所在目录)位于/xxx/mmdetection3d
下,则在终端输入如下命令:
bash tools/dist_train.sh configs/project/model_cfg.py 4 \
--work-dir /xxx/project/work_dir/
4.2 多机多卡训练
当分布式训练的范围为在多台计算机上的多个GPU时,需要修改NNODES
,NODE_RANK
,PORT
或MASTER_ADDR
。此时NNODES
为计算机数(节点数),而每个计算机有不同的NODE_RANK
(0,1,2,…),其中NODE_RANK=0
的为主机。MASTER_ADDR
为主机的IP地址,PORT
为主机的自由端口。
多机多卡训练时,需要在每个节点分别输入命令。在终端输入的命令为,在4.1节命令的基础上,在bash
前加上如NNODES=2 NODE_RANK=1
等语句。
mmdetection中的分布式测试与分布式训练类似,可自行阅读
dist_test.sh
文件确定相应的运行命令。
5. 可能的报错
当数据没有经过模型的某部分就计算损失时(常见于使用if
判断数据流向的情况下),会报如下错误:
RuntimeError: Expected to have finished reduction in the prior iteration before starting a new one. This error indicates that your module has parameters that were not used in producing loss. You can enable unused parameter detection by (1) passing the keyword argument `find_unused_parameters=True` to `torch.nn.parallel.DistributedDataParallel`; (2) making sure all `forward` function outputs participate in calculating loss. If you already have done the above two steps, then the distributed data parallel module wasn’t able to locate the output tensors in the return value of your module’s `forward` function. Please include the loss function and the structure of the return value of `forward` of your module when reporting this issue (e.g. list, dict, iterable).
这时,可参考报错中的(1)处理。在mmdetection3d中的处理方法为,在模型的配置文件中加入find_unused_parameters=True
。