为您的项目提供 GPU · 无 KYC 的加密货币支付 如何租用
简体中文
打开控制台
实用指南 / KERNODECK

对 PyTorch 步骤进行性能分析,弄清时间花在哪里

首先界定要观察的步骤,将加载、传输、计算和更新分开,然后用 torch.profiler 捕获一段具有代表性的短窗口。同时阅读 CPU 时间线和可用的 GPU 活动。Python 的启动时间不等于加速器上执行完成的时间,而一次插桩的跟踪本身也不构成基准测试。

2 分钟阅读 · 开发者指南

打开跟踪之前先选好一个问题

一次跟踪更能回答一个具体问题:计算在等数据吗,某个复制被重复了吗,还是某个小算子被调用得过于频繁?界定你的步骤的输入、输出和边界。对于训练,要明确它是否包含反向传播、优化器更新和读取批次。对于推理,要把模型加载和请求分开。

保留一个你知道其正确性的短场景。记录形状、批次、精度、模型模式、是否编译以及数据来源。简化输入有助于隔离某种行为,但它不再必然代表完整负载。请在记录中说明这一差异。

确定最终单位:每步毫秒数,或每秒处理的样本数。事件之和不能替代经过的时间。比较具有相同读取和传输边界的窗口。

区分 CPU 时间、GPU 工作和等待

CPU 准备并启动操作;GPU 可能稍后执行它们。因此一个 Python 区间可能包含启动、等待,或两者兼有。PyTorch 的 CUDA 文档指出,精确测量必须考虑这种异步性,尤其是通过与该范围相符的同步或事件。

对于有针对性的 GPU 时长测量,CUDA 事件可能适用。对于端到端延迟,要等到该延迟所包含的工作结束,并测量整个请求。不要把这两种单位混在一起。在每个操作之间添加同步可能会消除真实的重叠,并改变你试图理解的那个程序。

在性能分析器中,算子的自身时间和包含子操作的时间也回答不同的问题。先把时间线看清楚,再去加总表格中的各行。同时或在时间上嵌套的活动并不代表互不重叠的已用时间部分。

预留一个启动阶段和一个活动窗口

第一次运行可能包含初始化、加载或编译。确定你的问题针对的是这个启动过程还是一个已经稳定的阶段。当两者对使用都很重要时,请保留这两项观察,而不是把初始成本从一个号称全局的平均值中抹掉。

schedule 函数可以区分等待、收集准备和活动窗口。性能分析器的预热并不能证明你的模型已达到稳定状态。还要检查遇到的形状和缓存状态。对于输入可变的应用程序,在多次迭代后可能会遇到新的路径。

下面给出的教学计划会等待一步、准备一步并捕获两步。四步足以解释其机制,但不足以建立性能分布。在实际测试中,请选择有依据的窗口,并在分析之后在性能分析器之外重复测量。

建议示例:具有清晰边界的四个步骤

以下代码片段未被执行。它假定 model、optimizer、loss_fn、loader 和 device 均已存在,模型已位于 device 上,且加载器至少提供四个 x、y 批次对。它会执行更新:请使用为此准备的实验状态,而不是需要保留权重的会话。

标签将 CPU 读取、传输和训练分开。迭代器在窗口之前创建,这会将其启动的一部分排除在范围之外。文件名特意选择新的,以避免覆盖已有记录。该示例在 GPU 采集不可用时直接拒绝,而不是悄悄将 CPU 记录当作 GPU 分析呈现。

step() 信号会在每一步之后推进调度计划。官方教程描述了迭代与采集之间的这种关联。在 ROCm 平台上,PyTorch 的设备名仍然是 cuda;但加速器采集是否可用取决于构建版本及其工具。请检查结果中实际出现的活动。

短窗口教学采集,未执行
from pathlib import Path
import torch
from torch.profiler import (
    profile, schedule, record_function,
    ProfilerActivity, supported_activities,
)

trace = Path("trace-etape.json")
if trace.exists():
    raise FileExistsError("Choisissez un nouveau nom de trace")
activities = [ProfilerActivity.CPU]
if device.type == "cuda":
    if ProfilerActivity.CUDA not in supported_activities():
        raise RuntimeError("Collecte GPU indisponible dans ce build")
    activities.append(ProfilerActivity.CUDA)
iterator = iter(loader)
model.train()

with profile(
    activities=activities,
    schedule=schedule(wait=1, warmup=1, active=2, repeat=1),
    record_shapes=False, profile_memory=False, with_stack=False,
    on_trace_ready=lambda p: p.export_chrome_trace(str(trace)),
) as prof:
    for _ in range(4):
        with record_function("lecture_batch_cpu"):
            x, y = next(iterator)
        with record_function("transfert"):
            x, y = x.to(device), y.to(device)
        with record_function("entrainement"):
            optimizer.zero_grad(set_to_none=True)
            loss = loss_fn(model(x), y)
            loss.backward()
            optimizer.step()
        prof.step()
print(prof.key_averages().table(
    sort_by="self_cpu_time_total", row_limit=8,
))

将观察转化为可验证的假设

首先查看活动窗口,确认预期的标签是否出现。然后检查各活动之间的空隙、拷贝和重复。lecture_batch_cpu 中的长时间等待指向输入管道;它并不直接衡量存储。频繁拷贝提示需要检查张量的放置位置,但这并不能证明它没有必要。

先提出单一假设,然后提出一项受控修改。例如,如果某个常量在每一步都被重新构建并传输,检查它的生命周期能否在不改变结果的情况下覆盖多个步骤。如果某个算子看起来占主导,先检查它的形状和调用次数,再寻找替代方案。

以下几行是可能的解读,并非来自已执行追踪的实际结论。此处不宣称任何时长或加速。有用的结论是一个后续实验,它可以证实或推翻所提出的原因。

左右滚动表格即可查看所有列。
需在您自己的追踪中验证的教学解读
可能的观察假设后续检查
读取期间 GPU 无活动输入管道跟不上在批次已准备好的情况下执行相同计算
常量的反复拷贝放置位置或生命周期不当移动一次,检查输出
大量小型启动工作碎片化检查分组与整体开销
单个耗时较长的算子形状或算法起决定作用比较同一算子及其输入

限制插桩的开销与信息量

从简短且选项较少的采集开始。仅在某个问题需要时才启用形状、调用栈或内存采集。PyTorch API 明确指出这些信息会增加开销;形状采集甚至可能保留对张量的引用。因此,详细的性能分析可能会改变程序的时长或内存占用。

跟踪记录可能包含算子名称、形状,以及根据所选选项还会包含代码路径。在分享之前请先检查。区域标签应描述步骤,不应包含邮箱、令牌、私有路径或输入内容。请选择适合您环境的跟踪查看器,并将采集置于您的控制之下。

如果预期的 GPU 事件缺失,不要用零填补它们的时间。应说明这些事件未被观测到,并检查采集支持情况。工具中没有事件并不等于没有计算的证据。

在分析器之外验证优化效果

从同一相关状态重新出发,比较修改前后的修正效果。对于训练而言,多一步就会改变权重;连续进行两次快照未必构成等价的比较。保留代码、参数和起点,以便能够解释差异。

接着在无详细采集的情况下测量该场景,使用相同的预热和多次迭代。报告测量范围、原始值及其离散程度。局部改善可能在完整循环中消失,或导致质量下降:两者都应纳入决策。

最后,利用这些观察结果来明确实际所需的资源。您本机的跟踪记录既不能对 Kernodeck 的套餐进行排序,也无法证明租用服务器的宿主处理器或网络情况。GPU 比较需要在相关资源上具备可比的负载、条件和结果。

您的疑问

CPU 耗时最长的算子是否就是最慢的 GPU 算子?

不是。它可能包含启动、主机端处理或等待时间。当采集数据提供时,请查看 GPU 事件及其时间线。按 CPU 时间排序的表格只能回答这一视角的问题。

我应该把表格中所有 CUDA 时间相加吗?

不应以此来自动得出总时长。各活动可能相互重叠,事件也可能嵌套。请定义一个实际耗时窗口,并利用跟踪记录来解释其内容。

两个活动步骤就足以发布性能数据吗?

不能。此处给出的小型调度仅用于演示 API。可用的结果需要具有代表性的时间窗口、多次重复、明确的预热,以及排除详细采集额外开销后的最终测量。

CPU 跟踪记录能诊断 ROCm 吗?

它可以揭示主机端的工作情况,但不能替代 GPU 活动数据。PyTorch 在 ROCm 上也使用 cuda 这一名称;在解读跟踪记录之前,请确认后端、所支持的活动以及实际记录到的活动。