分布式GPU训练优秀实践
一个简单的验证当前的训练程序是否需要进一步优化性能的方法, 是查看GPU的计算利用率 [2] ,通常用 命令查看。 如果GPU利用率较低,则可能存在较大的优化空间。 下面主要从环境变量设置、训练策略设置、数据准备和训练方式四个方向介绍GPU分布式训练中常用的方法。
环境变量设置表
说明:
- 关于
FLAGS_sync_nccl_allreduce
,配置FLAGS_sync_nccl_allreduce=1
让每次allreduce操作都等待完成,可以提升性能,详细原因和分析可以参考:。 - 关于
FLAGS_fraction_of_gpu_memory_to_use
,配置FLAGS_fraction_of_gpu_memory_to_use=0.95
,0.95是指95%的显存会预先分配。设置的范围是0.0~1.0。注意,设置成0.0会让每次显存分配都调用cudaMalloc
这样会极大的降低训练性能。 - 关于
NCCL_IB_DISABLE
,在使用NCCL2模式训练时,其会默认尝试开启RDMA通信,如果系统不支持,则会自动降级为使用TCP通信。可以通过打开环境变量NCCL_DEBUG=INFO
查看NCCL是否选择了开启RDMA通信。如果需要强制使用TCP方式通信,可以设置NCCL_IB_DISABLE=1
。
训练参数设置表
选项 | 类型 | 默认值 | 说明 |
---|---|---|---|
num_threads | int | 1 | CPU线程数 |
int | 1 | nccl通信器数量 | |
fuse_all_reduce_ops | bool | False | 多卡训练时,将AllReduce操纵进行融合 |
use_hierarchical_allreduce | bool | False | 分级式reduce |
num_iteration_per_drop_scope | int | 1 | scope drop频率,设置每隔几个batch的迭代之后执行一次清理scope |
fetch_frequency | int | 1 | fetch的刷新频率 |
说明:
- 关于设置合适的CPU线程数
num_threads
和nccl通信器数量nccl_comm_num
。PaddlePaddle Fluid使用“线程池” [3] 模型调度并执行Op,Op在启动GPU计算之前,通常需要CPU的协助,然而如果Op本身占用时间很小,“线程池”模型下又会带来额外的调度开销。使用多进程模式时,如果神经网络的计算图 [4] 节点间有较高的并发度,即使每个进程只在一个GPU上运行,使用多个线程可以更大限度的提升GPU利用率。nccl通信器数量nccl_comm_num
可以加快GPU之间的通信效率,建议单机设置为1,多机设置为2。针对CPU线程数num_threads
,建议单机设置为1,多机设置为nccl_comm_num
+1。 - 关于AllReduce融合
fuse_all_reduce_ops
,默认情况下会将同一layer中参数的梯度的AllReduce操作合并成一个,比如对于fluid.layers.fc
中有Weight和Bias两个参数,打开该选项之后,原本需要两次AllReduce操作,现在只用一次AllReduce 操作。此外,为支持更大粒度的参数梯度融合,Paddle提供了FLAGS_fuse_parameter_memory_size
和 两个环境变量选项。用户可以指定融合AllReduce操作之后,每个AllReduce操作的梯度字节数,比如希望每次AllReduce调用传输16MB的梯度,export FLAGS_fuse_parameter_memory_size=16
,经验值为总通信量的十分之一。可以指定每次AllReduce操作的最大层数,即到达该层数就进行AllReduce,如指定50层export FLAGS_fuse_parameter_groups_size=50
。注意:目前不支持sparse参数梯度。 - 关于降低scope drop频率
num_iteration_per_drop_scope
和fetch频率fetch_frequency
。减少scope drop和fetch频率,可以减少频繁的变量内存申请、释放和拷贝,从而提升性能。 - 其他训练策略的参数可以参考 这里 。
设置这些参数可以参考:
如果可能,使用GPU完成部分数据预处理,比如图片Tensor的归一化:
对输入的图片Tensor,使用 fluid.layers
完成图片数据归一化预处理, 这样可以减轻CPU预处理数据的负担,提升总体训练速度。
2、优化reader性能
数据读取的优化在GPU训练中至关重要,尤其在不断增加batch_size提升吞吐时,计算对reader性能会有更高对要求, 优化reader性能需要考虑的点包括:
1、Local SGD
GPU多机多卡同步训练过程中存在慢trainer现象, 即每步中训练快的trainer的同步通信需要等待训练慢的trainer。 由于每步中慢trainer的rank具有随机性, 因此我们使用局部异步训练的方式——LocalSGD, 通过多步异步训练(无通信阻塞)实现慢trainer时间均摊, 从而提升同步训练性能。 Local SGD训练方式主要有三个参数,分别是:
选项 | 类型 | 可选值 | 说明 |
---|---|---|---|
use_local_sgd | bool | False/True | 是否开启Local SGD,默认不开启 |
local_sgd_is_warm_steps | int | 大于0 | 训练多少轮之后才使用Local SGD方式训练 |
local_sgd_steps | int | 大于0 | Local SGD的步长 |
说明:
- Local SGD步长 ,一般该值越大,通信次数越少,训练速度越快,但随之而来的时模型精度下降。经验值设置为2或者4。
具体的Local SGD的训练代码可以参考:
2、使用混合精度训练
V100 GPU提供了 Tensor Core 可以在混合精度计算 场景极大的提升性能。使用混合精度计算的例子可以参考:
附录
GPU利用率:这里指GPU计算能力被使用部分所占的百分比 |
[3] |