多维度混合并行
==============

.. 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提供以下高级特性来支撑大模型分布式训练,用户可以根据自己的需要进行灵活组合。

`算子级并行 <https://www.mindspore.cn/tutorials/experts/zh-CN/r2.0/parallel/operator_parallel.html>`__
--------------------------------------------------------------------------------------------------------

算子级并行是以算子为单位,对其输入张量切分到多个设备,从而将算子进行分布式计算。一方面,可以将数据样本及模型参数同时切分到多个设备上,以完成大模型的训练。另一方面,可以充分利用集群资源进行并行计算,以提高整体速度。

用户可以设置正向网络中每个算子的切分策略,框架根据算子的切分策略对每个算子及其输入张量进行切分建模,使得该算子的计算逻辑在切分前后保持数学等价。

`流水线并行 <https://www.mindspore.cn/tutorials/experts/zh-CN/r2.0/parallel/pipeline_parallel.html>`__
--------------------------------------------------------------------------------------------------------

当集群设备数很多时,如果仅采用算子级并行的方式,则需要在整个集群的通信域上进行通信,这可能使得通信效率低,从而降低整体性能。

而流水线并行能将神经网络结构切分成多个stage,每个stage跑在一部分设备内,将集合通信的通信域限定在这部分设备范围内,而stage间采用点对点通信。

流水线并行的优点在于:能提升通信效率、能方便的处理按层堆叠的神经网络结构。缺点在于:同一时刻内,有些节点可能处于空闲状态。

`优化器并行 <https://www.mindspore.cn/tutorials/experts/zh-CN/r2.0/parallel/optimizer_parallel.html>`__
---------------------------------------------------------------------------------------------------------

在数据并行或算子级并行训练时,模型的参数可能在多个设备上存在同一份副本。这使得优化器在更新该权重之时,在多个设备间存在冗余计算。在此情况下,可以通过优化器并行将优化器的计算量分散到多个设备上。它的优点在于:能减少静态内存消耗、减少优化器内的计算量。缺点在于:增加了通信开销。

`Host&Device异构 <https://www.mindspore.cn/tutorials/experts/zh-CN/r2.0/parallel/host_device_training.html>`__
----------------------------------------------------------------------------------------------------------------

在大模型训练时,因每个设备(加速器)的内存容量有限,从而总体所能训练的模型规模将受设备数的限制。为了能完成更大规模的模型训练,可以使用主机端(Host)和加速器(Device)异构的训练模式。它同时发挥了主机端内存大和加速器端计算快的优势,是超大模型训练过程中减少设备数的有效方式。

`重计算 <https://www.mindspore.cn/tutorials/experts/zh-CN/r2.0/parallel/recompute.html>`__
--------------------------------------------------------------------------------------------

MindSpore根据正向图计算流程来自动推导出反向图,正向图和反向图一起构成了完整的计算图。在计算某些反向算子时,可能需要用到某些正向算子的计算结果,导致这些正向算子的计算结果,需要驻留在内存中直到这些反向算子计算完,它们所占的内存才会被其他算子复用。而这些正向算子的计算结果,长时间驻留在内存中,会推高计算的内存占用峰值,在大规模网络模型中尤为显著。为了降低内存峰值,重计算技术可以不保存正向激活层的计算结果,让该内存可以被复用,然后在计算反向部分时,重新计算出正向激活层的结果。

`分布式图切分 <https://www.mindspore.cn/tutorials/experts/zh-CN/r2.0/parallel/distributed_graph_partition.html>`__
--------------------------------------------------------------------------------------------------------------------

MindSpore支持用户对一张计算图进行自定义切分。MindSpore能够根据用户传参,将计算图中任意算子切分到任意进程,充分利用了不同进程所在节点设备上的计算资源,从而执行分布式训练等任务。分布式切图后,计算任务的执行结果和单机单卡副本的执行结果保持一致。

在MindSpore中,
`参数服务器 <https://www.mindspore.cn/tutorials/experts/zh-CN/r2.0/parallel/parameter_server_training.html>`__\ 训练模式使用了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\|                     |
|               |                         | 接口后才会生效     |                     |
+---------------+-------------------------+--------------------+---------------------+