多维度混合并行 ============== .. image:: https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.0/resource/_static/logo_source.png :target: https://gitee.com/mindspore/docs/blob/r2.0/tutorials/experts/source_zh_cn/parallel/multi_dimensional.rst .. toctree:: :maxdepth: 1 :hidden: operator_parallel pipeline_parallel optimizer_parallel host_device_training recompute distributed_graph_partition 随着深度学习的发展,模型规模越来越大。如NLP领域,短短几年时间,参数量就从BERT的亿级,发展到GPT-3的1700亿,再到盘古alpha 2000亿,以及当前业界甚至提出百万亿级。由此可以看出,近年来参数规模呈指数增长趋势。另一方面,随着大数据、互联网等领域相关技术的发展,可供模型训练的数据集也极速扩增,例如推荐、自然语言处理等场景的数据集可达数TB。 面对大数据量、大规模参数的训练,单个设备要么完成模型训练的时间很长,要么因显存不足而导致无法进行训练。因此,需要引入分布式训练技术。 当前,最常用的分布式训练技术是数据并行。数据并行将训练数据切分到多个设备上,每个设备维护相同的模型参数和相同大小的计算任务,但是处理不同的数据,并在反向传播过程中,对每个设备产生的参数梯度进行全局AllReduce同步求和。当数据集较大而模型较小时,选择数据并行较有优势,如ResNet50。但是,当模型规模较大、或数据集与模型规模均较大时,就需要借助于其他分布式特性。 MindSpore提供以下高级特性来支撑大模型分布式训练,用户可以根据自己的需要进行灵活组合。 `算子级并行 `__ -------------------------------------------------------------------------------------------------------- 算子级并行是以算子为单位,对其输入张量切分到多个设备,从而将算子进行分布式计算。一方面,可以将数据样本及模型参数同时切分到多个设备上,以完成大模型的训练。另一方面,可以充分利用集群资源进行并行计算,以提高整体速度。 用户可以设置正向网络中每个算子的切分策略,框架根据算子的切分策略对每个算子及其输入张量进行切分建模,使得该算子的计算逻辑在切分前后保持数学等价。 `流水线并行 `__ -------------------------------------------------------------------------------------------------------- 当集群设备数很多时,如果仅采用算子级并行的方式,则需要在整个集群的通信域上进行通信,这可能使得通信效率低,从而降低整体性能。 而流水线并行能将神经网络结构切分成多个stage,每个stage跑在一部分设备内,将集合通信的通信域限定在这部分设备范围内,而stage间采用点对点通信。 流水线并行的优点在于:能提升通信效率、能方便的处理按层堆叠的神经网络结构。缺点在于:同一时刻内,有些节点可能处于空闲状态。 `优化器并行 `__ --------------------------------------------------------------------------------------------------------- 在数据并行或算子级并行训练时,模型的参数可能在多个设备上存在同一份副本。这使得优化器在更新该权重之时,在多个设备间存在冗余计算。在此情况下,可以通过优化器并行将优化器的计算量分散到多个设备上。它的优点在于:能减少静态内存消耗、减少优化器内的计算量。缺点在于:增加了通信开销。 `Host&Device异构 `__ ---------------------------------------------------------------------------------------------------------------- 在大模型训练时,因每个设备(加速器)的内存容量有限,从而总体所能训练的模型规模将受设备数的限制。为了能完成更大规模的模型训练,可以使用主机端(Host)和加速器(Device)异构的训练模式。它同时发挥了主机端内存大和加速器端计算快的优势,是超大模型训练过程中减少设备数的有效方式。 `重计算 `__ -------------------------------------------------------------------------------------------- MindSpore根据正向图计算流程来自动推导出反向图,正向图和反向图一起构成了完整的计算图。在计算某些反向算子时,可能需要用到某些正向算子的计算结果,导致这些正向算子的计算结果,需要驻留在内存中直到这些反向算子计算完,它们所占的内存才会被其他算子复用。而这些正向算子的计算结果,长时间驻留在内存中,会推高计算的内存占用峰值,在大规模网络模型中尤为显著。为了降低内存峰值,重计算技术可以不保存正向激活层的计算结果,让该内存可以被复用,然后在计算反向部分时,重新计算出正向激活层的结果。 `分布式图切分 `__ -------------------------------------------------------------------------------------------------------------------- MindSpore支持用户对一张计算图进行自定义切分。MindSpore能够根据用户传参,将计算图中任意算子切分到任意进程,充分利用了不同进程所在节点设备上的计算资源,从而执行分布式训练等任务。分布式切图后,计算任务的执行结果和单机单卡副本的执行结果保持一致。 在MindSpore中, `参数服务器 `__\ 训练模式使用了MindSpore分布式图切分能力:在此模式下,MindSpore设置优化器在Server进程执行,网络的其余部分在Worker执行,两类节点间通过host侧通信算子进行数据交互。 特性相关接口说明 ---------------- +---------------+-------------------------+--------------------+---------------------+ | 特性类别 | 特性接口 | 说明 | 作用 | +===============+=========================+====================+=====================+ | 算子级并行 | shard(in_strategy=None,\| 设置算子的输入及输\| 通过将网络模型中每\ | | | out_strategy=None)在\ | 出张量的切分策略(\| 个算子涉及到的张量\ | | | Primitive类 | 其中,输出张量的切\| 进行切分,降低单个\ | | | | 分策略仅支持部分算\| 设备的内存容量,以\ | | | | 子,如Gather\ | 完成大模型训练/推\ | | | | 、MatMul) | 理。或利用集群资源\ | | | | | ,进行分布式计算,\ | | | | | 减少整体执行时间。 | +---------------+-------------------------+--------------------+---------------------+ | | add_prim_attr(name,\ | Gather算子:\ | 在推荐领域,存在数\ | | | value)在Primitive类中 | add_prim_a\ | 据集的每一列对应一\ | | | | ttr(“man\ | 个子表的场景。在该\ | | | | ual_split\ | 场景下,使用此配置\ | | | | ”,\ | 能降低通信量,提升\ | | | | config):配\ | 整体性能。 | | | | 置其第一个输入的非\| | | | | 均匀切分策略,其中\| | | | | config类型为\ | | | | | tuple,用于描\ | | | | | 述第一个参数第零维\| | | | | 的切分方式。比如(\ | | | | | 10,\ | | | | | 20, 30,\ | | | | | 4)代表将算子第一\ | | | | | 个输入的第零维切分\| | | | | 成4份,每份的sh\ | | | | | ape大小分别为1\ | | | | | 0,20,30,4\ | | | | | 。 | | +---------------+-------------------------+--------------------+---------------------+ | | | Embedding\ | 在推荐领域,存在\ | | | | LookUp算子:\ | Embedding\ | | | | add_prim_attr\ | Table特别大的\ | | | | (“primitive\_\ | 场景,为了节约de\ | | | | target”,\ | vice内存,可以\ | | | | “CPU”):配置\ | 使用此配置将\ | | | | 其在CPU上执行,\ | EmbeddingLookUp\ | | | | 用于异构场景。 | 放到CPU上\ | | | | | 执行,以完成推荐大\ | | | | | 模型的训练。 | +---------------+-------------------------+--------------------+---------------------+ | | set_auto_parallel_con\ | 表示在通信时是否允\| AllToAll通\ | | | text(enable_alltoall=\ | 许产生AllToA\ | 信能减少通信数据量\ | | | bool_value) | ll通信算子,其值\ | ,提高通信效率,但\ | | | | 为bool类型,默\ | 需要环境支持。 | | | | 认为False。 | | +---------------+-------------------------+--------------------+---------------------+ | 流水线并行 | set_auto_parallel_con\ | 设置流水线并行的s\ | 指定stage的个\ | | | text(pipeline_stages=\ | tage个数,其值\ | 数,将集合通信的通\ | | | stage_num) | 为正整数,取值范围\| 信域限定在stage\ | | | | 为[1,\ | 范围内,而stage\ | | | | 设备数]。 | 间采用点对点通\ | | | | | 信。 | +---------------+-------------------------+--------------------+---------------------+ | | pipeline_stage(value)\ | 设置该Cell在哪\ | 设置该Cell在哪\ | | | 在Cell类中 | 个stage中执行\ | 个stage中执行\ | | | | 。 | 。 | +---------------+-------------------------+--------------------+---------------------+ | | PipelineCell(network,\ | 用于指定训练网络的\| 指定micro_size,\ | | | micro_size) | MicroSize\ | 能减少stage\ | | | | 数量,其中network\ | 间的空闲等待\ | | | | 为待训练的网\ | 时间,提升流水线并\ | | | | 络,micro_size\ | 行的整体效率。 | | | | 为正整数。 | | +---------------+-------------------------+--------------------+---------------------+ | 优化器并行 | set_auto_parallel_con\ | 表示是否开启优化器\| 优化器并行能节省静\ | | | text(enable_parallel\_ | 并行,其值为bool\ | 态内存的开销,但增\ | | | optimizer=bool_value) | 型,默认为False。 | 加了通信开销。 | +---------------+-------------------------+--------------------+---------------------+ | | set_auto_parallel_con\ | 只有开启优化器并行\| gradient\_\ | | | text(parallel_optimiz\ | 后,此配置才生效。\| accumulation\_\ | | | er_config=config) | 其中config是\ | shard\ | | | | 个dict,支持两\ | 为True时,将节\ | | | | 个键值: | 省一份参数大小的静\ | | | | gradient\_\ | 态内存,但增加了通\ | | | | accumulation\_\ | 信开销。优化器切分\ | | | | shard(bool\ | 阈值,能使得shape\ | | | | ):如果为True\ | 较小的参数不进\ | | | | ,则累积梯度变量将\| 行优化器切分,以节\ | | | | 在数据并行度上进行\| 省通信资源。 | | | | 分片,默认为False。| | | | | parallel\_ | | | | | optimizer_thres\ | | | | | hold(int)\ | | | | | :该值表示优化器切\| | | | | 分阈值,单位为KB\ | | | | | (默认64KB)。 | | | | | 当参数大小不超过该\| | | | | 值时,将不会被切分\| | | | | 。 | | +---------------+-------------------------+--------------------+---------------------+ | 重计算 | recompute(mode=True)在\ | 用于指定该算子是否\| 开启算子重计算后,\ | | | Primitive类中 | 需要重计算,其值为\| 能减少动态内存的峰\ | | | | bool类型,默认\ | 值,但增加整体计算\ | | | | 为True,表示开\ | 量。 | | | | 启算子重计算。 | | +---------------+-------------------------+--------------------+---------------------+ | | recompute(\*\*kwargs)在\| 调用此接口后,将会\| 开启Cell重计算\ | | | Cell类中 | 对此Cell中的算\ | ,且能配置模型并行\ | | | | 子进行重计算。其中\| 的通信算子、优化器\ | | | | 输入参数有两个bo\ | 并行的通信算子是否\ | | | | ol类型选项:\ | 进行重计算。当通信\ | | | | mp_comm\_\ | 算子重计算时,将消\ | | | | recompute:是否\ | 耗通信资源,但能降\ | | | | 开启模型并行通信算\| 低动态内存的峰值。 | | | | 子重计算,默认为\ | | | | | True。parallel\_\ | | | | | optimizer\_\ | | | | | comm_recompute:\ | | | | | 是否开启优化器\ | | | | | 并行通信算子重计算\| | | | | ,默认为False。 | | +---------------+-------------------------+--------------------+---------------------+ | 分布式图切分 | place(role,\ | 设置Primitive\ | 开放了通用的分布式\ | | | rank_id)在Primitive类中\| 对应算子或者\ | 图切分接口,用户能\ | | | place(role,\ | Cell中所有算子在\ | 够根据自定义算法,\ | | | rank_id)在Cell类中 | 某进程上执行,只有\| 对计算图进行切分,\ | | | | 调用\ | 从而执行分布式训练\ | | | | mindspore.\ | 等任务。 | | | | communication.init\| | | | | 接口后才会生效 | | +---------------+-------------------------+--------------------+---------------------+