天天看点

pytorch apex 混合精度训练和horovod分布式训练

转载请注明出处:

https://mp.csdn.net/postedit/103600124

如果你基于pytorch训练模型,然后,你想加快训练速度,增大batch_size,或者,你有一台配置多张显卡的机器,还是说你有多台带显卡机器,你想利用起来,分布式训练你的模型,那这篇文章对你有点用。

基于以上的需求,我趟了一遍,记录下我遇到的坑都有哪些,怎么跨过去。

先看一下我主要的工具:anaconda,apex,horovod。就这三个。

1. Conda 环境

接下来的工作,全部在conda环境内完成,所以安装一个最新版的conda,然后创建一个新的环境,并且激活这个环境。

在这个全新的环境里面,安装模型训练需要的所有package。

三种配置conda新环境的方法:

a.最最简单的办法,直接拷贝path_to_conda/anaconda3/envs下面的环境,移植到新机器对应环境下。但是这个方法有前提条件:首先是,最好新旧机器的硬件配置、系统版本是一样的;第二是环境内的package的安装过程不需要配置额外参数。

b.导出conda 环境,在新机器上创建。显然这种方式的前提和第一种相似。

conda env export > environment.yaml  #conda导出已有环境

    conda env create -f environment.yaml #在新机器上创建
           

c.当环境无法移植进来时,只能一个一个安装

安装好环境后建议检查以下cuda和pytorch版本是否匹配,在python脚本内使用以下方法检查:

import torch

    torch.cuda.is_available()
           

2. 混合精度训练和单机多卡分布式训练

Apex 是Nvidia开发维护的工具,使用简便的API实现混合精度训练和分布式训练

根据以下链接安装apex,

https://github.com/NVIDIA/apex#quick-start

pip install -v --no-cache-dir --global-option="--pyprof" --global-option="--cpp_ext" --global-option="--cuda_ext" ./
           

此处,需要确定pip的路径,必须是你想要的env内的pip,不然可能会安装到base env内。

一种简单的办法是path_to_conda/anaconda3/envs/bin/pip 安装,前提是你的环境装上了pip。

以上链接给出了混合精度和分布式的example,按照例子,增加几行代码即可。

启动分布式训练的命令:

python -m torch.distributed.launch --nproc_per_node=2 train.py
           

如果你要指定使用某几张显卡:

CUDA_VISIBLE_DEVICES=4,5 python -m torch.distributed.launch --nproc_per_node=2 train.py
           

Apex内的混合精度训练amp使用起来后,可以看到同样的数据,同样的batch size时,显存消耗减少到原来的60%,同时GPU-Util保持在较高值。在2080Ti的机器,batch size原来至多能达到12,使用apex.amp后可以达到24,效果显著。

而Apex的分布式训练DistributedDataParallel可以使模型在单机多卡上分布均匀的训练,同时GPU-Util保持在较高值。

另外,apex的分布式我只用到了单机多卡的训练,官方仅给出了单机多卡的训练方式,未知是否可以以及如何配置多机多卡训练。

3. 多机多卡训练工具horovod

3.1 尝试pytorch 分布式

选择horovod是因为它是目前多机多卡训练性能最优的工具(其实是尝试了pytorch自带的分布式工具失败后,调转枪头。。。)

关于尝试pytorch自带方法

     torch.nn.parallel.DistributedDataParallel

选用NCCL后端,遇到

    “NCCL error… unhandled_cuda_error”

追溯bug查到源码

    torch/nn/parallel/distributed.py    

    _distributed_broadcast_coalesced

无法往下追溯。

切换gloo后端,遇到问题:

    ”terminate called after throwing an instance of ‘gloo::EnforceNotMet’”

这两个问题都没有解决,促使我回头去整horovod。

 3.2安装horovod

https://github.com/horovod/horovod

按照以上链接指引,安装horovod。

首先是要安装Open MPI,第一次安装直接按照官方文档:

https://www.open-mpi.org/faq/?category=building#easy-build

运行分布式训练的时候,遇到问题:

    ORTE was unable to reliably start one or more daemons.

根据以下horovod的troubleshooting文档(**仔细阅读,帮你避坑**)

https://github.com/horovod/horovod/blob/master/docs/troubleshooting.rst

重新安装:

$ wget https://www.open-mpi.org/software/ompi/v4.0/downloads/openmpi-4.0.0.tar.gz

    $ tar zxf openmpi-4.0.0.tar.gz

    $ cd openmpi-4.0.0

    $ ./configure --enable-orterun-prefix-by-default

    $ make -j $(nproc) all

    $ make install

    $ ldconfig
           

重新安装openMPI后需要重新安装horovod。

 3.3  horovod with pytorch

https://github.com/horovod/horovod/blob/master/docs/pytorch.rst

这里概要了代码所需要的修改步骤。

 3.3.1 一些分布式的概念

https://pytorch.apachecn.org/docs/1.0/aws_distributed_training_tutorial.html

详细阅读这个文档,可以对分布式的常用变量和步骤有所了解后,你应该可以知道以下的启动命令怎么设置了。

horovodrun -np 16 -H server1:4,server2:4,server3:4,server4:4 python train.py
           

这条命令意思是:要在四台机器上启动分布式,server替换为对应机器的IP,‘:’后面表示该机器配备了几张显卡, ‘-np’ 表示总共起几个进程,相应也即是几张显卡。

确认一点我之前的疑问:horovod可以自动去启动从机内正确的conda环境下的python运行代码。这显然是有前提的:所用的机器配置和环境必须一模一样。

所以,只要在主机的运行conda env内,运行以上命令即可。这一点相比pytorch的分布式,需要在每台机器启动命令,方便的多。不过horovod需要你告诉它训练脚本的绝对路径,以及代码内也不要使用相对路径。

3.4 机器之间SSH免密登录

https://www.cnblogs.com/like1tree/p/9667751.html

3.5 网络接口配置

ubuntu下,ifconfig查看网络接口名称,使用内网地址对应的网络名称,我的是enp0s31f6,设置环境变量:

    $ export NCCL_SOCKET_IFNAME=enp0s31f6

    $ export GLOO_SOCKET_IFNAME=enp0s31f6 (如果后端使用的是gloo)

可以多机多卡运行代码。

4. apex和horovod一起用

这两者可以一起用,其实说的是apex.amp和horovod搭配使用。这样会让你单机减少显存开销同时多机一起训练,双剑合璧的感觉。

用法和很简单,先初始化horovd优化器,再初始化amp优化器,截止目前为止,两个工具的东家并没有官方地相互支持。因此这两个优化器并不能完美兼容,在接下来的训练过程中,horovod优化器需要调用的成员变量amp优化器并没有。

horovod开发者在git issue上给了以下方案:

with amp.scale_loss(loss, optimizer) as scaled_loss:

        scaled_loss.backward()

        if FLAGS_horovod:

            optimizer.synchronize()

            with optimizer.skip_synchronize():

                optimizer.step()
           

5.horovod 性能分析

我的网络环境配置是千兆交换机,1000Mb/s带宽,也就是理论每秒最多达到125MB/s带宽。实测大约能达到80MB/s。

在horovod运行时,节点机器之间来回传输数据速度大约是60MB/s,一个网络模型有250MB,因此每一个batch传输一次数据,完成all_reduce,就需要4-5秒时间。这样训练过程,显卡大量时间闲置,等待数据。

解决办法有三种:

a. 性能最优: 更改硬件,将多个显卡放在同一台主机。省去传输时间开销。

b.使用万兆交换机,1G带宽网卡,提高数据传输效率。

c.代码内修改不同机器之间权重的同步频率,由每个batch同步改为 N个batch 后同步。验证 horovod 优化器内参数backward_passes_per_step是控制多个batch 才做一次all_reduce,但是不能控制数据回传频率。因此该方案还需要研究下怎么做。

继续阅读