内容导读
PyTorch Profiler v1.9 现已发布,本版本旨在为用户提供全新工具,让用户无论是在一台还是多台机器上,都可以更轻松地诊断和修复机器学习性能问题。
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 传送门: https://pytorch.org/tutorials/intermediate/tensorboard_profiler_tutorial.html
汉化版 Colab 传送门:
https://openbayes.com/console/open-tutorials/containers/TA5H0qvm5rw
Colab 内容一览:
- 准备数据和模型
- 使用 Profiler 记录执行事件
- 运行 Profiler
- 使用 TensorBoard 查看结果并分析模型性能
- 借助 Profiler 提高性能
- 使用其他高级功能分析性能
开始使用 PyTorch Profiling 工具
首先:
$ pip install torch-tb-profiler
代码语言:javascript复制import torch.profiler as profiler
With profiler.profile(XXXX)
备注:关于 CUDA 和 CPU 的分析,详见:
https://github.com/pytorch/kineto/blob/master/tb_plugin/examples/resnet50_profiler_api.py
代码语言:javascript复制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 相关链接:
https://en.wikipedia.org/wiki/Load_balancing_(computing)
情景 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 来生成以下内存数据。
相关链接:
https://github.com/pytorch/kineto/blob/master/tb_plugin/examples/resnet50_profiler_api.py#L39
代码语言:javascript复制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 文档:
https://forums.developer.nvidia.com/t/nvprof-question-about-the-sm-efficiency-metric/72640
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 文档:
https://docs.nvidia.com/gameworks/content/developertools/desktop/analysis/report/cudaexperiments/kernellevel/achievedoccupancy.htm
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 后,为了通过云供应商读取数据,你可以运行:
代码语言:javascript复制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] 可以通过云服务商读取数据。
更多信息,请参考:
https://github.com/pytorch/kineto/tree/main/tb_plugin
跳转至源代码
将 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 跳转至源代码
关于如何优化批尺寸性能,请查看详细教程:
https://opendatascience.com/optimizing-pytorch-performance-batch-size-with-pytorch-profiler/
PyTorch Profiler 也可以与 PyTorch Lightning 集成,只需用 trainer.profiler=pytorch 来启动 lightning 训练任务即可生成 trace。
详细示例:
https://github.com/PyTorchLightning/pytorch-lightning/blob/master/pl_examples/basic_examples/profiler_example.py
原文地址:
https://pytorch.org/blog/pytorch-profiler-1.9-released/
—— 完 ——