多卡并行训练和微调技术

这是使用 Google DeepResearch 生成的偏理论分析报告,内容基于2026/4/27之前的公开资料和技术文献,主要是方便自己学习,准确性和时效性可能无法完全保证。 第一章 深度学习分布式训练的底层基石:显存与通信的博弈 随着大语言模型(LLM)参数规模从十亿级别飙升至万亿级别,深度学习的训练与微调已经彻底演变为一项复杂的系统工程。在这一演进过程中,单张图形处理器(GPU)的显存容量与计算能力已无法满足动辄数千吉字节(GB)的内存需求,多卡并行架构成为必然选择。 在多卡分布式训练中,架构设计的核心挑战始终围绕着**“显存墙(Memory Wall)”与“通信墙(Communication Wall)”**的博弈展开。 [1].1 显存消耗模型解构 要深刻理解分布式训练的演进,必须首先解构模型在训练过程中的显存消耗。在采用混合精度训练(Mixed Precision Training)及 Adam 优化器的情况下,每个模型参数通常需要消耗约 20 字节的显存: 模型状态(Model States): 权重与梯度: 半精度(16-bit)各占用 [2] 字节(共 [4] 字节)。 权重与梯度副本: 全精度(32-bit)各占用 [4] 字节(共 [8] 字节)。 优化器状态: Adam 优化器的一阶与二阶矩估计状态各占用 [4] 字节(共 [8] 字节)。 剩余消耗: 前向传播过程中产生的**残差状态(Residual States,即激活值 Activations)**和各类临时缓冲区,会随着批次大小(Batch Size)和序列长度呈线性甚至二次方增长。 示例: 一个 [75] 亿参数的模型,仅静态模型状态就需要消耗约 150GB 显存,远超单张 H100(80GB)的物理极限。 [1].2 通信原语与同步机制 在多 GPU 协同计算时,节点间必须通过特定的**集体通信原语(Collective Communications)**进行数据交互: 基础原语: 包括广播(Broadcast)、收集(Gather)、分散(Scatter)以及规约(Reduce)。 核心同步机制: 全规约(All-Reduce)。它确保了所有 GPU 在反向传播后能够获得一致的梯度总和。 从底层实现来看,最优的 All-Reduce 操作通常被分解为两个连续步骤:Reduce-Scatter(规约-分散) 与 All-Gather(全收集)。理解这种分解机制是掌握高级状态切分策略(如 ZeRO 和 FSDP)的技术基石。 ...

April 27, 2026 · 9 min

CS336 Lecture 7-8:Parallelism

本篇主题 这两节Lecture都是关于并行训练的,主要内容包括: 理解训练超大模型时系统层面的复杂性 掌握不同的 parallelization paradigms,以及为什么人们通常会同时使用多种并行方式 了解大规模训练任务通常是如何进行的 Lecture 7 - Parallelism 1 单块GPU无法满足SCALING的需求,必须使用多块GPU进行训练,所以我们需要Multi-GPU、Multi-Machine的并行训练方法,如下图所示: 首先讲了一些Basic Concepts: All Reduce:通信操作,所有参与的进程都将输入数据进行规约(如求和、最大值等)后,将结果分发给所有进程。常用于分布式训练中的梯度同步。 Broadcast:通信操作,数据从一个进程发送到所有其他进程。常用于分布式训练中的分发模型参数或者初始化数据。 All Gather:通信操作,所有参与的进程将各自的数据发送给所有其他进程,最终每个进程都获得所有数据的集合。常用于分布式训练中的收集模型输出或者中间结果。和All Reduce的区别在于,All Reduce会对数据进行规约操作(如求和),而All Gather只是简单地收集数据,不进行任何计算。 Reduce Scatter:通信操作,所有参与的进程将各自的数据发送给所有其他进程,并对数据进行规约操作(如求和),最终每个进程都获得规约后的结果的一部分。常用于分布式训练中的分布式梯度更新。 了解了初始知识之后,可以正式进入核心部分,不同的并行方式: Data Parallelism:最早的并行方式,模型复制到每个GPU上,每个GPU处理不同的数据batch,计算梯度后进行同步更新。优点是实现简单;缺点是通信开销大,尤其是模型参数较大时。 假设计算一个 SGD:我们会把 B 大小下的 batch 分给 M 个不同的机器,然后交换梯度去同步计算。这种情况对于 Compute scaling,每个 GPU 计算 B/M 个数据(不错!);对于 Communication overhead,每个 batch 需要转移两次梯度(发送和接受);对于 Memory scaling,完全没有,每个 GPU 都需要复制一次模型参数。 早期的data parallelism问题是只缓解了计算压力,内存压力没有缓解,需要每个GPU都复制一份模型参数,通信压力也很大。 Zero[HTTPS://arxiv.org/pdf/1910.02054]可以解决这个问题,核心的思想是将模型的state(参数和优化器状态)分布在不同的GPU上,每个GPU只存储模型的一部分,这样可以显著减少每个GPU的内存占用,同时通过通信操作来同步更新模型参数。 ZeRO分三个阶段: ZeRO-1:主要聚焦于 optimizer state sharding。把 optimizer state(first + second moments)分给每个 GPU,每个 GPU 都有 parameters + gradients,负责更新一部分 params。 每个 GPU 根据分配到的 batch 子集计算完整的梯度,此时只拥有局部梯度 利用 Reduce-Scatter 将所有 GPU 的局部梯度汇总并分散到每个设备上,现在每个 GPU 只持有全局梯度的一部分 每个 GPU 利用局部梯度和 optimizer state 更新该部分参数 利用 AllGather 将所有 GPU 的部分参数收集并分发给所有设备,确保每个 GPU 拥有完整的参数。 这种方法的通信开销并没有增加,而且 memory 减少了接近四倍(优化器状态是fp32,参数是fp16)。 ...

April 9, 2026 · 4 min

并行训练实践

Accelerate Accelerate 是 Hugging Face 开发的深度学习多卡并行训练库,构建在 torch_xla 和 torch.distributed 之上。它提供了一个简单的 API,将与多 GPU、TPU、混合精度训练相关的样板代码抽离了出来,让用户可以在不同设备上轻松地进行分布式训练和混合精度训练,而无需重复编写大量样板代码。 另外,Accelerate 还提供了很多性能优化的功能,使得大规模训练和推理变得简单、高效且适应性强。 在学习如何使用 Accelerate 之前,首先回顾一下并行训练的其他方法。 DataParallel (DP) DP 是最常见的并行训练方式,通过将数据拆分(split)到各个 workers 中(每个 worker 拥有完整模型)进行并行计算,以解决 Batch Size 过大的问题。因为求导以及加和都是线性的,所以数据并行在数学上是等价的。 DataParallel 是 PyTorch 中最容易实现的并行方案,只需要增加一行代码:model = nn.DataParallel(model)。 代码示例 import torch import torch.nn as nn from torch.utils.data import DataLoader, Dataset # 数据集的长度为 100,batch size 为 32 # 模型是一个简单的 fc 层,输入长度是 5,输出是 2 input_size, output_size = 5, 2 batch_size, data_size = 32, 100 model = Model(input_size, output_size) if torch.cuda.device_count() > 1: print(f"Detected {torch.cuda.device_count()} GPUs!") model = nn.DataParallel(model) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") model.to(device) rand_loader = DataLoader( dataset=RandomDataset(input_size, data_size), batch_size=batch_size, shuffle=True ) for data in rand_loader: input = data.to(device) output = model(input) 在上述代码中,batch_size=32。由于使用了 DataParallel,在有 2 个 GPU 时,一个 batch 被划分成了 2 份,即 tensor.split(16),分别送往两个 GPU。 ...

July 24, 2025 · 2 min