该专题是我本科毕设的各个知识点介绍和分析,以及一些实验结果展示。本科毕业了,研究生开学,又进入了一个新的学习阶段,那么趁着有时间就总结一下这个课题,分享给大家~
如果你觉得对你有帮助,给我点赞吧!小女子能力有限,也欢迎大家批评指正。
好啦,讲完基础知识,我们开始分布式训练吧(当时做毕设时学校提供的硬件只有cpu,gpu的以后我再试一试)。这部分会涉及代码,如果有疑问的可以问我哈。
Github链接:https://github.com/liyun-lu/CNN-distributed-training-pytorch
目录
卷积神经网络的分布式训练(三)分布式训练实战
一、分布式整体方法设计
我们先来看图,比较直观。
二、分布式训练的实现
处理好数据和建立好模型之后,可以开始对模型进行分布式训练。
分布式训练的过程主要有四个重要的步骤,四个步骤分别是:
1、消息通信
首先,要让所有要运行的机器连接起来进行通信。通信的方式有两种,一是基于TCP/IP协议的网络通信,二是通过分布式共享文件系统通信。
消息通信是分布式训练的核心,这决定了机器之间是否能够连接起来。在PyTorch框架中,使用torch.distributed.init_process_group()函数来初始化进程组以实现机器之间的消息通信。其接口的具体设计如下:
torch.distributed.init_process_group(backend= args.dist_backend,
init_method=args.dist_url,
timeout=datetime.timedelta(time),
world_size=args.world_size,
rank=args.rank)
(1)backend=args.dist_backend
这个参数描述了选择的后端,目前最新版本的PyTorch框架提供的后端一共有三种,分别是NCCL、Gloo、MPI,GPU的分布式训练使用的是NCCL,CPU的分布式训练使用的是Gloo,特殊情况下才是用MPI。本次实验使用的计算平台上的机器是通过InfiniBand互连的 CPU 主机,因此使用Gloo后端。
(2)init_method=args.dist_url
init_method参数描述了进程的具体通信方式,本次实验使用的进程初始化方式有以下两种。
①TCP/IP方式初始化,如:init_method=tcp://10.172.1.2:22225。这种方式包含了进程为0的机器的IP地址和端口号,这种方式下机器必须要能够联网通信,所以要确保防火墙和网络设置正确。
②分布式共享文件系统初始化,如init_method=file:///home/share/1。在通信的进程之间存在一个可直接访问的共享空间,这个共享空间可以是虚拟的,它可能分布在不同的机器的私有磁盘上。这个共享空间也可以是一个真实的共享磁盘。
(3)timeout=datetime.timedelta(time)
这个参数定义了进程组运行时的超时时间。当一个进程运行了之后,如果其他的进程迟迟不运行,让运行的进程一直等待连接,如果超过限定的时间,进程就会被杀死。
(4)world_size=args.world_size
这个参数定义了进程的个数,如果是CPU主机的集群就是节点的个数,如果是有GPU的集群就是GPU的卡数。
(5)rank=args.rank
这个参数定义了进程的ID。需要注意的是,每个进程执行的顺序必须要与它的ID相一致,否则就会造成进程的死锁
2、参数同步
PyTorch框架的参数同步机制是Ring Allreduce架构,要调用分布式并行模型(DistributedDataParalle,DDP)接口将模型转换为分布式并行模型,这样不同机器上的模型才能进行参数的同步。
ddp_model = torch.nn.parallel.DistributedDataParallel(model) if use_cuda else torch.nn.parallel.DistributedDataParallelCPU(model)
3、数据划分
PyTorch框架的分布式采用数据并行,所以要调用Distributed Sampler接口将数据平均划分到不同机器上,主要分为三个步骤:
(1)数据定义
train_data = MOFsDataset(data_size=args.data_size, file_path=train_data_path)
(2)数据划分
train_sampler = DistributedSampler(train_data, num_replicas=args.world_size, rank=args.rank)
train_data是我们定义好的数据集;
num_replicas=args.world_size定义了分布式训练进程的个数;rank=args.rank是进程的编号,指定了将数据划分给哪一个进程。
(3)数据加载
train_loader = Data.DataLoader(dataset=train_data, batch_size=args.batch_size, shuffle=True,
sampler=train_sampler)
sampler=train_sampler是用来防止机器加载全部的数据,而是每台机器只加载一部分的数据进行训练。
4、执行
当我们把程序编写好,并且数据、模型和训练脚本都上传到计算机集群上后,我们可以通过SSH远程登录,创建会话,执行训练脚本开始分布式训练。因为本次实验使用的计算平台并没有使用Slurm集群管理系统,因此执行的办法只能是在多台机器上分别执行训练脚本。例如,在三台机器上进行分布式训练,其执行语句是:
机器一:python train.py --rank 0 --world-size 3
机器二:python train.py --rank 1 --world-size 3
机器三:python train.py --rank 2 --world-size 3
三、实验环境配置
1、硬件环境
2、软件环境
①操作系统:CentOS Linux release 7.3.1611
②PyTorch版本:PyTorch 1.3.1
③Python版本:Python 3.7.3
④网络带宽:56g fdr InfiniBand
⑤其他:安装Secure Shell(SSH)远程登录管理安全协议
四、实验结果展示及分析
1、实验结果展示
2、实验结果分析
(1)节点个数的对比
可以明显的看到,随着机器的数目增多,训练的时间就越短。这毫无疑问的说明了:分布式训练可以减少训练神经网络模型的时间,大大提高效率。
(2)批大小的对比
上图数据量是:10000
下图数据量是:55000
说明了:Batch_size的规模大小对分布式训练很重要。这是和机器的存储大小或资源调度有关系的。因此,在分布式训练中,我们应该要充分考虑系统的资源,适当地调整训练的批大小,不能盲目的增大,只有选择合适的批大小才能实现分布式训练性能的最优化。
(3)通信方式的对比
从图中可以看到,不论训练的批大小是多少,不同的通信方式下训练时间是差不多一样的,这说明我使用的计算平台的网络通信并没有对分布式训练造成很大的影响,因为所有的节点是通过InfiniBand连接的,带宽还是很快的。