分布式训练基本原理
近十年来,深度学习技术不断刷新视觉、自然语言、语音、搜索、推荐等领域各种任务的纪录。这其中的原因,用一个关键词描述就是“大规模”。大规模的数据使得模型有足够的知识可以记忆,大规模参数量的模型使得模型本身有能力记忆更多的数据,大规模高性能的算力(以GPU为典型代表)使得模型的训练速度有百倍甚至千倍的提升。数据、模型、算力的发展催生了大规模深度学习这个领域,如何进行多机任务的拆分、如何配置集群训练资源、如何平衡训练速度和收敛速度、如何训练单机无法训练的模型、弹性训练与容错等都是这个方向重点研究的问题。分布式训练正是解决上述问题,提升训练效率的最有效手段。分布式训练的核心目的是加快模型的训练速度,如何加快训练速度的呢?首先,可以把单机单卡的模型训练过程看成是一个流水线生产的过程,数据就是输入生产线的原材料,而模型的网络可以看成生产线上的加工设备。数据经过第一个生产环节处理后,得到的结果发给下一个环节处理,后面环节依次类推。后来工厂要求提高生产效率,最直观的方法就是再加一条生产线,分出一部分原材料交由新生产线处理,这样生产的时间直接压缩了一半,有哪些生产环节可以同时做的,可以直接对单个生产线进行拆分重组。分布式训练采用了同样的方式,即将训练任务按照一定方法拆分到多个计算节点进行计算,再按照一定的方法对拆分后计算得到的信息,一般是梯度信息或基于梯度更新后的参数信息,进行聚合。这个拆分可以采用多种不同的方式,一般被统称为“并行方式”,而信息聚合的方式可以称为“模型更新传递方式”。下面将从这两个方面对分布式训练进行介绍。
分布式训练的并行方式
在分布式训练过程中,并不是所有的训练任务都可以拆分,当前常用的拆分方式有如下几种:
- 数据并行:将数据集切分放到各计算节点,每个计算节点的计算内容完全一致,并在多个计算节点之间传递模型参数,通常称这种并行训练方法为数据并行。数据并行可以解决数据集过大无法在单机高效率训练的问题,也是工业生产中最常用的并行方法。
- 模型并行:通常指将模型单个算子计算分治到多个硬件设备上并发计算,以达到计算单个算子计算速度的目的。一般会将单个算子的计算,利用模型并行的方式分配在配置相同的几个硬件上,进行模型存储和计算,以保证计算步调一致。
- 流水线并行:一般是指将模型的不同算子,拆分到不同的硬件设备上进行计算,通过生产者-消费者的方式(流水线)完成不同设备之间的数据流通。深度学习中的跨设备交换数据场景很多,例如硬盘数据到内存,内存数据到显存,内存数据到网卡等,由于不同硬件之间处理数据的速度通常不一致,通常会采用流水线并行的方式进行训练效率最大化。
在工业场景的实践中,分布式模型训练也会采用不同并行方式的组合,例如数据并行与模型并行结合,数据并行与流水线并行结合等。其中数据并行的应用范围最广,像搜索、推荐领域的深度学习模型,通常都是采用数据并行的方式进行切分的,而后面讲到的飞桨paddle分布式训练的几种架构方案中,基本都采用了数据并行方式,然后再与其它并行方式配合使用。
分布式训练中的模型参数传递
虽然训练任务可以拆分,但是在一个Batch的数据训练完成后,下一个Batch的数据训练开始之前,必须先更新Worker上的模型参数,因此模型参数的更新传递是分布式训练中非常重要的一环,模型参数信息的传递方式和更新频率都会直接影响模型的最终效果:
- 参数传递方式很大程度决定于参与分布式训练的硬件资源选用的组织架构类型,通常有两种架构方式,参数服务器架构和Collective架构,后面将会位大家详细介绍。
- 参数更新频率是指以什么样的节奏更新参数。这同样有两种方式,一个是同步,即所有Worker节点,共同完成一个Batch的数据训练后统一更新,另一个是异步,每个Worker节点,完成自己负责的数据部分的训练后,就直接开始更新参数。
下面先来看下分布式训练的架构。
分布式训练架构
在分布式训练的两种常用架构中, Collective架构多被用于视觉、自然语言处理等需要复杂网络计算的模型训练任务场景,而参数服务器架构多被用于搜索推荐场景中大规模稀疏特征模型的训练任务。下面会分别具体介绍下这两种架构。
参数服务器架构
参数服务器架构是一种中心化架构,该架构采用将模型参数进行中心化管理的方式实现模型参数的更新和分发。参数服务器架构有两个角色Server与Worker,值得注意的是,Server与Worker不一定对应实际的硬件,可以理解为是进程。Server负责参数的分片存储与更新,Worker则会保存有完整的模型网络结构,用于执行模型的前向与反向计算。常规的参数服务器的Worker节点,需要使用统一型号的CPU或GPU机器完成模型训练。
每个Worker在执行每一步训练时,都可以向参数服务器发出请求,获取全局最新的模型参数,并基于最新的模型参数计算当前数据的模型梯度。当Worker基于最新的模型参数完成模型梯度的计算后,会将模型梯度发回给Server。参数服务器架构通常可以对模型参数的存储进行分布式保存,因此对于存储超大规模模型参数的训练场景十分友好,这也是该架构在个性化推荐场景中,应该任务中需要保存的海量稀疏特征对应的模型参数,通常就只能采用参数服务器架构才能实现。
Collective架构
Collective架构是一种去中心化的架构,也是近年来非常流行的分布式训练架构。该架构没有所谓管理模型参数的中心节点,每个设备都是Worker,这个Worker同样是进程的概念。每个Worker负责模型的训练同时还需要掌握当前最新的全局信息。
在Collective架构中,多节点间的参数信息的传输通常是各个Worker之间多次点对点通信完成的,比较经典的通信算法,例如Baidu Ring
All Reduce,可以采用较少的点对点通信轮数完成全局节点的模型参数传输。Collective架构通常在现代高性能AI芯片中使用较多,这种架构对计算芯片的算力和芯片之间的网络互联要求较高。高性能计算的AI芯片例如GPU,芯片之间的高速网络互联例如NVLINK, InfiniBand,都加快的Collective架构的发展。Collective训练架构对于计算密集的任务非常友好,熟知的经典模型,例如机器翻译中的Transformer,图像分类中的ResNet50,语音识别中的DeepSpeech2通常都是采用这种训练架构完成。
参数更新频率
如前所述,参数同步的方式与训练架构的选取有关,即是统一由Server更新和分发,还是Worker间相互同步,这是关系到训练效果的重要因素之一,而另一个因素就是参数同步的频率,即什么时候同步参数,用户同样可以选择两种方式的一种,即同步和异步,下面将会分布进行介绍。
同步训练
同步训练通常是指每个Worker在模型训练的每一步都进行一次模型参数的全局更新,参数服务器架构和Collective架构都可以采用这种方式。这种方式在本质上与单机训练一致,只是单步训练的总数据量会更大。值得一提的是,在参数服务器架构下的同步训练,优化算法的执行是发生在参数服务器一端,而在Collective架构下,通过对每一步所有样本产生的模型参数梯度进行全局同步后,由每个Worker执行优化算法,相当于优化了全局的模型参数。下图展示了单机SGD算法,基于Collective架构的同步SGD算法,基于参数服务器的异步SGD算法在计算步骤上的区别。可以看到Collective架构发生通信的位置比较集中,并行是通过与正在训练的其他节点进行Collective通信完成,每个节点只需要关注自己即可。参数服务器架构在获取参数,推送参数梯度等操作上都需要与参数服务器进行通信,参数服务器架构下的参数服务器端,要等待每个计算节点发送的梯度信息进行汇总后再进行模型参数的更新。
异步并行训练算法
异步训练在参数服务器架构下采用较多,其本质就是让每个Worker不用关心其他节点的计算步调,独自与参数服务器完成模型参数的更新。异步训练情况下,参数服务器端的模型参数更新也是异步进行,即不需要等待其他正在计算的节点的进度。异步训练下,各个计算节点的计算频率不同,参数服务器更新模型参数的频率也会不同,这种特性使得模型的收敛可能存在一定的问题,能够保证高效率收敛的异步并行算法是一个研究比较多的领域。下图是一个单机SGD与参数服务器架构下的异步SGD的计算步骤对比,可以看到参数服务器一端与同步SGD的区别在于,不需要对各个节点的梯度进行汇聚而直接进行模型参数的更新。
飞桨paddle分布式API
尽管分布式训练能够大大提升用户在大规模数据下的模型训练速度,如前面背景知识的描述可知普通用户想快速掌握并行训练的方法并不容易,将飞桨paddle的单机训练程序转换成多机训练程序会给用户带来一定的使用成本。为了降低用户使用分布式训练的门槛,飞桨paddle官方支持分布式训练高层API Fleet,作为分布式训练的统一入口API,用户可以在单机程序的基础上进行简单的几行代码修改,可实现多种类型的并行训练方式。后面结合Fleet API介绍飞桨paddle数据并行方法,在参数服务器架构和Collective架构下,使用方法以及具体模型上的使用示例。