新闻详情

新闻详情

首页 / 资讯中心 / 详情

昇腾NPU性能调优:torch_npu profiler与kernel_details实战解析

发布时间:2026/9/26 23:13:05来源:尧图网络
昇腾NPU性能调优:torch_npu profiler与kernel_details实战解析
1. 从一次训练慢如蜗牛的排查说起模型代码在 GPU 上跑得好好的迁到昇腾 NPU 上之后 loss 曲线倒是对得上但每个 step 的耗时直接翻了一倍多。这种场景我遇到过不止一次很多人的第一反应是硬件不行或者驱动有问题但真正的原因往往藏在算子层面——某个看起来不起眼的 kernel 在 NPU 上走了低效实现或者 host 与 device 之间的拷贝次数远超预期。要定位这类问题靠print打时间戳是没用的必须上 profiler。torch_npu提供的 profiler 接口本质上是对昇腾 CANN 侧 profiling 能力的一层 Python 封装。它能把训练过程中每个算子的执行时间、内存占用、通信耗时、甚至 AI Core 的利用率和带宽数据全部采集下来最终落盘成若干 JSON 和 CSV 文件。其中kernel_details.csv是最核心的一份产物它记录了每一次 kernel 调用的详细信息算子名、执行时长、加速器核心类型、输入输出 shape、以及各种硬件指标。读懂这份文件基本就掌握了整个训练任务的性能画像。这篇文章面向的是已经在昇腾上跑通训练、但被性能问题卡住的工程师。不管你是用 PyTorch 原生训练循环还是套了 Megatron、DeepSpeed 这类框架profiler 的采集和解读逻辑是通用的。我会从采集配置讲起把kernel_details里每一列的含义拆开揉碎再结合几个真实的性能瓶颈案例说明怎么从数据反推到代码层面的优化动作。中间会穿插一些我踩过的坑比如采集时把显存打爆、时间线对不齐、算子名被截断之类的问题。2. torch_npu profiler 的采集链路与配置细节2.1 profiler 在昇腾软件栈中的位置昇腾的软件栈从上到下大致是PyTorch 框架层 →torch_npu适配层 → CANNCompute Architecture for Neural Networks→ NPU 驱动 → 硬件。profiler 的采集点分布在两个层面一是 PyTorch 侧的算子调度信息由torch_npu.profiler通过 hook 机制捕获二是 CANN 侧的底层执行信息包括 AI Core、AI CPU、DVPP 等不同计算单元的耗时这部分由 CANN 的 profiling 模块直接产出。两层数据最终会在torch_npu.profiler的analyse阶段被关联起来形成一份完整的 trace。理解这个分层很重要因为后面解读kernel_details时你会看到有些算子的耗时是 PyTorch 层面的调度时间有些是真实的硬件执行时间两者不能混为一谈。2.2 最小可用的采集代码先给一个能直接跑的采集模板基于 PyTorch 的训练循环import torch import torch_npu import torch_npu.profiler as profiler # 初始化 NPU 设备 device torch.device(npu:0) torch.npu.set_device(device) # 构造实验配置 experimental_config profiler._ExperimentalConfig( profiler_levelprofiler.ProfilerLevel.Level1, aic_metricsprofiler.AiCMetrics.PipeUtilization, l2_cacheFalse, op_attrFalse, data_simplificationFalse, ) # 启动 profiler with profiler.profile( activities[ profiler.ProfilerActivity.CPU, profiler.ProfilerActivity.NPU, ], scheduleprofiler.schedule( wait1, warmup1, active3, repeat1, skip_first2, ), on_trace_readyprofiler.tensorboard_trace_handler(./prof_result), experimental_configexperimental_config, ) as prof: for step, data in enumerate(train_loader): train_one_step(model, data) prof.step()这段代码里有几个关键参数需要展开说。profiler_level控制采集粒度。Level0只采集最基础的算子耗时开销最小Level1会额外采集 AI Core 的利用率、带宽等指标是日常排查的推荐档位Level2最详细但开销也最大通常只在定位特定算子问题时才用。我一般先用Level1跑一遍看整体画像发现可疑算子再针对性上Level2。aic_metrics决定采集哪些 AI Core 指标。PipeUtilization是最常用的它会记录 MAC乘加单元、Vector、Scalar 等各个流水线的利用率。如果你怀疑是内存带宽瓶颈可以换成MemoryBandwidth怀疑是缓存命中率问题用L2Cache。注意这个参数只在Level1及以上生效。schedule里的wait、warmup、active、repeat、skip_first这五个参数控制采集节奏。skip_first2表示前两个 step 不采集这是为了跳过初始化阶段wait1表示等待一个 step 再开始 warmupwarmup1是预热让 profiler 自身稳定下来active3是真正采集三个 step 的数据。这样设计的原因是 profiler 本身有开销如果从第一个 step 就开始采数据会被初始化操作污染。2.3 采集开销与显存风险profiler 采集不是零成本的。Level1下训练速度通常会下降 10% 到 30%Level2可能下降 50% 以上。更麻烦的是显存占用——profiler 会把采集到的数据缓存在 device 侧如果active步数太多或者模型本身显存吃紧很容易 OOM。我踩过一次坑在一个 7B 模型上设了active10结果跑到第 6 个 step 就爆显存了。后来改成active3并且把data_simplificationTrue打开问题解决。data_simplification会简化部分数据减少落盘体积和内存占用代价是丢失一些细节字段。日常排查够用只有在追查特定算子属性时才需要关掉。另一个经验是采集时尽量用单独的进程不要和训练主进程混在一起跑太久。如果只是定位问题采 3 到 5 个 step 足够了没必要全程开着 profiler。3. kernel_details.csv 的字段逐列拆解采集完成后prof_result目录下会生成若干文件其中kernel_details.csv是分析的核心。这份 CSV 的列比较多第一次看容易懵。我按重要程度分组来讲。3.1 基础标识列列名含义使用场景Name算子名称通常是 PyTorch 算子名加 NPU 实现后缀定位具体算子Type算子类型如AI_CORE、AI_CPU、MIX_AIC判断执行单元Accelerator Core实际执行的加速核心区分 AI Core 与 AI CPUStart Time(us)算子开始时间单位微秒时间线对齐Duration(us)算子执行时长单位微秒性能排序Name这一列有个坑昇腾的算子名经常很长比如aclnnIndexPutImpl_IndexPut_ND_...在 CSV 里可能被截断。如果你发现名字对不上去同目录下的kernel_details.json里找完整名。另外PyTorch 原生算子名和昇腾实现名之间有一层映射比如aten::add在 NPU 上可能显示为Add或aclnnAdd需要对照 CANN 的算子文档确认。Type列区分了算子的执行单元。AI_CORE是跑在 AI Core 上的这是 NPU 的主力计算单元AI_CPU是跑在 AI CPU 上的通常是一些控制流、shape 计算、或者 AI Core 不支持的算子MIX_AIC表示混合执行。如果一个本该在 AI Core 上跑的算子跑到了 AI CPU 上那基本就是性能瓶颈——AI CPU 的算力比 AI Core 低一到两个数量级。3.2 硬件指标列这部分是Level1及以上才有的也是最有价值的数据。aic_mac_ratio表示 MAC 单元的利用率。MAC 是矩阵乘加的核心单元这个值越高说明计算越密集。如果某个矩阵乘算子的aic_mac_ratio很低说明它在等数据可能是内存带宽瓶颈。aic_mte1_ratio和aic_mte2_ratio分别表示 MTE1L1 到 L0 的搬运和 MTE2外部内存到 L1 的搬运的利用率。这两个值高说明数据搬运频繁可能是算子切分不合理导致反复搬数据。aic_vec_ratio是 Vector 单元的利用率主要影响 element-wise 类算子。aic_scalar_ratio是 Scalar 单元的利用率这个值高通常意味着算子里有大量标量计算是低效的信号。aic_fixpipe_ratio是 Fixpipe 单元的利用率负责把计算结果从 L0C 搬回外部内存。这几个指标加起来能勾勒出一个算子的执行画像。理想情况下计算密集型算子的aic_mac_ratio应该接近 1其他搬运类指标较低如果反过来搬运指标高而 MAC 低那就是典型的搬运瓶颈。3.3 时间与内存列Duration(us)是算子执行时长但要注意这是 device 侧的时间不包括 host 侧的调度开销。如果你发现所有算子时长加起来远小于 step 总时间那说明瓶颈在 host 侧可能是 Python 调度慢或者算子下发有延迟。Wait Time(us)表示算子等待执行的时间。这个值高说明算子之间有依赖等待可能是流水线没排好。内存相关的列包括Input Shapes、Output Shapes、Input Data Types等。这些列在排查 shape 相关问题时很有用比如某个算子因为 shape 不对齐导致走了低效分支。4. 从数据到结论三类典型瓶颈的识别方法4.1 算子落错执行单元这是最常见也最容易修的问题。判断方法很简单在kernel_details.csv里按Type列筛选把所有AI_CPU类型的算子挑出来按Duration(us)降序排列。如果排在前面的算子耗时占比很高那就是问题所在。我遇到过一个案例一个自定义的IndexPut操作在 NPU 上跑到了 AI CPU 上单次耗时 800 微秒而整个 step 才 12 毫秒。查下来是因为索引 tensor 的 dtype 是 int64而昇腾的 AI Core 对 int64 索引支持不好自动 fallback 到了 AI CPU。改成 int32 之后这个算子回到了 AI Core耗时降到 60 微秒。修复这类问题的思路有三条一是改 dtype尽量用 int32 或 float16二是换等价算子比如用scatter替代index_put三是如果实在没有 AI Core 实现考虑把这个操作挪到 host 侧用 CPU 做避免占用 device 时间。4.2 搬运瓶颈MTE 指标异常当aic_mte1_ratio或aic_mte2_ratio持续高于 0.8而aic_mac_ratio低于 0.3 时基本可以判定是搬运瓶颈。这种情况常见于大 shape 的 element-wise 操作或者卷积的 im2col 阶段。一个真实的例子某模型里的LayerNorm算子aic_mte2_ratio达到 0.92aic_mac_ratio只有 0.05。原因是 LayerNorm 的输入 tensor 在内存里不是连续的导致 MTE2 搬运时要做 gather 操作效率极低。解决办法是在 LayerNorm 之前加一个contiguous()虽然多了一次拷贝但整体耗时反而下降了 40%。搬运瓶颈的通用优化手段包括确保输入 tensor 内存连续、调整算子切分策略让数据复用率更高、把多个小算子融合成一个大算子减少搬运次数。4.3 流水线空泡Wait Time 过高如果Wait Time(us)在多个算子上都很高说明算子之间存在严重的依赖等待。这通常不是单个算子的问题而是整个计算图调度的问题。常见原因有两个一是算子之间的依赖链太长没有足够的并行度二是 host 侧下发算子的速度跟不上 device 侧执行的速度导致 device 空等。判断是哪种原因可以看Start Time(us)的分布。如果算子开始时间是密集连续的但每个算子前面都有一段 wait那是依赖问题如果算子开始时间之间有明显的空隙那是下发问题。依赖问题可以通过调整计算图结构来缓解比如把一些独立的计算提前增加并行度。下发问题则需要检查 Python 侧是否有同步操作比如.item()、.cpu()这类会强制同步的调用。5. 几个容易踩的坑与排查技巧5.1 时间线对不齐profiler 采集的 CPU 时间和 NPU 时间基准不同直接对比会发现有偏移。torch_npu.profiler在 analyse 阶段会做一次对齐但对齐精度有限。如果你需要精确对齐建议在采集时加一个torch.npu.synchronize()作为时间锚点然后在分析时以这个锚点为基准做偏移校正。5.2 算子名被截断或混淆前面提到过CSV 里的算子名可能被截断。另外PyTorch 的算子名和昇腾的算子名不是一一对应的有些 PyTorch 算子会被拆成多个昇腾算子有些则会被融合。排查时不要只看名字要结合Input Shapes和Output Shapes来确认。5.3 采集本身影响结果profiler 采集会引入额外开销导致采集到的耗时比实际运行时偏高。这个偏差在Level1下大约是 10% 到 20%Level2下可能到 50%。所以不要用 profiler 的数据去绝对值对比而应该看相对占比——哪个算子占总时间的比例最高哪个就是优化重点。5.4 多次采集结果不一致NPU 的执行时间受温度、频率、其他进程干扰等因素影响多次采集的结果可能有波动。建议至少采集三次取中位数或者看趋势不要凭单次数据下结论。6. 把 profiler 数据用起来的几个实践采集和分析只是第一步真正有价值的是把数据转化成优化动作。我自己的习惯是每次性能优化前先跑一次 profiler建立基线优化后再跑一次对比kernel_details.csv里 top 10 算子的耗时变化。如果优化没有体现在 top 算子上那说明优化方向可能错了。另外kernel_details.csv可以导入到 Excel 或者用 pandas 做进一步分析。我常用的一段分析代码import pandas as pd df pd.read_csv(kernel_details.csv) # 按总耗时排序 df[total_time] df[Duration(us)] top_ops df.groupby(Name)[total_time].sum().sort_values(ascendingFalse).head(20) print(top_ops) # 筛选 AI CPU 算子 ai_cpu_ops df[df[Type] AI_CPU] print(ai_cpu_ops[[Name, Duration(us)]].sort_values(Duration(us), ascendingFalse))这段代码能快速定位到耗时最高的算子和所有跑在 AI CPU 上的算子是我每次分析的起点。最后说一个心态上的经验性能优化不是一次性的工作而是一个持续迭代的过程。profiler 给的是数据数据背后的原因需要结合代码和业务逻辑去判断。不要迷信某个指标也不要指望一次优化解决所有问题。每次改一个变量采集一次对比一次慢慢就能摸清模型的性能特征。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

营销型网站郑州新手入门 2026/9/27 0:09:40

营销型网站郑州新手入门

郑州搞营销型网站别踩坑,一文搞懂从流量到转化的实操 改个需求建站公司拖一周,这是郑州很多做企业老板们的噩梦。明明合同里写好了,结果一个简单的Banner图修改,对方客服踢皮球,开发排期遥遥无期,最后上线时间一拖再拖,客户流失了,钱倒是花出去…

阅读更多 →
从自研到生产落地:分布式任务调度引擎的架构设计与稳定性实践 2026/9/27 0:09:33

从自研到生产落地:分布式任务调度引擎的架构设计与稳定性实践

我们团队的后端技术栈里,一直流传着一个内部代号叫"ax"的调度引擎。说起来有点尴尬,一开始它只是我在某个版本迭代里临时写的任务调度模块,后来一步步演变成了承载全公司定时任务、异步批处理、甚至跨系统数据对账的"ax调度&q…

阅读更多 →
拒绝丑模板?网页美工设计脚本图解步骤全解析 2026/9/27 0:09:33

拒绝丑模板?网页美工设计脚本图解步骤全解析

拒绝丑模板?网页美工设计脚本图解步骤全解析 做企业官网的朋友,是不是也被那种千篇一律的模板网站折磨疯了?客户一眼看过去,觉得这公司没实力,或者干脆就是皮包公司,连个像样的首页都没有。更头疼的是,你明明想改个配色、调个布局,结果发现后台根本不…

阅读更多 →
ax调度是什么?异步调度原理、机制与实战排错全解析 2026/9/27 0:09:33

ax调度是什么?异步调度原理、机制与实战排错全解析

“ax调度”这四个字母第一次出现在我时间线的时候,我也愣了一下。点进去看了两段才反应过来,这就是程序员嘴里那个读起来像“ax”的异步调度——async 调度。做后端的朋友应该都遇到过这种场景:一堆任务排队等执行,系统像节假日的…

阅读更多 →
AX架构:基于Kubernetes与gRPC的AI智能体调度底座 2026/9/27 0:09:26

AX架构:基于Kubernetes与gRPC的AI智能体调度底座

1. 项目概述:AX不是缩写,而是一个正在成型的基础设施新范式“AX”这个词最近在技术社区里出现得越来越频繁,但它既不是某个老牌开源项目的代号,也不是某家大厂新发布的SaaS产品名称。它背后指向的,是一类正在快速收敛、…

阅读更多 →
C#实现CAN DBC解析与生成:从报文解析到上位机开发 2026/9/27 0:09:26

C#实现CAN DBC解析与生成:从报文解析到上位机开发

简介:这是一款面向汽车电子与嵌入式开发者的CAN总线DBC文件解析查看工具,内含完整C#源码,适合需要理解DBC报文结构、进行二次开发或集成到自有上位机项目的工程师与学习者。资源包共36个文件,约257KB,以C#源码文件为主…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉