Accelerate documentation

在代码中添加 Accelerate

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v1.15.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

在代码中添加 Accelerate

每个分布式训练框架都有其独特的工作方式,这可能需要编写大量自定义代码,才能将其适配到 PyTorch 训练代码和训练环境中。Accelerate 提供了一种友好的方式来对接这些分布式训练框架,而无需学习每个框架的具体细节。Accelerate 会为您处理这些细节,因此您可以专注于训练代码,并将其扩展到任何分布式训练环境。

在本教程中,你将学习如何使用 Accelerate 适配现有的 PyTorch 代码,从而轻松迈向分布式系统训练!你将从一个基础的 PyTorch 训练循环开始(假设诸如 model 和 optimizer 等训练对象已经配置完毕),并逐步将 Accelerate 集成到其中。

device = "cuda"
model.to(device)

for batch in training_dataloader:
    optimizer.zero_grad()
    inputs, targets = batch
    inputs = inputs.to(device)
    targets = targets.to(device)
    outputs = model(inputs)
    loss = loss_function(outputs, targets)
    loss.backward()
    optimizer.step()
    scheduler.step()

加速器

Accelerator 是用于将代码适配到 Accelerate 的主要类。它了解你所使用的分布式配置,例如不同的进程数量以及硬件类型。该类还提供了许多必要的方法,使你的 PyTorch 代码能够在任何分布式训练环境中运行,并管理跨设备的进程执行。

这就是为什么您应该始终在脚本中先导入并创建一个 Accelerator 实例。

from accelerate import Accelerator

accelerator = Accelerator()

Accelerator 还知道应将您的 PyTorch 对象移动至哪个设备,因此建议交由 Accelerate 来处理此操作。

- device = "cuda"
+ device = accelerator.device
  model.to(device)

准备 PyTorch 对象

接下来,您需要为分布式训练准备 PyTorch 对象(模型、优化器、调度器等)。prepare() 方法会负责将模型放置在适合您训练配置的容器中(例如单 GPU 或多 GPU),将优化器和调度器适配为使用 Accelerate 的 AcceleratedOptimizer 和 AcceleratedScheduler,并创建一个可以跨进程分片的新数据加载器。

Accelerate 仅准备继承自相应 PyTorch 类的对象,例如 torch.optim.Optimizer。

PyTorch 对象将按照发送的顺序返回。

model, optimizer, training_dataloader, scheduler = accelerator.prepare(
    model, optimizer, training_dataloader, scheduler
)

训练循环

最后,请移除训练循环中对输入和目标调用 to(device) 的操作,因为 Accelerate 的 DataLoader 类会自动将它们放置在正确的设备上。此外,您还应将常规的 backward() 反向传播替换为 Accelerate 的 backward() 方法,该方法会为您缩放梯度,并根据您的分布式配置(例如 DeepSpeed 或 Megatron)使用相应的 backward() 方法。

-   inputs = inputs.to(device)
-   targets = targets.to(device)
    outputs = model(inputs)
    loss = loss_function(outputs, targets)
-   loss.backward()
+   accelerator.backward(loss)

将所有内容整合起来,你的新 Accelerate 训练循环现在应该如下所示!

from accelerate import Accelerator
accelerator = Accelerator()

device = accelerator.device
model, optimizer, training_dataloader, scheduler = accelerator.prepare(
    model, optimizer, training_dataloader, scheduler
)

for batch in training_dataloader:
    optimizer.zero_grad()
    inputs, targets = batch
    outputs = model(inputs)
    loss = loss_function(outputs, targets)
    accelerator.backward(loss)
    optimizer.step()
    scheduler.step()

训练功能

Accelerate 提供了更多功能——例如梯度累积、梯度裁剪、混合精度训练等——你可以将它们添加到脚本中,以优化训练过程。让我们来探索这三个功能。

梯度累积

梯度累积允许你通过累积多个批次的梯度后再更新权重,从而以更大的批大小进行训练。这在突破内存限制时非常有用。要在 Accelerate 中启用此功能,请在 Accelerator 类中指定 gradient_accumulation_steps 参数,并在你的脚本中添加 accumulate() 上下文管理器。

+ accelerator = Accelerator(gradient_accumulation_steps=2)
  model, optimizer, training_dataloader = accelerator.prepare(model, optimizer, training_dataloader)

  for input, label in training_dataloader:
+     with accelerator.accumulate(model):
          predictions = model(input)
          loss = loss_function(predictions, label)
          accelerator.backward(loss)
          optimizer.step()
          scheduler.step()
          optimizer.zero_grad()

梯度裁剪

梯度裁剪是一种防止“梯度爆炸”的技术,Accelerate 提供了:

混合精度

混合精度通过使用较低精度的数据类型(如 fp16 半精度)来计算梯度,从而加速训练。为了在 Accelerate 中获得最佳性能,损失应在模型内部计算(例如在 Transformers 模型中),因为模型外部的计算将以全精度执行。

将 Accelerator 中使用的混合精度类型设置好,然后使用 autocast() 上下文管理器将值自动转换为指定的数据类型。

Accelerate 支持自动混合精度,因此只有在 backward() 已处理缩放的损失执行操作之外,还存在其他混合精度操作时,才需要 autocast()。

+ accelerator = Accelerator(mixed_precision="fp16")
+ with accelerator.autocast():
      loss = complex_loss_function(outputs, target)

保存和加载

Accelerate 还可以在训练完成后保存和加载 model,或者保存模型和优化器的 state,这对于恢复训练可能很有用。

模型

当所有进程完成后,在保存模型之前,请使用 unwrap_model() 方法解包模型,因为 prepare() 方法已将您的模型包装为适用于分布式训练的正确接口。如果您不解包模型,保存模型状态字典时也会保存来自更大模型的潜在额外层,您将无法将权重重新加载回基础模型中。

您应使用 save_model() 方法来解包并保存模型状态字典。该方法还可以将模型保存为分片检查点或 safetensors 格式。

单个检查点
分片检查点
accelerator.wait_for_everyone()
accelerator.save_model(model, save_directory)

对于来自 Transformers 库的模型,请使用 save_pretrained 方法保存模型,以便之后可以使用 from_pretrained 方法重新加载。

from transformers import AutoModel

unwrapped_model = accelerator.unwrap_model(model)
unwrapped_model.save_pretrained(
    "path/to/my_model_directory",
    is_main_process=accelerator.is_main_process,
    save_function=accelerator.save,
)

model = AutoModel.from_pretrained("path/to/my_model_directory")

要加载权重,请先使用 unwrap_model() 方法解包模型,然后再加载权重。由于所有模型参数都是张量的引用,因此这会将权重加载到 model 内部。

unwrapped_model = accelerator.unwrap_model(model)
path_to_checkpoint = os.path.join(save_directory,"pytorch_model.bin")
unwrapped_model.load_state_dict(torch.load(path_to_checkpoint))

状态

在训练过程中,您可能希望保存模型、优化器、随机数生成器以及潜在的学习率调度器的当前状态,以便在同一脚本中恢复它们。您应该在脚本中添加save_state()和load_state()方法来保存和加载状态。

若要进一步自定义通过 save_state() 保存状态的位置和方式,请使用 ProjectConfiguration 类。例如,如果启用了 automatic_checkpoint_naming,则每个保存的检查点都会存储在 Accelerator.project_dir/checkpoints/checkpoint_{checkpoint_number} 中。

其他需要存储的有状态项应通过 register_for_checkpointing() 方法进行注册,以便能够保存和加载。传递给此方法以进行存储的每个对象都必须具有 load_state_dict 和 state_dict 函数。

如果已安装 torchdata>=0.8.0,你还可以将 use_stateful_dataloader=True 传入 DataLoaderConfiguration。这将为 Accelerate 的 DataLoader 类扩展出 load_state_dict 和 state_dict 函数,并使得 Accelerator.save_state 和 Accelerator.load_state 在持久化模型时,也能记录训练数据集的读取进度。

Update on GitHub