对话:模型推理慢,怎么调


A:模型上线了,推理延迟 280ms,比预期高了一倍。

B:280ms 是什么模型?输入多大?

A:BERT-base,序列长度 512,batch=1。

B:单请求 280ms 明显偏高。BERT-base 在 910 上,序列 512,理论延迟是 80-100ms。差了 3 倍,先排查瓶颈在哪。

A:怎么排查?

B:看三个指标:AICore 利用率、HBM 带宽利用率、HCCL 通信时间(如果多卡)。用 npu-smi info -t usages 监控,推理的时候看实时数据。

A:AICore 利用率 45%,HBM 带宽利用率 60%,HCCL 不涉及(单卡)。

B:45% 太低了,正常应该 >70%。带宽利用率 60% 也偏低。说明瓶颈不在计算,在数据搬运。你的预处理在哪做的?

A:预处理在 CPU 上,用 transformers 库的 tokenizer。

B:tokenizer 本身不慢,但每次推理都要把 tokenized 结果从 CPU 搬到 NPU。PCIe 的带宽是 16GB/s,搬一个 (1, 512) 的 int64 tensor,大小是 4KB,理论耗时 0.25us。但实际搬运开销远大于这个------CPU 要准备数据、NPU 要接收、中间还有一次同步。batch=1 的时候,这个开销占比很大。

A:那预处理挪到 NPU 上?

B:对。昇腾有 ops-adv 仓库,里面有文本预处理的算子(分词、转 token ID)。但 tokenizer 的逻辑比较复杂,ops-adv 目前只支持基础操作(比如 lookup table)。如果模型用的是 BPE tokenizer,可能要自己写一个轻量版本。

A:写一个 tokenizer 算子工作量不小。有没有更快的方案?

B:有。把预处理和推理合成一个请求,减少 CPU-NPU 的交互次数。现在的流程是:CPU preprocess → 搬到 NPU → NPU inference → 搬回 CPU → CPU postprocess。改成:CPU preprocess → 搬到 NPU → NPU inference + postprocess(后处理也在 NPU 上做)→ 搬回 CPU。后处理就是取 argmax 和 softmax,很简单,用 Vector Unit 一行代码就能做。

A:改一下试试。


(半小时后)

A:改完了,延迟从 280ms 降到 180ms。还是比预期高。

B:180ms,进步了。AICore 利用率现在多少?

A:62%。带宽利用率 75%。

B:利用率上去了,但还是不够。再看计算图,BERT 的 Attention 算子有没有融合?

A:怎么看?

B:跑一遍推理,把 GE 的图导出来:export GENGINE_GRAPH_SAVE_PATH=./ge_graphs。然后用 Netron 打开,找 Attention 相关的节点。

A:看了一下,Attention 还是分开的:MatMul → Softmax → MatMul。没有合成 FlashAttention。

B:问题找到了。FlashAttention 没生效。ATC 编译的时候,模型要用 NPU 设备加载,GE 才能识别出 Attention 模式。你的模型是怎么加载的?

A:先在 CPU 上加载,然后 .npu()。

B:这就是问题。CPU 加载之后,GE 看到的是一个普通的 PyTorch 模型,不认为是 Attention。改成:

python 复制代码
with torch.npu.device(0):
    model = BertModel.from_pretrained("bert-base")

这样 GE 在编译时能识别出 Attention 模式,自动合成 FlashAttention。

A:改一下,重新编译。


(编译后)

A:延迟从 180ms 降到 95ms。AICore 利用率 78%,带宽利用率 45%。

B:95ms 接近预期了。带宽利用率降到 45%,说明瓶颈转移到计算了,这是好事。还有优化空间吗?

A:跑 AOE 调优试试?

B:BERT 的调优收益通常在 10-20%。跑一下 GA,50 轮就够了。记得保存调优结果,下次编译直接加载。

A:调完之后延迟 82ms。满足预期了。


总结一下这次调优的关键:

  1. 预处理/后处理搬到 NPU,减少 CPU-NPU 数据搬运
  2. 模型用 NPU 设备加载,让 GE 识别出 Attention 模式,触发 FlashAttention 融合
  3. 跑 AOE 调优,进一步压榨 AICore 性能

从 280ms 到 82ms,提升 3.4 倍。单卡推理慢的问题基本解决了。

相关推荐
Rocky Ding*几秒前
一文读懂Qwen-Audio-3.1核心基础知识:从语音识别到可控声景与实时Agent
论文阅读·人工智能·深度学习·机器学习·aigc·ai-native·qwen-audio
桃西西呀2 分钟前
Laya 源码级原理拆解之四:路由检测与服务部署
人工智能·llm·ai编程
努力努力再努力wz2 分钟前
【边缘计算入门系列】从“在哪里算”到“怎么算”:一文建立边缘计算、算子、计算图与 Tensor 的底层心智模型
人工智能·docker·边缘计算
黄啊码3 分钟前
【黄啊码】一个陪伴类的 Agent 产品,凭什么我觉得它做得好?
人工智能
leoZ2317 分钟前
第 34 篇 Copilot 与嵌入式 AI:把能力缝进工作流
人工智能·大模型·copilot·agent
桃西西呀7 分钟前
Laya 源码级原理拆解之三:字段编译与业务胶水
人工智能·llm·ai编程
欧特克_Glodon10 分钟前
OpenCV计算机视觉开发入门与实践(基于C++):专栏内容介绍及目录
c++·人工智能·opencv·计算机视觉
55873 生态系统10 分钟前
55873 全域文明生态系统:技术价值矩阵与底层创新内核
大数据·人工智能·55873全域文明生态体系·55873操作系统
倔强的石头10621 分钟前
【Transformer】Encoder_Decoder_vs_Decoder_Only架构对比
人工智能·深度学习·transformer
技灵AI23 分钟前
Seedance 长剧生产实战:用首尾帧接戏解决角色崩脸与场景漂移(含 return_last_frame 用法与提示词模板)
人工智能·prompt·aigc·音视频