
随着AI在移动端的应用不断增加,如语音助手、图像识别、实时翻译等,移动设备需要处理大量数据并进行复杂计算。这些任务通常具有高度并行性,传统的单线程处理方式难以满足实时性要求。现代移动设备配备了多核CPU、GPU、甚至专用的AI加速器(如NPU),为并行处理提供了硬件支持。这种硬件架构的进步使得在设备上运行复杂的AI模型成为可能。为了适应移动设备的计算和存储限制,模型压缩技术如量化、剪枝、蒸馏等应运而生。这些技术不仅减少模型大小,还提升了并行计算效率。未来的移动端AI Agent将利用CPU、GPU、NPU等多种计算资源,实现更高效的异构并行计算。任务将根据其特性动态分配到最适合的硬件资源上执行。在现代机器学习中,各种并行方法用于将非常大的模型安装到有限的硬件上。例如t5-11b 仅模型参数就为45GB,这样可以显着加快训练速度(只需数小时即可完成需要一年时间的训练)。同时,提出各种其他强大的替代方法。虽然主要概念很可能适用于任何其他框架,但本文重点讨论基于 PyTorch 的实现过程原理。数据并行技术(DataParallel,DP) :相同的设置被复制多次,并且每次都被馈送一个数据切片。处理是并行完成的,并且所有设置在每个训练步骤结束时同步。张量并行(TensorParallel,TP):每个张量被分成多个块,因此张量的每个分片都驻留在其指定的 GPU 上,而不是将整个张量驻留在单个 GPU 上。在处理过程中,每个分片在不同的 GPU 上单独并行处理,结果在步骤结束时同步。这就是所谓的水平并行性,因为分裂发生在水平层面上。流水线并行(PipelineParallel,PP):模型在多个GPU上垂直(层级)分割,因此模型中只有一层或几层放置在单个 GPU 上。每个 GPU 并行处理管道的不同阶段,并处理批次的一小部分。零冗余优化器 (ZeRO):也执行类似于 张量并行TP 的张量分片,不同之处在于整个张量会及时重建以进行前向或后向计算传播,因此不需要修改模型。它还支持各种offload技术来补偿有限的 GPU 内存。分片(DDP):ZeRO 的各种其他实现所使用的基本ZeRO概念的另一个名称。大多数只有 2 个 GPU 的配置已经享受到了训练速度的提高,这要归功于数据并行 DataParallel (DP) 和 分布式数据并行 DataParallel (DDP),实际上这两者都是Pytorch的内置功能。下图描述了由零数据并行ZeRO驱动的数据并行性(ZeRO-DP)。可能很难理解它,但实际上这个概念非常简单。这只是常见的 Data Parallel (DP),只不过每个 GPU 只存储其中的一部分,而不是复制完整的模型参数、梯度和优化器状态。然后在运行时,当给定层只需要完整层参数时,所有 GPU 都会同步以向彼此提供它们错过的部分。考虑这个具有 3 层的简单模型,其中每层有 3 个参数。层La具有权重a0、at和a2。如果我们有 3 个 GPU,则 Sharded DDP(= Zero-DP)会将模型分割到 3 个 GPU 上,如下所示。在某种程度上,如果针对典型的 DNN 图,这与张量并行性是相同的水平切片。垂直切片是将整个层组放在不同的 GPU 上,但这只是起点。现在,这些 GPU 中的每一个都将获得通常的小批量,因为它在 DP 中工作。
其中
当针对输入未经修改时,可以认为它们将由正常模型处理。首先,输入到达 La 层。当我们只关注GPU0时:x0 需要 a0、a1、a2 参数来执行其前向路径,但 GPU0 只有 a0 ,从 GPU1 发送 a1,从 GPU2 发送 a2,将模型的所有部分组合在一起。同时,GPU1 获取小batch为x1,它只有a1,但需要 a0 和 a2 参数,因此它从GPU0和GPU2获取这些参数。同样的情况也发生在 GPU2 上,获取输入x2。它从 GPU0 和 GPU1 获取 a0 和 a1,并使用 a2 重建完整的张量。所有 3 个 GPU 都会重建完整的张量并应用于前向传播过程。一旦计算完成,不再需要的数据(只在计算过程中使用)就会被丢弃,且通过预取可以有效地完成重建。对 Lb 层重复整个过程,然后前向传播至 Lc层。而后向传播过程则是刚好反向:Lc -> Lb -> La。要了解 Pytorch 中的 DataParallel(DP 和 DDP)。首先需要了解相关的术语定义:分片、分区。如果关注 ZeRO 划分模型权重的方式 - 看起来与稍后将讨论的张量并行性非常相似。这是因为它对每一层的权重进行分区/分片,这与接下来讨论的垂直模型并行性不同。朴素模型并行 (MP) 是将模型层组分布在多个 GPU 上的方式。该机制相对简单,即将所需的层切换到所需的设备。每当数据进出时,这些层都会将数据切换到与该层相同的设备,而其余部分保持不变。我们将其称为“垂直MP”,实际上,就是会垂直分割图层。过程中,只是将其垂直切成 2 部分,将层 0-3 放置到 GPU0 上,将 4-7 层放置到 GPU1 上。现在,当数据从第 0 层传输到第 1 层、第 1 层到第 2 层以及第 2 层到第 3 层时,这只是正常模型。但是,当数据需要从第 3 层传递到第 4 层时,它需要从 GPU0 传输到 GPU1,这会带来通信开销。如果参与的 GPU 位于同一计算节点(例如同一物理机)上,则复制速度相当快,但如果 GPU 位于不同的计算节点(例如多台机器)上,则通信开销可能会大得多。然后第 4 层到第 5 层到第 6 层到第 7 层与普通模型一样,当第 7 层完成时,我们通常需要将数据发送回标签所在的第 0 层(或者将标签发送到最后一层)。现在可以计算损失并且优化器可以完成其工作。当然这里有个主要缺陷,那就是该 MP 被称为朴素MP的原因是,除了一个 GPU 之外的所有 GPU 在任何给定时刻都处于空闲状态。因此,如果使用 4 个 GPU,则几乎相当于将单个 GPU 的内存量增加四倍,并忽略其余硬件。另外,还有在设备之间复制数据的开销。因此,4x 6GB 卡将能够使用 naive MP 容纳与 1x 24GB 卡相同的大小,但后者将更快地完成训练,因为它没有数据复制开销。但是,如果有40GB 卡并且需要安装45GB型号,则可以使用 4x40GB 卡(但这几乎是因为梯度和优化器状态)。共享嵌入可能需要在 GPU 之间来回复制。管道并行(PP)与简单的MP几乎相同,但它通过将传入batch分块为微batch并入,为创建管道来解决 GPU 空闲问题,从而允许不同的 GPU 同时参与计算过程。下面来自 GPipe 论文的插图显示了顶部的朴素MP和底部的PP:上图:由于网络的顺序性质,朴素的模型并行策略导致严重未充分利用。一次只有一个加速器处于活动状态。下图:GPiped 将输入小批量分成更小的微批量,使不同的加速器能够同时处理单独的微批量。从上图很容易看出 PP 的死区更少,GPU 处于空闲状态。闲置的部分被称为“气泡”。该图的两部分都显示了 4 级并行性,即 4 个 GPU 参与管道。因此,存在 4 个管道级 F0、F1、F2 和 F3 的正向路径,然后是 B3、B2、B1 和 B0 的返回逆序反向路径。PP 引入了一个新的超参数来调整,它的块定义了通过同一管道阶段按顺序发送多少数据块。例如,在底部的图中,可以看到 chunks=4。GPU0 在块 0、1、2 和 3(F0,0、F0,1、F0,2、F0,3)上执行相同的前向路径,然后等待其他 GPU 完成其工作,并且仅当它们的工作开始时,GPU0 再次开始工作,为块 3、2、1 和 0(B0,3、B0,2、B0,1、B0,0)执行反向路径。由于块的存在,PP 引入了微批次(MBS)的概念。DP 将全局数据批量大小拆分为小batch,因此,如果 DP 度为 4,则全局批量大小 1024 将分为 4 个小批量,每个小批量 256 (1024/4)。如果块(或 GAS)的数量为 32,最终得到的微批量大小为 8 (256/32)。每个管道阶段一次处理一个微批次。为了计算 DP + PP 设置的全局批量大小,我们执行:mbs*chunks*dp_Degree(8*32*4=1024)。回到图表,当 chunks=1 时,最终会得到朴素MP,这是非常低效的。如果块值非常大,最终会得到很小的微批量大小,这也可能不是很有效。因此,必须通过实验来找到能够使 GPU 利用率最高的值。虽然该图显示存在无法并行化的“死”时间泡沫,因为最后一个前向阶段必须等待后向阶段完成管道,但找到块的最佳值的目的是实现高并发所有参与 GPU 的利用率,这意味着气泡大小最小化。因此,必须对模型进行大量修改,因为 Pipeline 需要将模块的正常流程重写为 nn.Sequential 序列,这可能需要更改模型的设计。目前 Pipeline API 非常受限制。如果在管道的第一阶段传递了一堆 python 变量,则必须找到解决方法。目前,管道接口需要单个张量或张量元组作为唯一的输入和输出。这些张量必须将batch大小作为第一个维度,因为管道会将小batch分成微batch。且过程中必须安排每一层,以便一个模型的输出成为另一个模型的输入。当前Transformer状态中,当前没有合适的模型支持全 PP。主要障碍是无法将模型转换为 nn.Sequential 并使所有输入都是张量。这是因为当前模型包含许多使转换非常复杂的功能,需要删除才能实现对全流水线并行技术PP的支撑。比如Deep Speed 和 Sage Maker 使用交错管道的概念。这里,通过优先考虑向后传递,可以进一步最小化气泡(空闲时间)。可能能够自动将非 nn.Sequential 模型转换为管道。唯一的问题是,目前仅在 AWS 上可用,因此无法在自己的硬件上运行它。在张量并行中,每个 GPU 仅处理张量的一部分,并且仅聚合完整张量以进行需要整个张量的操作。在本节中,我们使用 Megatron-LM 论文中的概念和图表来进行说明:GPU 集群上的高效大规模语言模型训练。任何 Transformer 的主要构建块都是一个完全连接的 nn.Linear,随后跟随一个非线性激活 GeLU。可以将其点积部分写为 Y = GeLU(XA),其中 X 和 Y 是输入和输出向量,A 是权重矩阵。如果我们以矩阵形式查看计算,很容易看出矩阵乘法如何在多个 GPU 之间分配:如果我们将权重矩阵 A 按列拆分到 N 个 GPU 上,并并行执行矩阵乘法 XA_1 到 XA_n,那么我们最终将得到N个输出向量 Y_1、Y_2、...、Y_n,它们可以独立地输入到 GeLU 中:GeLU 是一种平滑的非线性激活函数,能够有效地捕捉复杂的特征模式。然而,复杂的特征提取可能导致模型在训练数据上表现很好,但在新数据上表现不佳,即过拟合。通过Dropout 这种正则化技术,通过在训练过程中随机将一部分神经元的输出设为零,防止模型对特定的神经元依赖过多,从而降低过拟合的风险。利用这一原理,我们可以更新任意深度的多层感知机 MLP,而无需在 GPU 之间进行任何同步,直到最后我们需要从分片重建输出向量。Megatron-LM 为此提供了一个有用的说明。并行化多头注意力层甚至更简单,因为由于具有多个独立头,它们本质上已经是并行的。特别注意的是,张良并行TP 需要非常快的网络,因此不建议跨多个节点进行张量并行TP计算。实际上,如果节点有 4 个GPU,则最高TP度为4。如果需要TP度为 8,则需要使用至少有 8 个 GPU 的节点。本节基于原始的更详细的张量并行 TP 概述。实施过程中,DeepSpeed 将其称为张量切片,Megatron-LM 有一个内部实现。Transformer状态当前的core尚未在核心中实现,但如果想要做推理,Parallel Formers 为大多数模型提供了这种支持。因此,在核心实现这一点之前,可以使用希望的训练模式也能得到支持。DeepSpeed 管道教程中的下图演示了如何将 DP 与 PP 结合起来。这里重要的是要了解 DP 等级 0 为何看不到 GPU2,而 DP 等级 1 为何看不到 GPU3。对于 DP,只有 GPU 0 和 1,它在其中提供数据,就好像只有 2个GPU一样。GPU0 使用 PP“秘密”的将其部分负载计算量分解一部分到 GPU2。GPU1 通过寻求 GPU3 的帮助来执行相同的操作。由于每个维度至少需要 2 个 GPU,因此这里至少需要 4 个 GPU。2、DP+PP+TP(数据并行+流水线并行+张量并行)为了获得更有效的训练,使用3D并行性,其中 PP 与 TP 和 DP 相结合,这可以在下图中看到。如上这种 3D 并行性可以缩放到万亿参数模型,由于每个维度至少需要 2 个 GPU,因此如果这里基于维度下的层数n可以扩展到至少需要 2n个 GPU。对于Deep Speed 还包括一个更高效的 DP,称之为 ZeRO-DP,它是 DP 的超扩展,且已经在ZeRO Data Parallel 中进行了讨论。通常它是一个独立的功能,不需要 PP 或 TP,但可以与PP、TP结合使用。当 ZeRO-DP 与 PP(以及可选的TP)结合使用时,它通常仅启用 ZeRO 阶段 1(称之为优化器分片)。虽然理论上可以将 ZeRO 第 2 阶段(称之为梯度分片)与管道并行结合使用,但它会对性能产生不良影响。每个微批次都需要一个额外的减少分散集合来在分片之前聚合梯度,这会显著的增加潜在的通信开销。根据管道并行性的本质,使用小微批次,重点是尝试平衡算术强度(微批次大小)与最小化管道气泡(微批次数量)。此外,由于 PP层数已经比正常情况少,因此节省的内存不会很大。PP已经将梯度大小减少了1/PP,因此除此之外的梯度分片节省不如纯 DP 显着。出于同样的原因,ZeRO 第 3 阶段也不是一个好的选择,因为需要更多的节点间通信。ZeRO 的另一个好处是ZeRO的offload技术,由于这是第1阶段,优化器状态可以offload到 CPU。总结起来,对于模型试用何种并行技术进行部署,可以根据模型对GPU的。当模型适合单个 GPU时,则正常使用该模型适配GPU,若模型不适合单个 GPU时,则通过ZeRO + offload CPU(offload技术是指在计算任务中,针对CPU处理的各种计算任务,(如大规模并行计算、图形渲染、机器学习推理等)更有效地交付给其他硬件单元处理。通过将这些任务"offload"到专用硬件,可以释放CPU资源,使其专注于处理其他任务,从而提升整体系统的效率和响应速度)。该过程中,可选用高速链接来实现数据交换。当模型适合单个 GPU时,则采用分布式DP。实际上,ZeRO 可能会更快,也可能不会,具体取决于所使用的情况和配置。当模型不适合单个 GPU时,将PP、ZeRO、TP通过 NVLINK 或 NVSwitch 这种非常快速的节点进行高速连接,这三者应该基本处于同等水平,没有这些 PP将比TP和 ZeRO 更快。TP 的程度也可能产生影响,最好在特定设置上进行试验以找到最优工作方式。当具有快速的节点间连接时,则采用ZeRO 方式部署。 因为它几乎不需要对模型进行任何修改。否则,采用PP+TP+DP组合方式,因为这种方式通信较少,但需要对模型进行大量更改。当节点间连接速度较慢并且GPU内存仍然不足时,则采用DP+PP+TP+ZeRO-1的方式进行并行策略优化。
版权声明
本文仅作者转发或者创作,不代表旺旺头条立场。
如有侵权请联系站长删除
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。