使用 🤗 Accelerate 在 Transformers 中实现分布式训练:从手写 PyTorch 训练循环到 Trainer 集成
【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers
随着模型参数量持续增长,并行(parallelism)已成为在有限硬件上训练大模型、并把训练速度提升数个数量级的关键策略。本指南以 🤗 Accelerate 为核心,完整讲解两条实战路径:一是如何用 Accelerate 改造原生 PyTorch 训练循环(仅需新增数行代码即可支持单机多卡与多机多卡);二是如何通过 Accelerate 配置文件与TrainingArguments让Trainer自动接管 FSDP、DeepSpeed、DDP 等分布式后端的全部底层机制。读完后你将掌握分布式训练的配置、改造与启动全流程,并理解其与 Transformers 源码的集成原理。
为什么需要 Accelerate:统一分布式训练的复杂性
在 Hugging Face 团队看来,并行化是解决两大现实问题的核心手段:在受限硬件上训练大模型,以及在多卡环境下成倍提升训练吞吐。但分布式训练的后端五花八门——FSDP、DeepSpeed、DDP、混合精度、多机通信……每种都有自己的配置方式和 API。🤗 Accelerate 提供的正是这样一个统一接口:它自动探测你的环境(GPU 数量、分布式后端、混合精度设置等),无论你是在单卡上用 DDP,还是在 8 卡上用 FSDP,都能自动完成配置。
Accelerate 与 Transformers 的分工非常清晰:
- Accelerate 负责把模型包进合适的分布式包装器、移动到正确的设备、创建兼容的优化器;
- 训练过程中,Accelerate 使用自己的
Accelerator.backward方法处理混合精度下的梯度缩放; Trainer调用相应的 Accelerate API,把所有分布式机制委托给 Accelerate 完成。
因此,无论是手写训练循环还是使用高层 Trainer,Accelerate 都是分布式训练能力背后的统一引擎。
路径一:改造原生 PyTorch 训练循环
这是关联文档 es/accelerate.md 的主体内容:在不引入 Trainer的情况下,用三步改造让一个普通 PyTorch 训练脚本跑在任意分布式环境中。
第一步:安装并初始化 Accelerator
安装 Accelerate:
pip install accelerate然后导入并创建Accelerator对象:
from accelerate import Accelerator accelerator = Accelerator()Accelerator会自动检测你当前可用的分布式配置类型,并初始化训练所需的全部组件。你无需手动指定模型应该放到哪个设备——设备放置(cuda/cpu/多卡)完全由 Accelerate 接管。
第二步:用 prepare 准备训练对象
把训练相关的所有对象传给prepare方法,包括训练/评估的 DataLoader、模型和优化器:
train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare( train_dataloader, eval_dataloader, model, optimizer )prepare是分布式改造的核心动作:它会依据探测到的环境,把 DataLoader 包装成分片采样(保证每个进程拿到不重叠的数据分片)、把模型包进 DDP/FSDP 等分布式包装器并移动到正确设备、为优化器创建兼容版本。这也是后文 Trainer 集成中create_accelerator_and_postprocess内部实际执行的逻辑。
第三步:用 accelerator.backward 替换 loss.backward()
在训练循环中,把常规的loss.backward()替换为 Accelerate 的backward方法。它负责在混合精度场景下正确地进行梯度缩放(gradient scaling),这是手写循环最容易出错的地方:
for epoch in range(num_epochs): for batch in train_dataloader: outputs = model(**batch) loss = outputs.loss accelerator.backward(loss) optimizer.step() lr_scheduler.step() optimizer.zero_grad() progress_bar.update(1)完整改造对比:只需 4 行代码
下面的 diff 展示了一个基于AutoModelForSequenceClassification的情感分类训练脚本的完整改造过程。注意三处变化:新增accelerator = Accelerator();删除手动的device = torch.device("cuda") ...和model.to(device)(以及循环内batch = {k: v.to(device) for k, v in batch.items()});用accelerator.prepare(...)一次性包装 DataLoader、模型和优化器;用accelerator.backward(loss)替换loss.backward()。
+ from accelerate import Accelerator from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler + accelerator = Accelerator() model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) optimizer = AdamW(model.parameters(), lr=3e-5) - device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") - model.to(device) + train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare( + train_dataloader, eval_dataloader, model, optimizer + ) num_epochs = 3 num_training_steps = num_epochs * len(train_dataloader) lr_scheduler = get_scheduler( "linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps ) progress_bar = tqdm(range(num_training_steps)) model.train() for epoch in range(num_epochs): for batch in train_dataloader: - batch = {k: v.to(device) for k, v in batch.items()} outputs = model(**batch) loss = outputs.loss - loss.backward() + accelerator.backward(loss) optimizer.step() lr_scheduler.step() optimizer.zero_grad() progress_bar.update(1)核心收益在于:你不再需要关心设备字符串、to(device)调用和数据搬运,Accelerate 统一处理了设备放置、梯度同步与混合精度。这正是文档强调的"只需要往训练循环里加四行代码"。
启动训练:脚本方式与 Notebook 方式
改造完成后,可以从脚本或 Notebook(如 Colaboratory)启动训练。
方式一:脚本启动(推荐,适合多卡/多机)
首先运行交互式配置向导,回答关于硬件和训练设置的问题,它会生成并保存一份配置文件:
accelerate config然后启动训练:
accelerate launch train.py在 examples/pytorch/README.md 中还可以看到官方推荐的完整三步流程:accelerate config回答向导问题 →accelerate test验证环境就绪 →accelerate launch path_to_script.py --args_to_script正式启动。仓库内大量的*_no_trainer.py示例脚本(如 run_qa_no_trainer.py)都遵循这一模式,例如 run_swag_no_trainer.sh 中直接用accelerate launch run_swag_no_trainer.py拉起训练。
方式二:Notebook 启动(适合 Colab TPU)
如果计划使用 Colaboratory 的 TPU,可以把负责训练的代码封装进一个函数,再传给notebook_launcher:
from accelerate import notebook_launcher notebook_launcher(training_function)路径二:通过 Trainer 集成 Accelerate
当使用高层Trainer时,你不再需要手写prepare/backward——Trainer 会在内部完成这一切。配置方式有两种:Accelerate 配置文件,或TrainingArguments参数。
方式 A:Accelerate 配置文件
先运行accelerate config并回答关于硬件与训练设置的问题,它会在缓存目录生成一份default_config.yaml。以下是一份 FSDP 配置示例(来自 en/accelerate.md):
compute_environment: LOCAL_MACHINE distributed_type: FSDP fsdp_config: fsdp_version: 2 fsdp_reshard_after_forward: true fsdp_cpu_offload: false fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP fsdp_cpu_ram_efficient_loading: true fsdp_activation_checkpointing: false fsdp_state_dict_type: SHARDED_STATE_DICT fsdp_transformer_layer_cls_to_wrap: LlamaDecoderLayer mixed_precision: bf16 num_machines: 1 num_processes: 4关键字段速览:
compute_environment:计算环境类型,本地机器为LOCAL_MACHINE;distributed_type:分布式后端,可选FSDP、DEEPSPEED、MULTI_GPU(DDP)等;fsdp_config:FSDP 专属配置块,包括分片策略(fsdp_auto_wrap_policy)、CPU 卸载(fsdp_cpu_offload)、激活检查点(fsdp_activation_checkpointing)以及需要包装的 Transformer 层类(fsdp_transformer_layer_cls_to_wrap: LlamaDecoderLayer)等;mixed_precision:混合精度类型,如bf16、fp16;num_machines/num_processes:机器数量与总进程数(通常等于 GPU 总数)。
之后用accelerate launch运行基于 Trainer 的脚本,Accelerate 会读取该配置文件完成训练环境搭建:
accelerate launch train.py值得注意:使用 Accelerate 配置文件时,TrainingArguments中的fsdp_config和deepspeed参数就不再需要设置了,因为配置文件已覆盖相同的配置项,避免双重配置引发冲突。
通过 accelerator_config 传入无专用参数的设置
TrainingArguments的accelerator_config参数用于接收那些没有独立顶层参数的 Accelerate 设置。一个典型例子是non_blocking=True:把它与dataloader_pin_memory=True搭配,可以让数据搬运与计算重叠,提升 GPU 吞吐:
from transformers import TrainingArguments TrainingArguments( ..., dataloader_pin_memory=True, accelerator_config={ "non_blocking": True, }, )这一设计在源码中有直接印证:accelerator_config字段接受一个 JSON 配置文件路径或字典。在 create_accelerator_and_postprocess 中,Trainer 会从accelerator_config中提取出split_batches、dispatch_batches、even_batches、use_seedable_sampler等 DataLoader 相关参数构造DataLoaderConfiguration,并单独取出non_blocking——同时还会校验:如果开启了non_blocking却没有开启dataloader_pin_memory,会打印性能建议警告(源码见 trainer.py)。
方式 B:通过 TrainingArguments 配置后端
也可以直接向TrainingArguments传入后端专属配置,由create_accelerator_and_postprocess读取并据此完成训练配置。三种常用后端对比如下。
FSDP(全分片数据并行)
把 JSON 配置文件路径或字典传给fsdp_config:
from transformers import TrainingArguments TrainingArguments( ..., fsdp=True, fsdp_config="path/to/fsdp.json", )完整指南与配置参考见 FSDP 指南。
DeepSpeed(ZeRO 优化与卸载)
把 JSON 配置文件路径或字典传给deepspeed:
from transformers import TrainingArguments TrainingArguments( ..., deepspeed="path/to/ds_config.json", )完整指南与配置参考见 DeepSpeed 指南。
DDP(数据并行)
模型能放进单卡时,DDP 直接通过TrainingArguments字段配置:
from transformers import TrainingArguments TrainingArguments( ..., ddp_backend="nccl", ddp_find_unused_parameters=False, ddp_bucket_cap_mb=25, ddp_timeout=1800, )常用 DDP 参数说明:
ddp_backend:通信后端,NVIDIA GPU 用"nccl"(默认且最快),CPU 训练或调试用"gloo",其他硬件分别有"xccl"、"hccl"、"cncl"等;ddp_find_unused_parameters:在前向结束遍历 autograd 图,为不会收到梯度的参数标记 ready,避免阻塞 all-reduce;不要与梯度检查点(gradient_checkpointing)同用;ddp_bucket_cap_mb:反向时将梯度打包进单次 all-reduce 的桶大小,更大的桶意味着更少的 all-reduce 调用和更低的启动开销;ddp_timeout:所有进程与通信操作(all-reduce、broadcast)的时间上限,进程挂起时抛出错误而非无限阻塞。
更完整的 DDP 机制讲解(含梯度累积与 all-reduce 时序)见 DDP 指南。
源码视角:Trainer 如何创建 Accelerator
理解了两种配置方式后,再深入源码看清 Trainer 内部的集成流程,这能帮助你诊断分布式训练中的问题。
create_accelerator_and_postprocess(trainer.py)是集成的枢纽方法,其执行流程大致如下:
- 梯度累积交由 Trainer 自己处理:显式地把
gradient_accumulation_kwargs["num_steps"]设为 1,避免与TrainingArguments.gradient_accumulation_steps双重计算(源码见 trainer.py); - 解析
accelerator_config:拆出 DataLoader 配置与non_blocking等参数; - 调用
_build_accelerator_args(trainer.py)组装 Accelerator 关键字参数:包括mixed_precision、deepspeed_plugin、由DistributedDataParallelKwargs包装的 DDP 参数(find_unused_parameters、bucket_cap_mb、broadcast_buffers、static_graph)、dataloader_config、gradient_accumulation_plugin、可选的fsdp_plugin与dynamo_plugin(torch.compile 后端),以及要求 Accelerate ≥ 1.12.0 的张量并行parallelism_config; - 创建 Accelerator 实例:
self.accelerator = Accelerator(**args)(trainer.py); - 后处理:通过
accelerator.state检测是否启用了 DeepSpeed/FSDP(is_deepspeed_enabled、is_fsdp_enabled),并做冲突校验——例如 FSDP 的activation_checkpointing与TrainingArguments.gradient_checkpointing不能同时为 True(trainer.py)。
值得留意的一点是 DDP 的find_unused_parameters默认值推导逻辑:当模型是PreTrainedModel时,Trainer 会自动取not (model.is_gradient_checkpointing or args.gradient_checkpointing),即开启梯度检查点时自动关闭该选项,这与官方文档"不要与 gradient_checkpointing 同用"的告诫完全一致(trainer.py)。
下一步深入方向
- 模型能放进单卡时,阅读 DDP 指南 掌握数据并行训练的梯度同步细节;
- 模型超出单卡显存时,阅读 FSDP 指南 学习跨卡分片参数、梯度与优化器状态;
- 需要 ZeRO 优化与 CPU/异构卸载时,阅读 DeepSpeed 指南。
总而言之,无论你选择手写训练循环还是高层 Trainer,Accelerate 都是 Transformers 分布式训练的统一底座:前者通过Accelerator+prepare+backward三步改造即可跑通多卡;后者只需一份accelerate config配置文件或几个TrainingArguments参数,Trainer 便会自动完成分布式后端的创建、包装与校验。理解这条集成链路,你就能在任何分布式环境中自如地训练 Transformers 模型。
【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考