Accelerate documentation
故障排除
故障排除
本指南提供了一些在使用 Accelerate 时可能遇到的问题及其解决方案。由于 Accelerate 是一个持续演进的活跃库,且存在多种不同的使用场景和分布式训练配置,因此并非所有错误都能在此涵盖。如果此处描述的解决方案无法解决您的特定错误,请参阅 寻求帮助 部分,了解在哪里以及如何获取帮助。
日志记录
日志记录有助于你定位错误的来源。在多进程组成的分布式环境中,日志记录可能颇具挑战,但 Accelerate 提供了 logging() 实用工具,以确保日志同步。
要排查问题,请使用 logging() 而不是标准的 Python logging 模块。使用 log_level 参数设置详细程度级别(INFO、DEBUG、WARNING、ERROR、CRITICAL),然后您可以:
- 将
log_level导出为ACCELERATE_LOG_LEVEL环境变量。 - 将
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 文件来启用它。
accelerate launch --debug {my_script.py} --arg1 --arg2如果通过环境变量启用调试模式,则无需调用 accelerate launch。
ACCELERATE_DEBUG_MODE="1" torchrun {my_script.py} --arg1 --arg2在 config.yaml 文件中添加 debug: true。
compute_environment: LOCAL_MACHINE
debug: true启用调试模式后,您应该会看到一个指向张量形状不匹配问题的回溯信息。
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():
breakLinux 上的低内核版本
在 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 的背景信息以及您的分布式环境详情,以便我们更好地查明问题所在并找到修复方法。