## 示例 - base-profiler.py - profiler-recipe.py - tensorboard-profiler.py ## PyTorch 分析器 ``` PyTorch 分析器是通过上下文管理器启用的,它接受许多参数,其中一些最有用的是: activities - 要分析的活动列表: ProfilerActivity.CPU - PyTorch 运算符、TorchScript 函数和用户定义的代码标签; ProfilerActivity.CUDA - 设备上的 CUDA 内核; ProfilerActivity.XPU - 设备上的 XPU 内核; record_shapes - 是否记录运算符输入的形状; profile_memory - 是否报告模型的 Tensor 消耗的内存量; ``` ## 使用 Profiler 记录执行事件 ``` 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) ``` 分析器通过上下文管理器启用,并接受多个参数,其中一些最有用的参数是: schedule - 可调用,它将步骤 (int) 作为单个参数,并返回在每个步骤中要执行的 Profiler 作。 在此示例中,Profiler wait=1, warmup=1, active=3, repeat=1 将跳过第一步/迭代,开始预热第二步,记录以下三次迭代,之后跟踪将变为可用,并调用 on_trace_ready(如果设置)。该循环总共重复一次。 每个循环在 TensorBoard 插件中称为 “span”。 在等待步骤中,分析器处于禁用状态。 在预热步骤中,分析器开始跟踪,但结果将被丢弃。这是为了减少性能分析开销。性 能分析开始时的开销很高,很容易给性能分析结果带来偏差。 在active步骤期间,分析器会工作并记录事件。 on_trace_ready - 在每个周期结束时调用的可调用对象; 在此示例中, torch.profiler.tensorboard_trace_handler ,我们使用为 TensorBoard 生成结果文件。分析后,结果文件将保存到 ./log/resnet18 目录中。将此目录指定为 logdir 参数,用于分析 TensorBoard 中的配置文件。 record_shapes — 是否记录运算符输入的形状。 profile_memory - 跟踪张量内存分配/释放。注意,对于旧版本的 pytorch 版本低于 1.10,如果性能分析时间过长,请禁用它或升级到新版本。 with_stack - 记录ops的源信息(文件和行号)。如果在 VS Code ( 参考 ) 中启动 TensorBoard,则单击堆栈帧将导航到特定代码行。 也支持以下非上下文管理器 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() ``` ## 跟踪长时间运行的作业 PyTorch 分析器提供了一个额外的 API 来处理长时间运行的作业(例如训练循环)。 跟踪所有执行可能会很慢,并导致跟踪文件非常大。为避免这种情况,请使用可选参数: - schedule - 指定一个函数,该函数将整数参数(步骤编号)作为输入并返回 Profiler 的action,使用此参数的最佳方法是使用 torch.profiler.schedule 辅助函数,该函数可以为您生成schedule。 - on_trace_ready - 指定一个函数,该函数将对分析器的引用作为输入,并在每次新跟踪准备就绪时由分析器调用。 torch.profiler.schedule 辅助函数: ``` from torch.profiler import schedule my_schedule = schedule( skip_first=10, wait=5, warmup=1, active=3, repeat=2) ``` Profiler 假定长时间运行的作业由步骤组成,这些步骤从零开始编号。 上面的示例为性能分析器定义了以下作序列: 参数 skip_first 告诉分析器它应该忽略前 10 个步骤(skip_first 的默认值为零); 在前 skip_first 个步骤之后,分析器开始执行分析器循环; 每个周期包括三个阶段: Idling (wait=5 steps),在此阶段 Profiler 未激活; 预热(Warmup=1 steps),在此阶段,Profiler 开始跟踪,但结果被丢弃; 此阶段用于丢弃 Profiler 在跟踪开始时获得的样本,因为它们通常会因额外的开销而产生偏差; active 跟踪 ( active = 3 steps),在此阶段,Profiler 跟踪并记录数据; 可选的 repeat 参数指定循环数的上限。默认情况下(零值),只要作业运行,分析器就会执行循环。 因此,在上面的示例中,profiler 将跳过前 15 个步骤,将下一步用于热身,active记录接下来的 3 个步骤,再跳过 5 个步骤,将下一步用于热身,主动记录另外 3 个步骤。由于指定了 repeat=2 参数值,因此性能分析器将在前两个周期后停止记录。 ``` sort_by_keyword = "self_" + device + "_time_total" def trace_handler(p): output = p.key_averages().table(sort_by=sort_by_keyword, row_limit=10) print(output) p.export_chrome_trace("/tmp/trace_" + str(p.step_num) + ".json") with profile( activities=activities, schedule=torch.profiler.schedule( wait=1, warmup=1, active=2), on_trace_ready=trace_handler ) as p: for idx in range(8): model(inputs) p.step() ```