加速训练
Gaudi 提供了几种加快训练速度的方法。它们彼此兼容,并且可以与 分布式训练 相结合。
懒惰模式
提出了两种执行模式
- 懒惰模式,其中操作在图中累积,图的执行以懒惰的方式触发。这使得图编译器能够优化这些操作的设备执行。
- 急切模式,其中一次执行一个操作。
在懒惰模式下,图编译器生成优化的二进制代码,该代码在 Gaudi 上实现给定的模型拓扑。它执行操作融合、数据布局管理、并行化、流水线处理和内存管理,以及图级优化。
要在懒惰模式下执行训练,您必须提供以下训练参数
args = GaudiTrainingArguments(
# same arguments as in Transformers,
use_habana=True,
use_lazy_mode=True,
gaudi_config_name=path_to_my_gaudi_config
)
在懒惰模式下,默认情况下,最后一个批次将用额外的样本填充,使其具有与之前批次相同的维度。这使您能够避免在训练期间进行额外的图编译。您也可以使用 dataloader_drop_last=True
丢弃最后一个批次。
在懒惰模式下,前两到三次训练迭代可能比较慢,因为要进行图编译。为了不在训练结束时的吞吐量计算中考虑这些迭代,您可以添加以下训练参数:throughput_warmup_steps=3
。
混合精度训练
混合精度训练能够使用更轻量级的数据类型来计算某些操作,从而加速训练。Optimum Habana 以类似于 🤗 Transformers 的方式启用混合精度训练
- 参数
--bf16
启用 PyTorch 自动广播的使用 - 参数
--half_precision_backend [hpu_amp, cpu_amp]
用于指定应执行混合精度操作的设备
请参阅 Gaudi 上的高级自动广播用法 以获取有关
- 默认自动广播操作
- 默认自动广播操作覆盖
HPU 图表
PyTorch 的灵活性是有代价的——通常,相同的 Pythonic 逻辑会在每个训练步骤中重复执行。这可能会导致 CPU 在 Habana 加速器上调度工作所花费的时间比加速器实际计算时间更长。为了应对这种主机绑定的工作负载,您可能想要尝试启用 HPU 图表 功能,该功能会记录一次计算图,然后以快得多的速度多次触发它进行执行。
为此,请指定 --use_hpu_graphs_for_training True
。此选项将用 habana_frameworks.torch.hpu.ModuleCacher
包装模型,该模型会自动在模型的使用情况上记录 HPU 图表。
对于多工作程序分布式训练,您还需要指定 --distribution_strategy fast_ddp
。此选项将替换 torch.nn.parallel.DistributedDataParallel
的使用,使用更简单且通常更快的 optimum.habana.distributed.all_reduce_gradients
。
谨慎使用:目前,使用 HPU 图表进行训练可能不支持所有可能的情况。但是,潜在的性能提升可能是巨大的!
快速 DDP
对于在多个设备上进行分布式训练,您也可以指定 --distribution_strategy fast_ddp
。 此选项将使用更简单且通常更快的 optimum.habana.distributed.all_reduce_gradients
替换 torch.nn.parallel.DistributedDataParallel
的使用。
流水线式前向和反向传递
在 Habana HPU 上运行模型时,有两个阶段:CPU 上的 Python 代码解释和 HPU 公式计算。HPU 计算阶段可以手动触发,也可以在请求复制到 CPU 时触发,通常 HPU 计算会在 loss.backward()
之后触发,以使 CPU 代码解释和 HPU 公式计算重叠,如下面的图示所示。
CPU:...forward + backward ...optimizer ...forward + backward ...optimizer ...
HPU:........................forward + backward...optimizer......forward + backward...optimizer
但是,当 CPU 代码解释时间比 HPU 计算时间长时,它就会成为瓶颈,HPU 计算无法在 CPU 代码解释完成之前触发。因此,对于这种情况,一个潜在的优化方法是在 CPU 前向 解释之后,并且在 CPU 反向 解释之前触发 HPU 前向 计算。您可以在下面看到一个示例,其中 CPU 反向 解释与 HPU 前向 计算重叠。
CPU:...forward ...backward ...optimizer ...forward ...backward ...optimizer ...
HPU:.............forward.......backward......optimizer......forward.....backward.......optimizer
要启用此优化,您可以设置以下训练参数 --pipelining_fwd_bwd True
。
我们建议在 Gaudi2 上使用它,因为主机通常是瓶颈。您应该能够在第一代 Gaudi 上看到加速,但它不会像在 Gaudi2 上那么明显,因为您的运行更有可能受 HPU 限制。
此外,当训练需要大量设备内存的模型时,我们建议禁用此优化,因为它会增加 HPU 内存使用量。
使用更多工作线程加载数据
如果数据加载器的工作量很大,您可以增加工作线程的数量,以加快运行速度。您可以使用训练参数 --dataloader_num_workers N
启用此功能,其中 N
是要使用的工作线程数。
我们建议将它与包含图像的数据集一起使用。 此外,在大多数情况下使用 --dataloader_num_workers 1
会有所帮助,因为它可以在与主线程不同的线程中启用数据加载。
非阻塞数据复制
此优化非常适合那些数据从主机复制到设备成本很高的模型(例如,像 ViT 或 Swin 这样的视觉模型)。您可以使用训练参数 --non_blocking_data_copy True
启用它。
我们建议在 Gaudi2 上使用它,因为主机可以继续执行其他任务(例如,图构建),以在主机和设备之间实现更好的流水线。在第一代 Gaudi 上,设备执行时间更长,因此不应该期望看到任何加速。
自定义运算符
Habana 提供了一些自定义运算符,它们在 Gaudi 上比它们的 PyTorch 对应运算符实现了更好的性能。您也可以像 这里 所述的那样为 Gaudi 定义自己的自定义运算符。
融合 ADAM
Habana 提供了 自定义融合 ADAM 实现。可以通过在 Gaudi 配置文件中指定 "use_fused_adam": true
来使用它。
Habana 融合 ADAM 优化器的epsilon默认值为 1e-6
,而 torch.optim.AdamW
的默认值为 1e-8
。
融合梯度范数裁剪
Habana 提供了 自定义梯度范数裁剪实现。可以通过在 Gaudi 配置文件中指定 "use_fused_clip_norm": true
来使用它。
跟踪内存使用情况
每 logging_steps
(默认值为 500)步显示实时内存统计信息。
memory_allocated (GB)
指的是以 GB 为单位的当前内存使用量,max_memory_allocated (GB)
指的是以 GB 为单位的运行过程中达到的最大内存使用量,total_memory_available (GB)
指的是以 GB 为单位的设备上可用的总内存。
这些指标可以帮助您调整运行的批次大小。
在分布式模式下,内存统计信息仅由主进程进行通信。
您可以查看 英特尔® Gaudi® AI 加速器的官方文档,以获取有关内存统计信息 API 的更多信息。
< > 更新 在 GitHub 上