【Hello AI】使用AIACC-Training MXNet版
由于MXNet支持KVStore和Horovod两种分布式训练方式,因此AIACC-Training 1.5能够支持使用KVStore的方式对MXNet分布式训练进行加速,同时支持Horovod的分布式训练方式,并且能够无缝兼容Horovod的API版本。
快速启用
代码适配与运行
适配AIACC-Training的方式与Horovod一致,如果您之前的训练代码是使用Horovod进行分布式训练,只需要替换import一行即可。替换内容如下:
-
完整的适配过程,请参见适配基于Horovod的API。
-
如果您的训练代码基于KVStore进行分布式训练,修改代码的具体操作,请参见适配基于KVStore的API。
示范用例
AIACC-Training软件包中为您提供了示例代码。您可以通过以下操作体验训练过程。
-
进入示例代码目录。
-
启动分布式训练。
以启动单机8卡的MNiST训练模型为例,示例命令如下:
适配MXNet
适配基于KVStore的API
为了支持InsightFace中特殊的数据+模型并行,Perseus KVStore增加了如下API:
-
local_rank:返回当前GPU worker在本节点内部的编号,以此编号来建立对应的gpu context。您可以在Python内部,直接使用local_rank作为当前的GPU ID来创建context,相较于在启动的Shell脚本中获得当前的GPU编号作为参数传入Python的示范用例,此方式更为便捷。
- init(key_name, ndarray, param_only = false): init方法中增加参数param_only。取值说明如下:
-
true:表示其他参数的同步。当需要一次性同步如feature map数据、AllReduce精度数据等参数时,或者当不使用KVStore进行参数更新时,需要添加param_only参数并设置为true。
-
false:表示普通的梯度同步。
-
push(key_name, ndarray, op = PerseusOp.Sum):push方法中增加了用于同步Softmax layer的输出参数op。该参数的取值范围是Sum、Max、Min。默认值为Sum。
-
使用Perseus KVStore。
您需要参考如下示例修改自身训练代码,新增+后代码import perseus mxnet module,并删除-后代码,替换为KVStore的生成。示例如下:
diff --git a/example/image-classification/common/fit.py b/example/image-classification/common/fit.pyindex 9412b6f..3a6e9a0 100755--- a/example/image-classification/common/fit.py+++ b/example/image-classification/common/fit.py@@ -22,6 +22,7 @@ import time import re import math import mxnet as mx+import perseus.mxnet as perseus_kv def _get_lr_scheduler(args, kv):@@ -146,7 +147,8 @@ def fit(args, network, data_loader, **kwargs): # kvstore- kv = mx.kvstore.create(args.kv_store)+ kv = perseus_kv.create(args.kv_store) if args.kv_store == dist_sync_perseus else mx.kvstore.create(args.kv_store) if args.gc_type != 'none': kv.set_gradient_compression({'type': args.gc_type, 'threshold': args.gc_threshold})
-
将进程绑定至GPU卡。
AIACC-Training通过重载KVStore实现了对MXNet分布式训练的支持,在API上与原生KVStore基本兼容,使用AIACC-Training后,您只需要对模型代码中的ctx设定稍作修改,将单进程绑定至单张GPU卡上即可。
以如下代码片段为例,使用Perseus KVStore新增的API local_rank,将当前process绑定到kv.local_rank所对应的GPU卡上。
-
启动分布式训练任务。
与其它框架类似,Perseus采用MPI的启动方式,并且启动单机多卡与多机多卡的方式基本一致,不再支持原生MXNet下的单机多卡在单一Process中的模式。以下操作以启动4机8卡分布式训练任务为例,带您体验启动过程。
-
准备训练脚本config.sh。
由于该脚本要使用mpirun命令运行,因此需要使用MPI的环境变量来推导此进程所对应的GPU设备ID,然后设定此环境变量,并将此ID作为参数传递到module代码中去创建对应的ctx。脚本示例如下:
-
执行如下命令,启动训练脚本。
其中,mpi_host.txt为普通的MPI machinefile,与MXNet的SSHLauncher的host file类似,简单示例如下:
开始训练之后,每个GPU都是一个单独的进程,有各自的输出。查看多机情况下每个机器的输出,总性能为所有单进程性能的总和。
开源版本MXNet会默认占据系统所有的CPU资源,因此在最初的启动阶段,会占用较多的CPU时间,启动速度较慢。您可以通过设置以下环境变量解决该问题。
适配基于Horovod的API
本小节介绍如何使用Horovod兼容API进行MXNet分布式训练的基本步骤,以下操作为原始训练代码适配到AIACC-Traninig的一般过程。
AIACC-Training for MXNet支持Horovod API。适配AIACC-Training的方式与Horovod一致,如果您之前是使用Horovod进行分布式训练,只需替换import模块即可。替换后的内容如下:
如果您的训练代码是非分布式代码,可以参考以下操作步骤将训练代码升级为Horovod接口的分布式训练代码。
-
在main函数的开头部分,执行如下命令,初始化Perseus Horovod模块。
说明:请务必在使用其他Perseus API之前进行调用。
-
将当前进程绑定对应的GPU卡。
-
创建Optimizer。
通常情况下,模型的学习率需要增大hvd.size()倍。
说明:部分模型不需要增大学习率,如BERT模型,具体请根据训练收敛情况作判断。
-
广播参数。
-
重载Optimizer。
-
启动训练。
以4机8卡的训练为例,启动命令示例如下:
其中,mpi_host.txt为普通的MPI machinefile,与MXNet的SSHLauncher的host file类似,简单示例如下:
开始训练之后,每个GPU都是一个单独的进程,有各自的输出。类比多机情况下每个机器的输出,总性能为所有单process性能的总和。
使用SyncBatchNorm
Perseus的SyncBatchNorm实现基于MXNet官方代码src/operator/contrib/sync_batch_norm-inl.h的计算逻辑,并通过加载libperseus_MXNet.so调用Perseus通信的API,在operator内部实现SyncBatchNorm,且支持单机local模式以及全局global模式。
背景信息
针对object-detection等小Batch Size场景,继续使用每个GPU单独的BatchNorm计算的mean和var信息有较大的偏差,会带来一定的精度损失。通过使用SyncBatchNorm可以弥补对统计信息的内部偏移,真正发挥理论上BN层的作用,即使在大规模分布式的情况下也能达到更高的期望精度。相较于原始BatchNorm,SyncBatchNorm能够在忽略某些训练性能的情况下,提高收敛精度的上限。
操作步骤
-
使用perseus-MXNet-sync-bn.patch补丁。
-
编译MXNet源码。
-
调用SyncBatchNorm模型。
Perseus的SyncBatchNorm实现基于原始MXNet官方代码,因此兼容SyncBatchNorm的原始使用方法,只需将名称从SyncBatchNorm修改为PerseusSyncBatchNorm,并增加参数comm_scope用于修改模式,如mx.gluon.contrib.nn.PerseusSyncBatchNorm(comm_scope=0), mx.sym.contrib.PerseusSyncBatchNorm(comm_scope=0)。
-
修改模式。
模式说明如下:
-
local:局部平均,即每次forward、backward计算均值和方差后,只在单机内部的GPU上分别进行同步。默认为此模式,参数设置为PerseusSyncBatchNorm(comm_scope=0)。
-
global:全局平均,即每次forward、backward计算的均值和方差在全局进行同步,需要修改BN定义的参数为PerseusSyncBatchNorm(comm_scope=1)。
测试精度
以单卡Batch Size为2,单机8卡的训练为例,使用基于GluonCV实现的Faster RCNN模型适配Perseus,然后进行原始BatchNorm与PerseusSyncBatchNorm的精度对比,测试效果图如下:
如上图所示,从第1个Epoch开始,到第20个Epoch结束,PerseusSyncBatchNorm达到的精度均高于BatchNorm,最高的mAP从31.3%提升至34.6%。
常见问题
额外显存占用问题
以单机8卡为例,0号卡被其余7个process均占用了200 MB到500 MB显存,从而导致0号卡显存被耗尽。
该问题的根因在于MXNet内部的cpu_pinned memory分配机制默认使用0号卡。您可以参考上文步骤2,重新绑定GPU卡。
运行时显示Undefined symbols
运行时显示NDArray相关的symbol没有定义,即Undefined symbols。
该问题由于pip安装了1.4之前版本的MXNet,导致没有导出libMXNet.so中对于Perseus必要的symbol。您可以将MXNet升级到1.4或以上版本,也可以重新编译安装MXNet。
启动速度较慢
您可以尝试以下方法改善该问题:
-
检查CPU的负载,若占比很高可尝试进行以下设置:
-
减小preprocess的线程数。
Perseus下训练模式为单process、单GPU,如果默认线程数设置过大,可以根据单节点的GPU数目,等比例缩小preprocess的线程数。例如preprocess的线程数默认值为24,而单节点GPU数目为8,那么您可以将preprocess的线程数降低为3或4。
单机时正常,多机时异常退出
可能是由于人为导致多机中存在正在运行训练的机器,则运行多机会发生create cusolver handle failed报错,您可以使用mpirun执行nvidia-smi检查多机中是否存在运行的机器。
好啦!小弹的分享到此为止。我们更欢迎您分享您对阿里云产品的设想、对功能的建议或者各种吐槽,请扫描提交问卷并获得社区积分或精美礼品一份。https://survey.aliyun.com/apps/zhiliao/P4y44bm_8
【扫码填写上方调研问卷】
欢迎每位来到弹性计算的开发者们来反馈问题哦~