性能调优是一个系统化工程不是靠玄学调参。这份Checklist将调优过程拆分为20个可执行的步骤每步都有明确的判断标准、操作命令和避坑指南。第一阶段建立基线Step 1-5在动手优化前必须先知道“现在有多慢”以及“瓶颈在哪里”。Step 1测量当前性能Baseline不要只看平均值要关注P99延迟和吞吐量。importtimeimporttorchimportnumpyasnpdefmeasure_latency(model,input_data,num_runs200,warmup20): 测量延迟的规范方法 关键点 1. 必须Warmup排除JIT编译/初始化开销 2. 循环内只同步一次避免频繁同步掩盖真实耗时 3. 使用 perf_counter() 高精度计时 # 预热for_inrange(warmup):_model(input_data)torch.npu.synchronize()latencies[]for_inrange(num_runs):t0time.perf_counter()_model(input_data)# 注意这里不立即同步等循环结束统一同步或仅最后同步# 若需精确单轮延迟需在循环内 sync但会略微影响结果# 推荐循环内不sync循环后sync一次获取整体时间再除以次数# 但为了统计分布通常每轮都sync确保数据完整torch.npu.synchronize()t1time.perf_counter()latencies.append((t1-t0)*1000)latenciesnp.array(latencies)print(fLatency P50:{np.percentile(latencies,50):.2f}ms)print(fLatency P90:{np.percentile(latencies,90):.2f}ms)print(fLatency P99:{np.percentile(latencies,99):.2f}ms)print(fThroughput:{1000/np.mean(latencies):.1f}samples/s)return{p50:np.percentile(latencies,50),p99:np.percentile(latencies,99)}# 执行modeltorch.jit.load(model_fp16.om).eval()inptorch.randn(1,3,224,224).npu()baselinemeasure_latency(model,inp)# 记录baseline {p50: 45.2, p99: 61.3}Step 2检查NPU利用率利用率高不代表快但利用率低一定有问题。# 方法1实时监控发现持续性低负载watch-n1npu-smi info -t utilization,power,temperature -i 0# 方法2Profiling抓Trace发现间歇性卡顿python3EOF import torch with torch.npu.profile(./trace.json): for _ in range(100): model(inp) print(Trace saved to trace.json) EOF# 分析工具# 1. 浏览器打开 https://ui.perfetto.dev/# 2. 导入 trace.json# 3. 查看 Device Utilization 轨道# 4. 关键判断# - 80%: 正常优化空间小# - 50~80%: 有优化空间 (IO或调度问题)# - 50%: 严重瓶颈 (必须优化)Step 3确认数据传输不是瓶颈PCIe传输是常见的隐形杀手。importtorchimportnumpyasnpimporttime# 测试纯计算耗时t_model_starttime.perf_counter()for_inrange(100):outmodel(inp)# inp已在NPU上torch.npu.synchronize()t_model(time.perf_counter()-t_model_start)/100*1000# 测试含传输的总耗时t_total_starttime.perf_counter()for_inrange(100):# 模拟真实场景CPU生成 - 传输 - 推理inp_cpunp.random.randn(1,3,224,224).astype(np.float32)inp_nputorch.from_numpy(inp_cpu).npu()# 触发传输outmodel(inp_npu)torch.npu.synchronize()t_total(time.perf_counter()-t_total_start)/100*1000overheadt_total-t_model ratiooverhead/t_total*100print(fModel Only:{t_model:.2f}ms | Total:{t_total:.2f}ms | Overhead:{overhead:.2f}ms ({ratio:.1f}%))# 判断标准# - overhead 5%: 正常# - 5% ~ 20%: 需优化 (考虑异步传输)# - 20%: 严重瓶颈 (必须优化)Step 4定位最大瓶颈算子级分析找出耗时最长的Top 5算子。importcann# 开启详细算子日志cann.set_op_trace_mode(True)# 运行推理并抓取Tracewithtorch.npu.profile(./op_trace.json):model(inp)# 分析 op_trace.json (或使用msprof工具)# 典型瓶颈特征# - Conv2d/MatMul 占 60%: 算子融合或减少计算量# - DataCopy 占 30%: 格式转换太多 (NCHW - NC1HWC0)# - Reshape/Transpose 占 20%: 数据排布不合理# - Softmax 占 15%: Shape不规则尝试融合Step 5确认Batch Size是否合理寻找吞吐量拐点。results{}forbsin[1,2,4,8,16,32]:inptorch.randn(bs,3,224,224).npu()# Warmupfor_inrange(10):model(inp)torch.npu.synchronize()# Measuret0time.perf_counter()for_inrange(100):model(inp)torch.npu.synchronize()latency(time.perf_counter()-t0)/100*1000throughputbs*1000/latency results[bs]{latency:latency,throughput:throughput}print(fBS{bs:2d}: Latency{latency:.2f}ms, Throughput{throughput:.1f}/s)# 策略# - 实时服务 (低延迟): 选最小Batch (通常1或2)# - 离线批处理 (高吞吐): 选Throughput峰值对应的Batch# - 拐点判断: 过了某个点后Throughput不再增加甚至下降第二阶段逐项优化Step 6-15Step 6启用算子融合最有效手段之一减少Kernel Launch次数。# 检查融合情况python3-c from cann.graph import load_model g load_model(model_fp16.om) print(g.get_fusion_report()) # 输出示例 # [x] ConvBNReLU fused # [ ] ConvConvConv NOT fused -- 重点优化对象 # ATC编译时强制开启激进融合atc--modelmodel.onnx\--fusion_switch_fileaggressive_fusion.cfg\--op_compiler_paramsenable_tilingtrue,enable_fusiontrue\...Step 7消除 NCHW ↔ NC1HWC0 格式转换格式转换是NPU的大忌。# 诊断在模型前后打印Shape和Stridedefcheck_format(model,inp):outmodel(inp)print(fInp:{inp.shape}, Stride:{inp.stride()})print(fOut:{out.shape}, Stride:{out.stride()})returnout# 解决策略# 1. 尽量保持NC1HWC0格式贯穿整个网络# 2. 如果必须用NCHW将所有NCHW算子集中在一起减少切换次数# 3. 使用 --input_format 参数指定输入格式Step 8检查并启用混合精度 (FP16/BF16)提升速度并降低显存占用。# ATC编译配置atc--modelmodel.onnx\--precision_modeallow_mix_precision\--insert_op_confmix.cfg\...# mix.cfg 示例{mixed_precision_ratio:0.8,# 80%算子转FP16skip_layers:[output_layer]# 最后一层保留FP32防止溢出}Step 9启用图优化 (Graph Engine, GE)让编译器自动进行常量折叠、死代码消除。atc--modelmodel.onnx\--graph_engine_modehigh_performance\...Step 10启用连续Batch (Continuous Batching)解决静态Batch带来的等待延迟。classContinuousBatcher:def__init__(self,model,max_batch16,timeout_ms10):self.modelmodel self.max_batchmax_batch self.pending[]defadd_request(self,req_id,input_data):self.pending.append((req_id,input_data))iflen(self.pending)self.max_batch:returnself._run_batch()# 可选超时自动触发def_run_batch(self):inputstorch.stack([xfor_,xinself.pending])outputsself.model(inputs)results{req_id:outfor(req_id,_),outinzip(self.pending,outputs)}self.pending[]returnresults# 配合 CANN 动态Shape特性效果更佳Step 11优化数据预处理 (AIPP)将预处理固化进OM利用硬件加速单元。# aipp.cfg 示例aipp_op{related_input_rank:0src_image_size_w:224src_image_size_h:224resize:224mean_ax1:123.675var_reci_ax1:0.017124761# ... 其他归一化参数}# 编译atc--modelmodel.onnx\--insert_op_confaipp.cfg\...Step 12减少小算子数量避免频繁的Kernel Launch。# ❌ 错误写法100次小运算classBadModel(torch.nn.Module):defforward(self,x):for_inrange(100):xx1xx*2returnx# ✅ 正确写法数学合并classGoodModel(torch.nn.Module):defforward(self,x):returnx*22# 一次完成Step 13检查Tiling策略大图推理时的内存分块优化。# 查看默认Tilingpython3-cimport cann; print(cann.op_info(Conv2d).tiling_params)# 手动调整Tiling (针对特定大模型)atc--modelmodel.onnx\--te_config{tile_memory_size: 16777216}\...Step 14检查内存排布 (Contiguous)确保数据访问连续性减少Cache Miss。# 检查Stridextorch.randn(1,3,224,224).npu()print(x.stride())# 如果中间结果不连续强制连续化outputoutput.contiguous()Step 15启用L2 Cache优化复用中间结果。atc--modelmodel.onnx\--enable_l2_cachetrue\...第三阶段进阶调优与监控Step 16-20Step 16多卡通信优化 (HCCL)如果是多机多卡训练/推理检查通信带宽。# 检查网络带宽iperf3-cpeer_ip# 调整HCCL参数exportHCCL_CONNECT_TIMEOUT600exportHCCL_STREAM_PRIORITY0Step 17显存管理优化防止碎片化导致的OOM。# 定期清理缓存torch.npu.empty_cache()# 避免在循环中创建大量临时Tensor# 使用 del 及时释放delintermediate_tensorStep 18使用msprof深度分析CANN自带的火焰图分析工具。# 生成profile文件msprof--modetrace--outputprofile.prof ./train.py# 分析msprof--inputprofile.prof--outputreport.htmlStep 19温度与功耗控制过热会导致降频。# 监控watch-n1npu-smi info -t temperature -i 0# 优化# 1. 改善机房散热# 2. 降低频率限制 (if allowed)# 3. 避免长时间满负荷运行Step 20自动化回归测试建立性能基线库每次代码更新自动对比。# 伪代码defregression_test(new_model,baseline_metrics):new_metricsmeasure_latency(new_model)ifnew_metrics[p99]baseline_metrics[p99]*1.05:raisePerformanceRegressionError(P99延迟增加超过5%!)总结调优路线图先测: 建立Baseline量化当前性能。找病: 通过Profiler和Utilization找到瓶颈IO? 计算? 通信?。开刀: 按优先级实施优化融合 格式 精度 并行。复查: 再次测量确保优化有效且无副作用。固化: 将最佳配置写入脚本形成自动化流程。记住没有银弹。最好的优化方案是针对你的具体模型和数据特征量身定制的。