基于魔搭平台进行DDP分布式训练
《基于魔搭平台进行DDP分布式训练》共 0.2 万字,通篇围绕 GPU、微调、推理、LoRA 展开,归在「训练、微调与数据」这一层。
适合要自己训模型、或者判断这一版该不该训的人
目录骨架(8 节)
- 示例代码
- 数据并行
- 环境准备
- 微调训练
- 模型合并
- 模型推理
- 分布式数据并行
- 使用CLI
示例代码
数据并行
数据并行,就是将数据集分为 N 份,分别装载到 N 个 GPU 节点中,每个 GPU 节点持有一个完整的模型副本,分别基于每个 GPU 中的数据去进行梯度求导。在 GPU0 上对每个 GPU 中的梯度进行累加,最后,再将 GPU0 聚合后的结果广播到其他 GPU 节点。数据并行不仅仅指对训练的数据并行操作,还可以对网络模型梯度、权重参数、优化器状态等数据进行并行。
数据并行
数据并行 (torch.nn.DataParallel),基于单进程多线程进行实现的,使用一个进程来计算模型权重,在每个批处理期间将数据分发到每个 GPU。
DataParallel 的计算过程如下所示:
- 将 inputs 从主 GPU 分发到所有 GPU 上。
- 将 model 从主 GPU 分发到所有 GPU 上。
- 每个 GPU 分别独立进行前向传播,得到 outputs。
- 将每个 GPU 的 outputs 发回主 GPU。
- 在主 GPU 上,通过 loss function 计算出 loss,对 loss function 求导,求出损失梯度。
- 计算得到的梯度分发到所有 GPU 上。
- 反向传播计算参数梯度。
- 将所有梯度回传到主 GPU,通过梯度更新模型权重。
- 不断重复上面的过程。
分布式数据并行
PyTorch 官方建议使用 DistributedDataParallel,而不是 DataParallel 类来进行多 GPU 训练,即使在单机多卡的情况下。那么下面我们来看看 PyTorch DDP。
分布式数据并行 (torch.nn.DistributedDataParallel),基于多进程进行实现的,每个进程都有独立的优化器,执行自己的更新过程。每个进程都执行相同的任务,并且每个进程都与所有其他进程通信。进程(GPU)之间只传递梯度,这样网络通信就不再是瓶颈。DistributedDataParallel 方式可以更好地进行多机多卡运算,更好的进行负载均衡,运行效率也更高,虽然使用起来较为麻烦,但对于追求性能来讲是一个更好的选择。
具体流程如下:
- 首先将 rank=0 进程中的模型参数广播到进程组中的其他进程;
- 然后,每个 DDP 进程都会创建一个 local Reducer 来负责梯度同步。
- 在训练过程中,每个进程从磁盘加载 batch 数据,并将它们传递到其 GPU。每个 GPU 都有自己的前向过程,完成前向传播后,梯度在各个 GPUs 间进行 All-Reduce,每个 GPU 都收到其他 GPU 的梯度,从而可以独自进行反向传播和参数更新。
- 同时,每一层的梯度不依赖于前一层,所以梯度的 All-Reduce 和后向过程同时计算,以进一步缓解网络瓶颈。
- 在后向过程的最后,每个节点都得到了平均梯度,这样各个 GPU 中的模型参数保持同步 。
环境准备
推荐的第三方库版本参考SWIFT安装文档
pip install ms-swift -U
# 若使用deepspeed zero2/zero3
pip install deepspeed -U
微调训练
ms-swift使用了分层式的设计思想,用户可以使用命令行界面、Web-UI界面和直接使用Python的方式进行微调。
使用CLI
我们提供了10分钟在单卡3090上对Qwen2.5-7B-Instruct进行自我认知微调的最佳实践,具体参考这里,这可以帮助您快速了解SWIFT。
此外,我们给出了一系列脚本帮助您了解SWIFT的训练能力:
- 轻量化训练:SWIFT支持的轻量微调示例可以参考这里。(注意:这些方式预训练也可以使用,但预训练通常使用全参数训练)。
- 分布式训练:SWIFT支持的分布式训练技术包括:DDP、device_map、DeepSpeed ZeRO2/ZeRO3、FSDP。
- device_map: 简易模型并行。如果存在多GPU,device_map会自动开启。这会将模型按层均匀的划分到可见的GPU中,显著降低显存消耗,但是训练速度通常会降低,因为是串行的。
- DDP+device_map:将按组对模型进行device_map划分,参考这里。
小帖士:
- 在使用swift sft通过LoRA技术微调base模型为chat模型时,有时需要手动设置模板。通过添加--template default参数来避免base模型因未见过对话模板中的特殊字符而无法正常停止的情况。具体参考这里。
- 如果需要在断网环境下进行训练,请设置--model <model_dir>和--check_model false。如果对应的模型需要git clonegithub的仓库,例如deepseek-ai/Janus-Pro-7B,请设置手动下载仓库,并设置--local_repo_path <repo_dir>。具体参数含义请参考命令行参数文档。
- SWIFT默认在训练时设置--gradient_checkpointing true来节约显存,这会略微降低训练速度。
- 若使用DDP进行训练,出现报错:RuntimeError: Expected to mark a variable ready only once.,请额外设置参数--gradient_checkpointing_kwargs '{"use_reentrant": false}'或者使用DeepSpeed进行训练。
