PyTorch 官方博客:PyTorch Profiler v1.9 详解

2,320 阅读10分钟

在这里插入图片描述 Profiler v1.9 的改进主要针对在运行时和/或内存上能耗最严重的执行步骤,同事将 GPU 和 CPU 之间的工作负载分配进行可视化。

Profiler v1.9 新增五个主要功能包括:

1、分布式训练视图: 这有助于你掌握分布式训练任务中,消耗的时间和内存。假设你有一个训练模型,当你要把负载分成 Worker 节点并行运行时,可能会像黑盒一样,出现各种各样的问题。模型整体的目标是提高训练速度。这个分布式训练视图有助于你诊断和调试单个节点内的问题。

2、内存视图: 借助该视图,你可以更好地了解内存使用情况。这个工具能显示程序在不同运行阶段的活动内存分配情况,从而帮助你避免 Out of Memory 错误的发生。

3、GPU 应用可视化: 该工具可以确保 GPU 得到充分利用。

4、云存储支持: Tensorboard 插件现在可以从Azure Blob Storage、Amazon S3和Google Cloud Platform 读取解析数据。

5、跳转源代码: 该功能支持堆栈跟踪信息可视化,并可以直接跳转至源代码。这有助于你根据分析结果快速优化和迭代代码。

PyTorch Profiler Colab 传送门

汉化版 Colab 传送门

Colab 内容一览:

  • 准备数据和模型

  • 使用 Profiler 记录执行事件

  • 运行 Profiler

  • 使用 TensorBoard 查看结果并分析模型性能

  • 借助 Profiler 提高性能

  • 使用其他高级功能分析性能

开始使用 PyTorch Profiling 工具

首先:

$ pip install torch-tb-profiler

import torch.profiler as profiler
With profiler.profile(XXXX)

备注: 关于 CUDA 和 CPU 的分析,详见 Here

with torch.profiler.profile( 
activities=[ 
torch.profiler.ProfilerActivity.CPU, 
torch.profiler.ProfilerActivity.CUDA],
  • profiler.record_function("$NAME"):允许为函数区块添加装饰器 (decorator,指与名称相关的标签)。

  • profiler.profile 下的 Profile_memory=True 参数,可以对 CPU 和 GPU 的内存占用情况进行分析。

对 PyTorch 模型性能进行可视化

分布式训练

深度学习的最新进展证明了大型数据集和大型模型的价值,这也意味着模型训练需要更多的计算资源。

分布式数据并行 (DDP) 和英伟达多卡通信框架 (NCCL) 是 PyTorch 中广泛采用的范式,用于加速深度学习训练。

在这个版本的 PyTorch Profiler 中,现已支持 NCCL 后端的 DDP。 在这里插入图片描述

计算/通信概览

在分布式训练视图中的「计算/通信概览」中,用户可以观察所有 Worker 之间「load balancer」节点的计算与通信比,这是按照颗粒度来衡量的。

load balancer 相关链接: Here

情景 1:

如果一个 Worker 的计算和重叠时间,比其他 Worker 长,这可能表示工作负载均衡中存在问题,或有一个节点是 straggler。计算是 GPU 内核时间之和,减去重叠时间。重叠时间是指计算过程中,通过交错通信节省的时间。

重叠时间越长,表示计算和通信之间的并行性更好。理想状况下,计算和通信完全相互重叠。通信是总的通信时间减去重叠时间。

以下示例展示了这种情况在 Tensorboard 上的表现。 在这里插入图片描述 straggler 示例

情景 2:

如果批尺寸较小(即所有 Worker 上的计算都比较少),或需要传输的数据较大,那么计算通信比也可能较小,在 Profiler 中可以看到 GPU 利用率低,等待时间长。

用户可以根据这种计算/通信视图 review 代码,通过采用梯度累积来减少通信,或通过增加批尺寸来减少通信比例。DDP 通信时间取决于模型大小。批尺寸与模型大小无关。因此,增加批尺寸可以使计算时间更长、计算通信例更大。

同步/通信概览

在同步/通信视图中,用户可以观察通信效率。这是用步骤时间减去计算和通信时间得出来的。同步时间是等待并与其他 Worker 同步的总通信时间的一部分。同步/通信视图包括初始化、数据加载器、CPU计算等。

从该视图中可以得知:总通信量中真正用于交换数据的比例是多少,等待其他 Worker 提供数据的空置时间是多少。

在这里插入图片描述

例如,如果存在低效的工作负载均衡或 straggler 问题,就可以在同步/通信视图中发现。这个视图将展示一些 Worker 的等待时间比其他 Worker 长。

图片

从上表可以得知每个节点中所有通信算子的详细统计数据。通过该表可以了解调用了哪些算子类型,每个算子被调用了多少次,每个算子所传输的数据大小是多少,等等。

内存视图

利用该工具,可以了解模型中算子的硬件资源消耗。了解算子层面的时间和内存消耗,有助于解决性能瓶颈问题,进而加快模型运行速度。鉴于 GPU 内存大小有限,优化内存使用效率有助于:

  • 允许运行更大规模的模型,在终端级别的任务上表现更好。

  • 允许更大的批尺寸,提高训练速度。

Profiler 记录了 Profiler 间隔期间的所有内存分配。选择「设备」就可以看到每个算子在 GPU 侧或主机侧的内存使用详情。

注意:必须启用 profile_memory=True 来生成以下内存数据。

相关链接: Here

With torch.profiler.profile(
Profiler_memory=True # this will take 1 – 2 minutes to complete. 
)

重要定义:

  • 「Size Increase」显示所有分配字节的总和,减去所有内存释放字节。

  • 「Allocation Size」显示不包括内存释放的所有分配字节的总和。

  • 「Self」意味着分配的内存不是来自任何 child 算子,而是由算子自行分配的。

图片

时间轴上的 GPU 指标

利用该功能,你可以在一个或多个 GPU 利用不充分时,轻松调试性能问题。理想情况下,你的程序应该有很高的 GPU 利用率(尽可能达到 100% 的 GPU 利用率),CPU 到 GPU 的通信成本最低,且没有功耗。

概述: 概述页面强调了三个重要的 GPU 使用指标 (即 GPU Utilization、Est. SM Efficiency 以及 Est. Achieved Occupancy) 在不同层面的结果。

从本质上讲,每个 GPU 都有很多 SM,每个 SM 都有很多 Warp,可以同时执行很多线程。Warp 执行 的线程多,是因为其数量取决于 GPU。从更高角度来看,时间轴上的 GPU 指标可以帮助开发者对整个堆栈有全局观,这非常重要。

如果 GPU 利用率很低,则表明模型有潜在问题。常见原因如下:

  • 内核中的并行性不足,即批尺寸过小

  • 在一个循环中调用小内核,即启动 overhead 没被摊销

  • CPU 或 I/O 瓶颈导致工作内容不足,GPU 利用率低

在概览页面中,性能建议部分是一些可以提高 GPU 利用率的可行性建议。在这个例子中,GPU 利用率很低,所以性能建议是增加批尺寸。根据性能建议,将批尺寸从 4 增加到 32,使 GPU 利用率增加了 60.68%。

GPU 利用率: 在 Profiler 中,当 GPU 引擎执行一个工作负载时会出现一个步骤间隔时间 (step interval time)。利用率百分比越高越好。仅通过 GPU 利用率来判断性能瓶颈,结果并不准确。你无法借此得知到底有多少流处理器 (Streaming Multiprocessor) 在运行。

注意,虽然这个指标对检测空闲期很有帮助,但高数值并不代表 GPU 的利用率很高。如,一个单线程连续运行的内核,其 GPU 利用率将达到 100%。

预估流处理器效率 (Est. SM Efficiency) 是一个更细化的指标, 它表示在跟踪全过程中,正在使用的 SM 的百分比,代表 SM 上至少有一个活动 wrap 的 time 百分比,以及那些空闲 warp。

NVIDIA 文档: Here

Est. SM Efficiency 也有局限性。如每个区块只有一个线程的内核,无法完全利用所有 SM。只依据 SM Efficiency 无法得知每个 SM 的利用率,只能知道每个 SM 正在进行的操作,这包括等待内存加载结果时的停顿。

为了保持 SM 的高利用率,必须保证足够数量的 ready wrap,只要发生停滞就可以运行。

对于性能诊断问题而言,预估实现的占用率(Est. Achieved Occupancy)比 Est. SM Efficiency 和 GPU 利用率更准确。预估实现的占用率表明每个 SM 有多少 warp 可以同时活动。拥有数量足够多的活动 warp 通常是实现良好吞吐量的关键。与 GPU 利用率和 SM Efficiency 不同,让这个值尽可能高并不是终极目的。

从经验角度出发,通过将这个指标提高到 15% 或以上,可以获得良好的吞吐量收益。但在某些时候,也会遇到收益递减的情况。例如,如果该值已经达到 30%,接下来的收益就变得不确定了。这个指标展示了内核执行期间,所有 warp scheduler 的平均值

NVIDIA 文档: Here

Est. Achieve Occupancy 的值越大越好。

图片

详细细节:Resnet50_batchsize4

图片

详细细节:Resnet50_batchsize32

内核视图:内核有「Blocks per SM」和「Est. Achieved Occupancy」。

Est. Achieved Occupancy 是比较模型运行状况的有利工具。

图片

每个 SM 的平均取块数 (Mean Blocks per SM):

每 SM 的区块数量=该内核的区块数/该 GPU 的 SM 数。如果这个数字小于 1,表明 GPU 多处理器没有被完全利用。"Mean Blocks per SM "是这个内核 name 所有运行的加权平均值,使用每次运行的时长作为权重。

平均 Est. Achieved 占用率 (Mean Est. Achieved Occupancy:

Est. Achieved Occupancy 的定义与上述概述相同。Mean Est. Achieved Occupancy 是这个内核 name 所有运行的加权平均值,使用每次运行的持续时长作为权重。

跟踪视图:

跟踪视图显示的是一个时间线,表示模型中算子的持续时间,以及是哪个系统执行的操作。这个视图可以帮助你识别高消耗和长执行,是不是由于输入或模型训练引起的。目前,该跟踪视图可显示一个时间线内的 GPU 利用率和 Est. SM Efficiency。

图片

上述例子中,「ProfilerStep5」在线程 28022 期间的 GPU 利用率比「Optimizer.step」期间要高。可以通过放大来查看相关原因。

图片

从上图可知,前者的内核比后者长。后者的内核执行时间太短,导致 GPU 利用率降低。

Est. SM Efficiency: 每个内核都有一个计算出的EST. SM Efficiency,介于 0-100% 之间。例如,下面的内核只有 64 个区块,而这个 GPU 的 SM 为 80,则它的「Est. SM Efficiency」为 64/80,即 0.8。

图片

云存储支持

运行 pip install tensorboard 后,为了通过云供应商读取数据,你可以运行:

torch-tb-profiler[blob] 
torch-tb-profiler[gs] 
torch-tb-profiler[s3]

借助 pip install torch-tb-profiler[blob], pip install torch-tb-profiler[gs],或 pip install torch-tb-profiler[S3] 可以通过云服务商读取数据。

更多信息,请参考: Here

跳转至源代码

将 TensorBoard 和 PyTorch Profiler 直接集成到 Visual Studio Code (VS Code) 中的一大好处,就是能从 Profiler 的 stack trace 直接跳转至源代码(文件和行)。VS Code Python 扩展现已支持 TensorBoard 集成。

只有当 Tensorboard 在 VS Code 中运行时,跳转到源代码才可用。如果profiling with_stack=True,stack trace 就会出现在插件 UI上。点击 PyTorch Profiler 中的 stack trace,VS Code 就会打开相应的文件,并直接跳转到对应代码,以便进行调试。这样就可以根据分析结果和建议,迅速对代码进行优化和修改。

图片

用 Visual Studio Code Plug In UI 跳转至源代码

关于如何优化批尺寸性能,请查看详细教程: Here

PyTorch Profiler 也可以与 PyTorch Lightning 集成,只需用 trainer.profiler=pytorch 来启动 lightning 训练任务即可生成 trace。

详细示例: Here

原文地址: Here