Accelerate documentation

故障排除

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 时可能遇到的问题及其解决方案。由于 Accelerate 是一个持续演进的活跃库,且存在多种不同的使用场景和分布式训练配置,因此并非所有错误都能在此涵盖。如果此处描述的解决方案无法解决您的特定错误,请参阅 寻求帮助 部分,了解在哪里以及如何获取帮助。

日志记录

日志记录有助于你定位错误的来源。在多进程组成的分布式环境中,日志记录可能颇具挑战,但 Accelerate 提供了 logging() 实用工具,以确保日志同步。

要排查问题,请使用 logging() 而不是标准的 Python logging 模块。使用 log_level 参数设置详细程度级别(INFO、DEBUG、WARNING、ERROR、CRITICAL),然后您可以:

  1. 将 log_level 导出为 ACCELERATE_LOG_LEVEL 环境变量。
  2. 将 log_level 直接传递给 get_logger。

例如,要设置 log_level="INFO":

from accelerate.logging import get_logger

logger = get_logger(__name__, log_level="DEBUG")

默认情况下,日志仅在主进程上调用。若要在所有进程上调用,请传入 main_process_only=False。 如果日志需要在所有进程上按顺序调用,请同时传入 in_order=True。

from accelerate.logging import get_logger

logger = get_logger(__name__, log_level="DEBUG")
# log all processes
logger.debug("thing_to_log", main_process_only=False)
# log all processes in order
logger.debug("thing_to_log", main_process_only=False, in_order=True)

代码挂起和超时错误

代码挂起的原因可能有很多。让我们来看看如何解决一些最常见的导致代码挂起的问题。

张量形状不匹配

张量形状不匹配是一个常见问题,在分布式环境中可能会导致代码长时间挂起。

在分布式环境中运行脚本时,需要使用诸如 Accelerator.gather() 和 Accelerator.reduce() 等函数,以跨设备获取张量并对它们执行集体操作。这些(以及其他)函数依赖 torch.distributed 来执行 gather 操作,该操作要求所有进程中的张量具有 完全相同的形状。如果张量形状不匹配,代码将会挂起,并最终触发超时异常。

您可以使用 Accelerate 的操作调试模式来立即捕获此问题。我们建议在 accelerate config 配置过程中启用此模式,但您也可以通过命令行界面、环境变量或手动编辑 config.yaml 文件来启用它。

CLI
环境变量
config.yaml
accelerate launch --debug {my_script.py} --arg1 --arg2

启用调试模式后,您应该会看到一个指向张量形状不匹配问题的回溯信息。

Traceback (most recent call last):
  File "/home/zach_mueller_huggingface_co/test.py", line 18, in <module>
    main()
  File "/home/zach_mueller_huggingface_co/test.py", line 15, in main
    broadcast_tensor = broadcast(tensor)
  File "/home/zach_mueller_huggingface_co/accelerate/src/accelerate/utils/operations.py", line 303, in wrapper
accelerate.utils.operations.DistributedOperationException:

Cannot apply desired operation due to shape mismatches. All shapes across devices must be valid.

Operation: `accelerate.utils.operations.broadcast`
Input shapes:
  - Process 0: [1, 5]
  - Process 1: [1, 2, 5]

早停

在分布式训练中实现早停时,如果每个进程都有特定的停止条件(例如验证损失),这些条件可能无法在所有进程之间同步。因此,进程 0 可能会触发 break,而进程 1 不会,这会导致代码无限期挂起,直到发生超时。

如果存在提前停止的条件,请使用 set_trigger 和 check_trigger 方法,以确保所有进程都能正确结束。

# Assume `should_do_breakpoint` is a custom-defined function that returns a conditional, 
# and that conditional might be true only on process 1
if should_do_breakpoint(loss):
    accelerator.set_trigger()

# Later in the training script when we need to check for the breakpoint
if accelerator.check_trigger():
    break

Linux 上的低内核版本

在 Linux 内核版本 < 5.5 上,有进程挂起的报告。为避免此问题,请将系统升级到更高的内核版本。

MPI

如果在使用 MPI 的分布式 CPU 训练任务出现挂起,请确保节点之间已配置 免密 SSH(使用密钥)。这意味着,对于 hostfile 中的所有节点,您都应能够在不输入密码的情况下从一个节点 SSH 到另一个节点。

接下来,尝试运行 mpirun 命令以进行健全性检查。例如,下面的命令应打印出每个节点的主机名。

mpirun -f hostfile -n {number of nodes} -ppn 1 hostname

内存不足

One of the most frustrating errors when it comes to running training scripts is hitting “Out-of-Memory” on devices like CUDA, XPU or CPU. The entire script needs to be restarted and any progress is lost.

为解决此问题,Accelerate 提供了 find_executable_batch_size() 实用工具,该工具主要基于 toma。 此工具会重试因 OOM(内存不足)条件而失败的代码,并自动降低批处理大小。对于每次 OOM 条件,算法会将批处理大小减半并重试代码,直到成功为止。

要使用 find_executable_batch_size(),请重构训练函数,在其中包含一个内部函数,并在该内部函数中使用 find_executable_batch_size 并构建数据加载器。至少,这只需要新增 4 行代码。

内部函数必须以批大小作为第一个参数,但在调用时我们并不会向其传递该参数,包装器会为您处理这一点。任何消耗设备内存并传递给Accelerator的对象(模型、优化器)也必须在内部函数中声明。

def training_function(args):
    accelerator = Accelerator()

+   @find_executable_batch_size(starting_batch_size=args.batch_size)
+   def inner_training_loop(batch_size):
+       nonlocal accelerator # Ensure they can be used in our context
+       accelerator.free_memory() # Free all lingering references
        model = get_model()
        model.to(accelerator.device)
        optimizer = get_optimizer()
        train_dataloader, eval_dataloader = get_dataloaders(accelerator, batch_size)
        lr_scheduler = get_scheduler(
            optimizer, 
            num_training_steps=len(train_dataloader)*num_epochs
        )
        model, optimizer, train_dataloader, eval_dataloader, lr_scheduler = accelerator.prepare(
            model, optimizer, train_dataloader, eval_dataloader, lr_scheduler
        )
        train(model, optimizer, train_dataloader, lr_scheduler)
        validate(model, eval_dataloader)
+   inner_training_loop()

不同设备配置之间结果不可复现

如果您更改了设备配置并观察到不同的模型性能,很可能是因为在从一个配置切换到另一个配置时,您没有更新脚本。即使您使用相同的脚本和相同的批处理大小,在 TPU、多 GPU 和单 GPU 上的结果仍然会有所不同。

例如,如果你最初在单 GPU 上以 16 的批大小进行训练,然后切换到双 GPU 配置,你需要将批大小更改为 8,才能保持相同的有效批大小。这是因为在使用 Accelerate 进行训练时,传递给数据加载器的批大小是每个 GPU 的批大小。

为确保在不同配置之间能够复现结果,请确保使用相同的随机种子,相应地调整批大小,并考虑对学习率进行缩放。

有关更多详细信息以及批量大小的快速参考,请参阅比较不同设备配置之间的性能指南。

不同 GPU 上的性能问题

如果您的多 GPU 配置由不同的 GPU 组成,您可能会遇到一些性能问题:

  • 各 GPU 之间的显存可能存在不均衡。在这种情况下,显存较小的 GPU 将限制可以加载到 GPU 上的批处理大小或模型大小。
  • 如果您使用的是性能规格不同的 GPU,整体性能将由其中最慢的 GPU 决定,因为其他 GPU 必须等待它完成其工作负载。

同一配置中性能差异巨大的 GPU 可能会导致性能瓶颈。

寻求帮助

如果本文中的解决方案和建议未能解决您的问题,您随时可以联系社区和 Accelerate 团队寻求帮助。

  • 在 Hugging Face 论坛上发帖求助,请将你的问题发布在 Accelerate 分类 下。请务必撰写描述清晰的帖子,提供关于你环境的相关背景信息以及可复现的代码,以最大程度提高问题得到解决的可能性!

  • 在 Discord 上发布问题,让团队和社区来帮助你。

  • 如果您认为发现了与 Accelerate 库相关的 bug,请在 Accelerate 的 GitHub 仓库中创建一个 Issue。请提供有关该 bug 的背景信息以及您的分布式环境详情,以便我们更好地查明问题所在并找到修复方法。

Update on GitHub