pytorch profiler需正确配置才能精准定位训练瓶颈:必须启用cpu/cuda双活动、合理设置schedule(wait=1,warmup=1,active=3)、开启record_shapes和profile_memory;record_function要包裹实际执行逻辑而非仅模型调用;分析时优先看self cpu time total和gpu kernel utilization曲线,结合with_stack排查协作断点。

PyTorch Profiler 能直接告诉你训练慢在哪——不是靠猜,是看 conv2d 占了 38% 的 CPU 时间,还是 data_loader 在等 I/O,或是 GPU 因 torch.cuda.synchronize() 频繁空转。关键在配置对、分析准、不干扰真实训练节奏。
怎么配 profile 才不白跑?
默认参数几乎没用:不设 schedule 就只录第一个 batch,record_shapes=False 会漏掉张量尺寸异常导致的隐式拷贝,profile_memory=False 则看不到显存峰值是否卡在某个 layer 输出上。
-
activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA]必须同时开,否则看不到数据搬运(如copy_to_device)这类跨设备瓶颈 -
schedule=torch.profiler.schedule(wait=1, warmup=1, active=3)是工业级推荐组合:跳过首 step(避免冷启动抖动),第 2 步预热(让 CUDA kernel 编译完成),只分析紧接其后的 3 步——既降低开销,又避开初始化噪声 -
record_shapes=True和profile_memory=True建议始终开启;with_stack=True在查自定义模块或封装层时才启用(会明显拖慢 profiler)
训练循环里怎么插 record_function?
不加 record_function,Profiler 只能按算子名归类(比如一堆 add、mul),根本分不清哪个是 loss 计算、哪个是梯度裁剪。加了它,才能把耗时精准绑定到你代码里的逻辑段。
- 必须包住实际执行逻辑,而不是仅包模型调用:
with record_function("forward"):下面要跟model(inputs),不能只写model -
backward段要包含loss.backward()和optimizer.step()全流程,否则梯度更新耗时会被拆散到不同算子中 - 别在
data_loader迭代外加record_function,否则 DataLoader 的__next__耗时会混进 "forward" 统计里
怎么看输出才能快速定位真瓶颈?
直接调 prof.key_averages().table(sort_by="cpu_time_total", row_limit=10) 容易被表头带偏——比如看到 aten::copy_ 排第一,就去改 tensor.clone(),其实它只是表象,根因可能是输入 tensor 在 CPU 上、而模型在 GPU 上,导致每次 forward 都强制同步拷贝。
- 优先看
Self CPU time total(非累计),排除被子调用撑高的父项;若某算子# Calls异常高(比如 1000+ 次index_select),大概率是 for 循环写在了 GPU 上 - 打开 TensorBoard 日志后,重点看
GPU Kernel Utilization曲线:如果长期低于 60%,说明 GPU 在等 CPU(查 data loader 或 pre-processing);如果曲线锯齿状剧烈波动,说明 kernel 启动太碎(查是否用了 too small batch 或 dynamic shape) - 内存视图里出现
cudaMalloc高频小块分配,往往意味着中间变量没复用(如反复创建新 tensor 而非.zero_()复用)
真正卡住训练的,往往不是单个算子慢,而是 CPU-GPU 协作断点——比如 pin_memory=True 没配、num_workers 设为 0、或者 torch.compile 和 profiler 同时启用导致 trace 冲突。这些细节不会出现在 top-10 表里,得靠 with_stack=True 配合日志路径反查。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











