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,但是不能控制数据回传频率。因此该方案还需要研究下怎么做。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PyTorch AMP(Automatic Mixed Precision)是一种用于深度学习模型训练的加速技术,它可以将低精度的计算操作与高精度的计算操作混合使用,从而在保持模型精度的同时提高训练速度和减少显存占用。具体来说,PyTorch AMP 使用了 NVIDIA Apex 库中的混合精度训练技术,将一些计算操作转换为 FP16(半精度浮点数)格式,从而减少计算和存储的需求。 实现 PyTorch AMP 混合精度训练的步骤如下: 1. 引入必要的库和模块: ```python import torch from torch.cuda.amp import autocast, GradScaler ``` 2. 定义模型和优化器: ```python model = MyModel() optimizer = torch.optim.SGD(model.parameters(), lr=1e-3) ``` 3. 定义混合精度训练相关的参数: ```python scaler = GradScaler() ``` 4. 在训练过程中使用 autocast 和 GradScaler 完成混合精度训练: ```python for data, target in train_loader: # 将数据和目标值转换为合适的类型 data, target = data.to(device), target.to(device) # 使用 autocast 进行前向计算和反向传播 with autocast(): output = model(data) loss = loss_function(output, target) # 使用 GradScaler 进行梯度缩放和反向传播 scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() # 清空梯度 optimizer.zero_grad() ``` 在上面的代码中,autocast 用于自动将一些计算操作转换为 FP16 格式,从而提高训练速度;GradScaler 用于梯度缩放和反向传播,确保在低精度的计算下仍能保持模型精度。 需要注意的是,不是所有的计算操作都能够使用 FP16 格式,一些数值较大的计算操作可能会出现溢出等问题。因此,在使用 PyTorch AMP 进行混合精度训练时,需要仔细选择转换的计算操作,并且进行必要的检查和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值