目录

带有 TensorBoard 的 PyTorch Profiler

创建时间: 2021 年 4 月 20 日 |上次更新时间:2024 年 10 月 31 日 |上次验证: Nov 05, 2024

本教程演示如何将 TensorBoard 插件与 PyTorch Profiler 结合使用 来检测模型的性能瓶颈。

警告

TensorBoard 与 PyTorch 分析器的集成现已推出 荒废的。相反,请使用 Perfetto 或 Chrome 跟踪来 查看文件。生成跟踪后, 只需将 拖动到 Perfetto UI 中或可视化您的配置文件。trace.jsontrace.jsonchrome://tracing

介绍

PyTorch 1.8 包括一个更新的分析器 API,该 API 能够 记录 CPU 端操作以及 GPU 端的 CUDA 内核启动。 分析器可以可视化此信息 在 TensorBoard Plugin 中提供性能瓶颈分析。

在本教程中,我们将使用一个简单的 Resnet 模型来演示如何 使用 TensorBoard 插件分析模型性能。

设置

要安装和使用以下命令,请执行以下操作:torchtorchvision

pip install torch torchvision

步骤

  1. 准备数据和模型

  2. 使用 Profiler 记录执行事件

  3. 运行 Profiler

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

  5. 在 Profiler 的帮助下提高性能

  6. 使用其他高级功能分析性能

  7. 其他做法:在 AMD GPU 上分析 PyTorch

1. 准备数据和模型

首先,导入所有必要的库:

import torch
import torch.nn
import torch.optim
import torch.profiler
import torch.utils.data
import torchvision.datasets
import torchvision.models
import torchvision.transforms as T

然后准备输入数据。在本教程中,我们使用 CIFAR10 数据集。 将其转换为所需的格式并用于加载每个批次。DataLoader

transform = T.Compose(
    [T.Resize(224),
     T.ToTensor(),
     T.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
train_set = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(train_set, batch_size=32, shuffle=True)

接下来,创建 Resnet 模型、损失函数和优化器对象。 要在 GPU 上运行,请将 model 和 loss 移动到 GPU 设备。

device = torch.device("cuda:0")
model = torchvision.models.resnet18(weights='IMAGENET1K_V1').cuda(device)
criterion = torch.nn.CrossEntropyLoss().cuda(device)
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
model.train()

定义每批输入数据的训练步骤。

def train(data):
    inputs, labels = data[0].to(device=device), data[1].to(device=device)
    outputs = model(inputs)
    loss = criterion(outputs, labels)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

2. 使用 Profiler 记录执行事件

Profiler 通过上下文管理器启用,并接受多个参数 一些最有用的是:

  • schedule- 将 step (int) 作为单个参数的 callable 并返回要在每个步骤中执行的 Profiler 操作。

    在此示例中,使用 , Profiler 将跳过第一步/迭代, 从第二个开始热身, 记录以下 3 次迭代, 之后,跟踪将变为可用,并调用 on_trace_ready(如果已设置)。 该循环总共重复一次。每个循环在 TensorBoard 插件中称为 “span”。wait=1, warmup=1, active=3, repeat=1

    在步骤中,Profiler 处于禁用状态。 在步骤中,分析器开始跟踪,但结果将被丢弃。 这是为了减少性能分析开销。 性能分析开始时的开销很高,很容易给性能分析结果带来偏差。 在步骤中,Profiler 会工作并记录事件。waitwarmupactive

  • on_trace_ready- 在每个周期结束时调用的 callable; 在此示例中,我们使用为 TensorBoard 生成结果文件。 分析后,结果文件将保存到目录中。 指定此目录作为参数,用于分析 TensorBoard 中的配置文件。torch.profiler.tensorboard_trace_handler./log/resnet18logdir

  • record_shapes- 是否记录运算符输入的形状。

  • profile_memory- 跟踪张量内存分配/释放。注意,对于旧版本的 pytorch 版本为 在 1.10 之前,如果您遇到较长的分析时间,请禁用它或升级到新版本。

  • with_stack- 记录操作的源信息(文件和行号)。 如果 TensorBoard 是在 VS Code 中启动的(参考), 单击堆栈帧将导航到特定的代码行。

with torch.profiler.profile(
        schedule=torch.profiler.schedule(wait=1, warmup=1, active=3, repeat=1),
        on_trace_ready=torch.profiler.tensorboard_trace_handler('./log/resnet18'),
        record_shapes=True,
        profile_memory=True,
        with_stack=True
) as prof:
    for step, batch_data in enumerate(train_loader):
        prof.step()  # Need to call this at each step to notify profiler of steps' boundary.
        if step >= 1 + 1 + 3:
            break
        train(batch_data)

或者,也支持以下非上下文管理器 start/stop。

prof = torch.profiler.profile(
        schedule=torch.profiler.schedule(wait=1, warmup=1, active=3, repeat=1),
        on_trace_ready=torch.profiler.tensorboard_trace_handler('./log/resnet18'),
        record_shapes=True,
        with_stack=True)
prof.start()
for step, batch_data in enumerate(train_loader):
    prof.step()
    if step >= 1 + 1 + 3:
        break
    train(batch_data)
prof.stop()

3. 运行 Profiler

运行上述代码。性能分析结果将保存在 directory../log/resnet18

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

注意

TensorBoard 插件支持已弃用,因此其中一些函数可能不会 像以前一样工作。请看一下替代品 HTA

安装 PyTorch Profiler TensorBoard 插件。

pip install torch_tb_profiler

启动 TensorBoard。

tensorboard --logdir=./log

在 Google Chrome 浏览器或 Microsoft Edge 浏览器(不支持 Safari)中打开 TensorBoard 配置文件 URL。

http://localhost:6006/#pytorch_profiler

您可以看到 Profiler 插件页面,如下所示。

  • 概述

../_static/img/profiler_overview1.png

概述显示了模型性能的高级摘要。

“GPU 摘要”面板显示 GPU 配置、GPU 使用情况和 Tensor Core 使用情况。 在此示例中,GPU 利用率较低。 这些指标的详细信息在这里。

“Step Time Breakdown” 显示不同执行类别中每个步骤所花费的时间分布。 在此示例中,您可以看到开销很大。DataLoader

底部的 “Performance Recommendation” 使用分析数据 自动突出显示可能的瓶颈, 并为您提供可操作的优化建议。

您可以在左侧的 “Views” 下拉列表中更改视图页面。

  • 操作员视图

操作员视图显示每个 PyTorch 操作员的性能 ,该操作将在主机或设备上执行。

../_static/img/profiler_operator_view.png

“Self” 持续时间不包括其子运算符的时间。 “Total” 持续时间包括其子运算符的时间。

  • 查看调用堆栈

点击运算符的 ,将显示名称相同但调用堆栈不同的运算符。 然后点击该子表中的 a,将显示调用堆栈帧。View CallstackView Callstack

../_static/img/profiler_callstack.png

如果 TensorBoard 在 VS Code 中启动 (启动指南)、 单击调用堆栈帧将导航到特定的代码行。

../_static/img/profiler_vscode.png
  • 内核视图

GPU 内核视图显示所有内核在 GPU 上花费的时间。

../_static/img/profiler_kernel_view.png

使用的 Tensor 核心: 此内核是否使用 Tensor Core。

每 SM 的平均区间数: 每个 SM 的块数 = 此内核的块数 / 此 GPU 的 SM 编号。 如果此数字小于 1,则表示 GPU 多处理器未得到充分利用。 “Mean Blocks per SM” 是使用此内核名称的所有运行的加权平均值,使用每次运行的持续时间作为权重。

平均估计入住率: Est. Achieved Occupancy 在此列的工具提示中定义。 对于大多数情况,例如内存带宽有限内核,越高越好。 “Mean Est. Achieved Occupancy” 是该内核名称的所有运行的加权平均值, 使用每次运行的持续时间作为权重。

  • 跟踪视图

trace (跟踪) 视图显示分析的运算符和 GPU 内核的时间线。 您可以选择它以查看详细信息,如下所示。

../_static/img/profiler_trace_view1.png

您可以借助右侧工具栏移动图表并放大/缩小。 键盘还可用于在时间轴内缩放和移动。 'w' 和 's' 键以鼠标为中心进行放大, “A”和“D”键可左右移动时间轴。 您可以多次点击这些键,直到看到可读的表示形式。

如果 backward 运算符的 “Incoming Flow” 字段的值为 “forward correspond to backward”, 您可以单击文本以获取其 Launching forward 运算符。

../_static/img/profiler_trace_view_fwd_bwd.png

在此示例中,我们可以看到前缀为 的事件花费了大量时间。 在此期间的大部分时间里,GPU 都是空闲的。 因为这个函数是在主机端加载数据和转换数据, 在此期间,GPU 资源被浪费。enumerate(DataLoader)

5. 借助 Profiler 提高性能

在“Overview(概述)”页面的底部,“Performance Recommendation(性能建议)”中的建议暗示瓶颈是 。 默认情况下,PyTorch 使用单个进程。 用户可以通过设置参数 来启用多进程数据加载。以下是更多详细信息。DataLoaderDataLoadernum_workers

在此示例中,我们遵循 “Performance Recommendation” 并设置如下: 传递一个不同的名称,例如 to ,然后再次运行它。num_workers./log/resnet18_4workerstensorboard_trace_handler

train_loader = torch.utils.data.DataLoader(train_set, batch_size=32, shuffle=True, num_workers=4)

然后,让我们在左侧的 “Runs” 下拉列表中选择最近分析的运行。

../_static/img/profiler_overview2.png

从上面的视图可以看出,与上一次运行的 132ms 相比,单步时间减少了大约 76ms, 以及主要贡献的时间减少。DataLoader

../_static/img/profiler_trace_view2.png

从上面的视图可以看出,的运行时间减少了, GPU 利用率提高。enumerate(DataLoader)

6. 使用其他高级功能分析性能

  • 内存视图

要分析内存,必须在 的参数中设置为 。profile_memoryTruetorch.profiler.profile

您可以使用 Azure 上的现有示例进行试用

pip install azure-storage-blob
tensorboard --logdir=https://torchtbprofiler.blob.core.windows.net/torchtbprofiler/demo/memory_demo_1_10

分析器在性能分析期间记录所有内存分配/释放事件和分配器的内部状态。 内存视图由三个组件组成,如下所示。

../_static/img/profiler_memory_view.png

这些组件分别是 Memory Curve Graph、Memory Events Table 和 Memory Statistics Table,从上到下。

可以在 “Device” 选择框中选择内存类型。 例如,“GPU0” 表示下表仅显示每个运算符在 GPU 0 上的内存使用情况,不包括 CPU 或其他 GPU。

内存曲线显示内存消耗的趋势。“已分配” 曲线显示实际 正在使用,例如 Tensors。在 PyTorch 中,CUDA 分配器和其他一些分配器中使用了缓存机制。这 “Reserved” 曲线显示分配器保留的总内存。您可以在图表上单击鼠标左键并拖动 要在所需范围内选择事件:

../_static/img/profiler_memory_curve_selecting.png

选择后,这三个组件将在限制的时间范围内进行更新,以便您获得更多 信息。通过重复此过程,您可以放大到非常精细的细节。右键单击图表 会将图表重置为初始状态。

../_static/img/profiler_memory_curve_single.png

在 memory events 表中,allocation 和 release 事件成对到一个条目中。“operator” 列显示 导致分配的直接 ATen 运算符。请注意,在 PyTorch 中,ATen 运算符通常用于分配内存。例如,按照后跟 .仅显示操作员名称,因为帮助不大。它将如此特殊情况所示。“分配时间”、“释放时间”和“持续时间” 如果事件发生在时间范围之外,则可能会缺少列的数据。aten::emptyaten::onesaten::emptyaten::fill_aten::emptyaten::ones (aten::empty)

在内存统计信息表中,“Size Increase” 列将所有分配大小相加,并减去所有内存 release size,即该算子之后内存使用量的净增加量。“自身大小增加”列为 类似于 “Size Increase”,但它不计算子运算符的分配。关于 ATen 运维的 implementation detail,则某些运算符可能会调用其他运算符,因此内存分配可以发生在 call 堆栈。也就是说,“Self Size Increase” 仅计算当前调用堆栈级别的内存使用量增加。 最后,“Allocation Size” 列汇总了所有分配,而不考虑内存释放。

  • 分布式视图

该插件现在支持以 NCCL/GLOO 作为后端分析 DDP 的分布式视图。

可以使用 Azure 上的现有示例进行尝试:

pip install azure-storage-blob
tensorboard --logdir=https://torchtbprofiler.blob.core.windows.net/torchtbprofiler/demo/distributed_bert
../_static/img/profiler_distributed_view.png

“计算/通信概述”显示了计算/通信比率及其重叠程度。 从这个视图中,用户可以找出 worker 之间的负载均衡问题。 例如,如果一个 worker 的计算 + 重叠时间比其他 worker 大得多, 可能存在负载均衡问题,或者此 worker 可能是落后者。

“同步/通信概述”显示了通信的效率。 “数据传输时间”是指实际交换数据的时间。 “同步时间” 是等待并与其他 worker 同步的时间。

如果一个 worker 的 “同步时间” 比其他 worker 的 “同步时间” 短得多, 这个 worker 可能是一个落后者,可能比其他 worker 有更多的计算工作负载。

“Communication Operations Stats” 汇总了每个 worker 中所有 communication operations 的详细统计数据。

7. 其他实践:在 AMD GPU 上分析 PyTorch

AMD ROCm 平台是专为 GPU 计算而设计的开源软件堆栈,由驱动程序、开发工具和 API 组成。 我们可以在 AMD GPU 上运行上述步骤。在本节中,我们将使用 Docker 安装 ROCm 基础开发映像 在安装 PyTorch 之前。

例如,让我们创建一个名为 的目录,并将步骤 1 中的代码保存为此目录中的代码。profiler_tutorialtest_cifar10.py

mkdir ~/profiler_tutorial
cd profiler_tutorial
vi test_cifar10.py

在撰写本文时,ROCm 平台上的 PyTorch 的 Stable() Linux 版本是 ROCm 5.62.1.1

  • Docker Hub 获取具有正确用户空间 ROCm 版本的基础 Docker 映像。

是的。rocm/dev-ubuntu-20.04:5.6

  • 启动 ROCm 基础 Docker 容器:

docker run -it --network=host --device=/dev/kfd --device=/dev/dri --group-add=video --ipc=host --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --shm-size 8G -v ~/profiler_tutorial:/profiler_tutorial rocm/dev-ubuntu-20.04:5.6
  • 在容器内,安装安装 wheels 包所需的任何依赖项。

sudo apt update
sudo apt install libjpeg-dev python3-dev -y
pip3 install wheel setuptools
sudo apt install python-is-python3
  • 安装轮子:

pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/rocm5.6
  • 安装 ,然后运行 Python 文件 :torch_tb_profilertest_cifar10.py

pip install torch_tb_profiler
cd /profiler_tutorial
python test_cifar10.py

现在,我们有了在 TensorBoard 中查看所需的所有数据:

tensorboard --logdir=./log

选择不同的视图,如步骤 4 中所述。例如,下面是 Operator 视图:

../_static/img/profiler_rocm_tensorboard_operartor_view.png

在编写此部分时,Trace (跟踪) 视图不起作用,并且不显示任何内容。您可以通过在 Chrome 浏览器中输入来解决此问题。chrome://tracing

  • 将目录下的文件复制到 Windows。trace.json~/profiler_tutorial/log/resnet18

如果文件位于远程位置,则可能需要使用 复制文件。scp

  • 单击 Load (加载) 按钮,从浏览器中的页面加载跟踪 JSON 文件。chrome://tracing

../_static/img/profiler_rocm_chrome_trace_view.png

如前所述,您可以移动图形并放大和缩小。 您还可以使用键盘在时间轴内缩放和移动。 和 键以鼠标为中心进行放大, 和 和 键可左右移动时间轴。 您可以多次点击这些键,直到看到可读的表示形式。wsad

文档

访问 PyTorch 的全面开发人员文档

查看文档

教程

获取面向初学者和高级开发人员的深入教程

查看教程

资源

查找开发资源并解答您的问题

查看资源