有效扩展大型语言模型面临多项挑战。数据并行是一种用于扩展并发处理数据样本数量的技术。内存优化策略,例如 DeepSpeed 的 ZeRO,有助于在数据并行工作器之间管理大型模型的内存占用。尽管有这些方法,但仍然可能遇到一个根本性的限制:单个模型副本(或其优化期间的状态)对于单个加速设备(GPU/TPU)的内存来说可能仍然过大。此外,即使在最快的可用硬件上,单次前向或反向传播中的计算也可能太慢。这正是模型并行变得极其重要的地方,NVIDIA 的 Megatron-LM 库提供了一个高度优化的框架,专门用于为大型 Transformer 模型实现张量并行 (TP) 和流水线并行 (PP)。Megatron-LM 最初是为了训练数十亿参数的语言模型而开发的,它提供了直接应对模型计算和参数在多个设备上分布挑战的构建模块和方法。核心贡献:张量并行与流水线并行Megatron-LM 的主要优势在于它对张量并行和流水线并行的高效实现。张量并行(层内模型并行): Megatron-LM 能够将单个层,或者更准确地说,这些层内部的大型权重矩阵,拆分到多个设备上。对于 Transformer 模型来说,这通常针对多头注意力 (MHA) 块和多层感知机 (MLP) 块。张量并行不是在一块 GPU 上计算 $Y = XA$,而是可能将矩阵 $A$ 按列拆分到 $N$ 块 GPU 上($A = [A_1, A_2, ..., A_N]$),在每块 GPU $i$ 上计算 $Y_i = XA_i$,然后聚合结果 $Y = [Y_1, Y_2, ..., Y_N]$。类似地,矩阵也可以按行拆分,这需要不同的通信模式(例如,归约部分和)。Megatron-LM 提供了这些拆分计算的优化实现以及必要的通信(例如 all-gather、reduce-scatter、all-reduce),这些通常使用 NVIDIA 的 NCCL 库,适用于 NVLink 等高速互联。digraph G { rankdir=TB; node [shape=rect, style=filled, fillcolor="#e9ecef", fontname="sans-serif", fontsize=12]; subgraph cluster_0 { label = "GPU 0"; fontsize=12; bgcolor="#f8f9fa"; A1 [label="权重矩阵 A1\n(H x W/2)", fillcolor="#a5d8ff", fontsize=12]; X -> A1 [label="输入 X (B x H)", fontsize=12]; A1 -> Y1 [label="输出 Y1 (B x W/2)", fontsize=12]; } subgraph cluster_1 { label = "GPU 1"; bgcolor="#f8f9fa"; fontsize=12; A2 [label="权重矩阵 A2\n(H x W/2)", fillcolor="#a5d8ff", fontsize=12]; X -> A2 [label="输入 X (B x H)", fontsize=12]; A2 -> Y2 [label="输出 Y2 (B x W/2)", fontsize=12]; } Y1 -> Y_combined [style=dashed, arrowhead=none, fontsize=12]; Y2 -> Y_combined [style=dashed, arrowhead=none, fontsize=12]; Y_combined [label="合并输出 Y\n(B x W)", fillcolor="#ffec99", shape=invhouse, fontsize=12]; X [label="输入 X (B x H)", fillcolor="#b2f2bb", shape=box]; {rank=same; A1; A2;} {rank=same; Y1; Y2;} Y_combined -> Gather [label="通信\n(例如,All-Gather)"] ; Gather [label="聚合结果", shape=cylinder, fillcolor="#ced4da"]; }一个线性层($Y=XA$)的列并行张量并行视图。输入 $X$ 被广播,权重矩阵 $A$ 被按列拆分($A_1, A_2$)到两块 GPU 上。每块 GPU 计算一个部分结果($Y_1, Y_2$),然后通过通信将它们组合起来。以 PyTorch 中一个简化的线性层实现为例。Megatron-LM 提供了这些层的版本,它们在内部处理拆分和通信。# PyTorch - 标准线性层 import torch import torch.nn as nn linear_layer = nn.Linear(in_features=1024, out_features=4096) input_tensor = torch.randn(32, 1024) # 批大小 32,隐藏层大小 1024 output = linear_layer(input_tensor) # 输出形状 (32, 4096) # Megatron-LM 的 ColumnParallelLinear 的理念(简化) # 实际实现使用特定的通信原语。 # 假设 tensor_model_parallel_size = 2 # 在 GPU 0 上: # linear_layer_part1 = ColumnParallelLinear(in_features=1024, out_features=4096, tensor_model_parallel_size=2) # output_part1 = linear_layer_part1(input_tensor) # 在 GPU 0 上的输出形状 (32, 2048) # 在 GPU 1 上: # linear_layer_part2 = ColumnParallelLinear(in_features=1024, out_features=4096, tensor_model_parallel_size=2) # 使用不同的权重切片 # output_part2 = linear_layer_part2(input_tensor) # 在 GPU 1 上的输出形状 (32, 2048) # 计算后: # 如果需要,使用通信(例如 all-gather)在所有 TP 排名上聚合 output_part1 和 output_part2 # 以形成形状为 (32, 4096) 的完整输出张量。这使得能够训练具有非常大的隐藏维度或注意力头的模型,在这些模型中,即使单个层的权重也可能超过单块 GPU 的内存。流水线并行(层间模型并行): 当模型变得非常深(许多层)时,即使张量并行可能也不够,或者张量并行在太多设备上的通信开销变得过高。流水线并行通过将模型的层按顺序划分成阶段来解决这个问题,将每个阶段分配给不同的 GPU(或 GPU 组)。数据流经这些阶段,就像流水线一样。一个简单的实现会导致显著的空闲时间(“流水线气泡”),因为后面的阶段会等待前面的阶段完成。Megatron-LM 实现了带有微批处理的流水线,其中输入小批次被拆分成更小的微批次,然后按顺序送入流水线。这使得不同的阶段能够并发处理不同的微批次,从而大大提高硬件利用率。digraph G { rankdir=TB; splines=true; node [shape=rect, style=filled, fillcolor="#e9ecef", fontname="sans-serif", fontsize=12]; subgraph cluster_0 { label = "GPU 0 (阶段 0)"; bgcolor="#f8f9fa"; fontsize=12; L0 [label="层 1-8\n(微批次 1)", fillcolor="#fd7e14", fontsize=12]; L1 [label="层 1-8\n(微批次 2)", fillcolor="#fab005", fontsize=12]; L2 [label="层 1-8\n(微批次 3)", fillcolor="#ffd43b", fontsize=12]; L0 -> L1 -> L2 [style=invis, fontsize=12]; } subgraph cluster_1 { label = "GPU 1 (阶段 1)"; bgcolor="#f8f9fa"; M0 [label="层 9-16\n(微批次 1)", fillcolor="#fd7e14", fontsize=12]; M1 [label="层 9-16\n(微批次 2)", fillcolor="#fab005", fontsize=12]; M2 [label="层 9-16\n(微批次 3)", fillcolor="#ffd43b", fontsize=12]; M0 -> M1 -> M2 [style=invis, fontsize=12]; } subgraph cluster_2 { label = "GPU 2 (阶段 2)"; bgcolor="#f8f9fa"; fontsize=12; N0 [label="层 17-24\n(微批次 1)", fillcolor="#fd7e14", fontsize=12]; N1 [label="层 17-24\n(微批次 2)", fillcolor="#fab005", fontsize=12]; N2 [label="层 17-24\n(微批次 3)", fillcolor="#ffd43b", fontsize=12]; N0 -> N1 -> N2 [style=invis, fontsize=12]; } edge [arrowhead=vee, color="#495057"]; L0 -> M0 [label=" 发送/接收", fontsize=12]; L1 -> M1 [label=" 发送/接收", fontsize=12]; L2 -> M2 [label=" 发送/接收", fontsize=12]; M0 -> N0 [label=" 发送/接收", fontsize=12]; M1 -> N1 [label=" 发送/接收", fontsize=12]; M2 -> N2 [label=" 发送/接收", fontsize=12]; edge [arrowhead=vee, color="#adb5bd", style=dashed, fontsize=12]; N0 -> M0; N1 -> M1; N2 -> M2; M0 -> L0; M1 -> L1; M2 -> L2; }简化的流水线并行,包含 3 个阶段和 3 个微批次。每块 GPU 处理一部分层(一个阶段)。微批次流经这些阶段(实线箭头)。虚线箭头表示反向传播流程。这种并发减少了空闲时间。使用与集成使用 Megatron-LM 通常包括:模型定义: 修改您的 Transformer 模型代码,使用 Megatron-LM 的并行层实现(例如 ParallelMLP、ParallelAttention),而不是标准的 PyTorch 层。配置: 通常在启动训练脚本时,通过命令行参数指定张量并行度(tensor_model_parallel_size)和流水线并行度(pipeline_model_parallel_size)。使用的 GPU 总数将是这些大小与数据并行大小的乘积。初始化: Megatron-LM 提供了处理这些分布式组件正确初始化的实用程序。训练循环: 调整训练循环,以处理跨流水线阶段的前向/反向传播并管理梯度同步。Megatron-LM 是一个功能强大的专用工具。它提供了高度优化的内核和通信模式,特别是针对 NVIDIA GPU。虽然它可以独立使用,但也经常与 DeepSpeed 等框架集成。这使得开发者能够将 Megatron-LM 高效的张量并行和流水线并行实现与 DeepSpeed 基于 ZeRO 的数据并行以及其他内存节省功能结合起来,形成一个在极大规模下训练模型的有效组合。接下来的部分会说明如何在 DeepSpeed 和 Megatron-LM 中配置和使用这些特定功能。