TensorFlow目前进行数据分布式训练的主流方式是Horovod,AIACC-Training 1.5支持使用Horovod API兼容的方式对TensorFlow分布式训练进行加速。本文为您介绍使用AIACC-Training TensorFlow版的具体操作及可能遇到的问题。
适配Horovod API
本小节介绍如何使用Horovod兼容API进行TensorFlow分布式训练的基本步骤,以下操作为原始训练代码适配到AIACC-Traninig的一般过程。
AIACC-Training for TensorFlow支持Horovod API。适配AIACC-Training的方式与Horovod一致,如果您之前是使用Horovod进行分布式训练,只需替换import模块即可。替换内容后的内容如下所示:
import perseus.tensorflow.horovod as hvd
如果您的训练代码是非分布式代码,可以参考以下操作步骤将训练代码升级为Horovod接口的分布式训练代码。
示范用例
AIACC-Training软件包路径中为您提供了针对tf.Session.run()、Keras、Estimator、tf2 eager等训练方式的适配示例代码,您可以通过以下操作体验训练过程。
常见问题
训练过程中出现OOM(显存不足)报错
您可以识别以下几种可能情况并解决。
- 使用
nvidia-smi
检测启动过程中,各显卡占用显存是否均衡增加,单个process对应单个GPU,每个process所使用显存应该接近。 - 若存在多个process绑定同一张卡的情况,需要检查
config.gpu_options.visible_device_list
是否正确设置。 - 若存在显存直接被用尽,您可以尝试增加
config.allow_growth = True
。 - 若启用了XLA,您可以尝试增加参数
config.gpu_options.per_process_gpu_memory_fraction = 0.9
或者0.8
。
如何快速判断是否是梯度通信带来的性能瓶颈
您可以将适配代码中的DistributedOptimizer(opt)
参数注释掉,此时,将不会产生梯度通信,您即可进一步排查数据IO、CPU预处理等可能造成性能瓶颈的原因。
对数据集做shard的注意事项
由于AIACC-Training是由多个进程启动同一份训练代码,因此您需要对数据集做数据集切分为子数据集,使每个进程处理与训练不同的子数据集。TensorFlow为
tf.data.Dataset
类提供了自动切分数据的shard()
接口,您可以结合size()
、local_rank()
或rank()
函数进行自定义的数据切分,例如:dataset = tf.dataset.shard(hvd.size(), hvd.rank())
注意 为保证算法的准确性,shard使用时必须放在数据集shuffle操作之前,且为了保证性能稳定,shard操作不要放在repeat操作之后。否则会带来额外的预处理负担,将严重影响性能。