MiniCPM-o 4.5 Ascend 优化实验报告

1. 摘要

  • 环境: Ascend 910C 单卡
  • 结果结果: RTF 0.44 -> 0.37
  • 优化项:
  1. 对 Stage 2 Code2Wav 的 CFM DiT estimator 引入精确签名 NPUGraph,;
  2. 将 Stage 1 Talker 的图模式从 PIECEWISE 调整为 FULL_DECODE_ONLY。

两项优化分别针对不同的调度碎片:

Code2Wav:大量短算子由 CPU 逐个下发
→ 对固定 tensor 签名捕获并回放 CFM estimator

Talker:一次 codec decode 被拆成约 21 个图片段
→ 将一次完整 decode 合并为一次图调用

在相同的中文 Seed-TTS、32 请求、单并发工作负载下,最终组合结果相对本地 eager 基线为:

指标本地 eager 基线两项优化后相对改善
Mean E2EL1835.63 ms1587.15 ms13.54%
Mean TTFT294.81 ms290.02 ms1.62%
Mean Audio TTFP980.10 ms861.59 ms12.09%
Mean Audio RTF0.44000.378813.91%

Profiler 同时证明两项改动降低了调度或空闲时间,而不是通过减少模型计算、 缩短输出或改变 Benchmark 口径获得性能收益:

  • Stage 2 NPU Computing 基本不变,host kernel launch 数下降 86.13%;
  • Stage 1 NPU Computing 基本不变,每个 codec decode 的图调用从约 21 次降至 1 次。

2. 基线与证据边界

2.1 官方性能参考

指标数据
TTFT333.27 ms
TTFP986.47 ms
Chunk RTF0.4423

2.2 本地 baseline

指标MeanMedianP99
E2EL1835.63 ms1801.14 ms2578.17 ms
TTFT294.81 ms265.91 ms486.34 ms
Audio TTFP980.10 ms950.15 ms1188.79 ms
Audio RTF0.44000.44000.5000

3. 优化一:Code2Wav CFM 精确签名 NPUGraph

3.1 观察

Stage 2 trace 显示 Code2Wav 在生成一个 4.68 秒音频样本时存在:

  • 1 次 setup CFM;
  • 5 次 streaming decode CFM;
  • 5 次 HiFT/STFT,对应 5 个 waveform chunk;
  • 74,233 次 aclrtLaunchKernelWithHostArgs;
  • NPU Computing 约 885 ms,但 Stage span 达到约 2235 ms。

这说明 Code2Wav 不只是 NPU 算子计算,还存在大量 host 侧小算子下发和算子间 空隙。

3.2 从 trace 还原执行结构

Profiler 中包含 960 次 FlashAttentionScore。源码中的 DiT depth 为 16,CFM 采样使用 10 个 timestep,因此:

960 / 16 layers / 10 timesteps = 6 CFM invocations

这 6 次调用与源码执行路径完全对应:

setup_batch:  1 CFM
decode_batch: 5 CFM
total:        6 CFM

同时出现 5 次 STFT,与 5 个 decode waveform chunk 对应。这组关系把 profiler 事件、模型结构和源码循环对齐,排除了仅根据算子名称猜测热点的可能。

3.3 根因假设

CFM 的 estimator 在每个 timestep 都重复运行相同的 DiT 结构。对于相同 tensor 形状、dtype、device 和 cache 状态,这条计算路径具有可重复图结构;eager 模式 却需要 CPU 持续逐算子下发,形成高频 launch 开销。

根因假设为:

CFM estimator 的数学计算不是主要新增成本;
大量重复的 host kernel dispatch 扩大了 Code2Wav 的关键路径。

3.4 修改方法

实现没有对整个 Code2Wav stage 强制套用静态图,而是只捕获 tensor-only 的 CFM estimator 内层:

  1. 使用 operation、常量以及 tensor 的 shape、dtype、device 构建精确签名;
  2. 新签名第一次先 eager 执行,完成 lazy kernel 和 allocator 初始化;
  3. 为该签名捕获 NPUGraph;
  4. 后续相同签名把请求输入复制到 static input buffer 后 replay;
  5. replay 输出会被下一次执行覆盖,因此 clone 后再交给请求级 streaming cache;
  6. 捕获失败后 fail fast,要求重启 stage,避免在可能失效的 allocator/RNG capture 状态上继续执行。

图 key 可概括为:

operation
+ constants
+ [(shape, dtype, device), ...]

host-backed timestep embedding 保留在图外;CFM estimator 的 tensor-only 主体进入 图内。Stage 2 外层仍为 eager,以保留 streaming 状态和动态 shape 的灵活性。

部署配置为:

- stage_id: 2
  additional_config:
    code2wav_enable_npu_graph: true
    code2wav_max_npu_graphs: 6

max_graphs=6 是容量扫描后对当前固定工作负载选择的缓存上限,最多保留 6 个精确 签名。容量过小会使后续签名退回 eager,降低 replay 覆盖率;容量过大则允许更多 冷签名进入捕获,增加图内存和测量期首次捕获扰动。Trace 中的 6 次 CFM 调用用于 还原执行结构,并不自动等价于 6 种不同签名。该容量是当前工作负载的经验选择, 不等价于所有输入下的全局最优值。

3.5 Trace A/B

对比 trace:

  • Before:minicpmo-58a8615a-stage2/.../2544680f4271_1707382_20260826161903189_ascend_pt
  • After:minicpmo-npugraph-stage2/.../2544680f4271_1812046_20260826183633391_ascend_pt
Trace 指标EagerNPUGraph变化
Stage span2234.99 ms1869.46 ms-16.36%
NPU Computing885.18 ms885.01 ms-0.02%
NPU Free1349.81 ms984.44 ms-27.07%
Host kernel launches74,23310,295-86.13%
Setup CFM wall time227.88 ms150.50 ms-33.95%
5 次 decode CFM wall time1137.59 ms595.79 ms-47.63%
5 次 decode batch wall time1328.52 ms844.71 ms-36.42%

图模式中观察到 60 次 aclmdlRIExecuteAsync:

6 CFM invocations × 10 timesteps = 60 graph replays

NPU Computing 基本不变,而 NPU Free、host launch 数和 CFM wall time明显下降, 支持“减少 CPU 下发碎片”这一根因假设。它没有减少 DiT 层数、CFM timestep 或 输出 chunk 数。

3.6 性能结果

Graph-only 代表性 warm 结果:

指标MeanMedianP99
E2EL1696.49 ms1613.47 ms2356.42 ms
TTFT287.39 ms258.70 ms468.08 ms
Audio TTFP911.86 ms887.97 ms1095.04 ms
Audio RTF0.40340.39620.4643

相对本地 eager 终端基线:

指标EagerStage 2 NPUGraph相对改善
E2EL1835.63 ms1696.49 ms7.58%
TTFT294.81 ms287.39 ms2.52%
Audio TTFP980.10 ms911.86 ms6.96%
Audio RTF0.44000.40348.32%

共享环境存在明显抖动。同一候选的另一次 cold 结果为 RTF 0.4341、TTFP 946.35 ms、E2EL 1830.56 ms。本文保留该退化样本,不用单次最优值掩盖环境 方差;代表性 warm 结果只用于描述已进入稳定图回放后的性能。

3.7 正确性保护

实现增加了 6 个 CPU 测试用例,覆盖:

  • replay 输出必须 clone,避免请求持有被下一次 replay 覆盖的 static output;
  • 相同精确签名先 capture 再 replay;
  • capture 失败后停止继续使用图运行器;
  • graph 模式要求可捕获的 math SDPA 路径;
  • 有 cache 和无 cache 两种 legacy backend 分发路径。

测试结果为 6 passed。当前环境的 Python/torch 退出阶段存在已知 teardown 异常, 因此测试通过证据来自 pytest.main 完成后显式退出的隔离方式;这不等价于解决了 环境 teardown 问题。

4. 优化二:Talker FULL_DECODE_ONLY

4.1 观察

完成 Stage 2 优化后,Stage 1 Talker 成为下一条可观测的关键路径。PIECEWISE trace 中观察到:

  • 116 次 _compute_slot_mapping_kernel anchor;
  • 115 次 codec token sampling;
  • 2320 次 FusedInferAttentionScore;
  • 2415 次 aclmdlRIExecuteAsync。

模型结构可由数据交叉验证:

2320 attention calls / 116 anchors = 20 Transformer layers

sampling 次数与实际 codec decode step 数对应,因此:

2415 graph executions / 115 decode steps = 21 graph executions per step

PIECEWISE 虽然已经捕获部分模型区域,但一次 codec token decode 仍被拆成约 21 个图片段。短图片段反复回到 host,再由 host 发起下一次执行,形成调度空隙。

4.2 根因假设

Talker 是自回归 codec token 生成器。每一步重复执行近似相同的 Transformer decode,并更新 KV cache。其重复性适合完整 decode graph。

根因假设为:

Talker PIECEWISE 图覆盖过碎;
每个 codec token 内约 21 次图启动拉长了稳定 decode 间隔。

4.3 修改方法

只修改 Stage 1 的图模式:

- stage_id: 1
  compilation_config:
    cudagraph_mode: FULL_DECODE_ONLY

这里的 cudagraph_mode 是 vLLM 跨平台配置名称;在本实验的 Ascend 后端中,它 控制对应的 NPU 图执行策略,并不表示实际使用 CUDA。

选择 FULL_DECODE_ONLY 而不是捕获整个请求,原因是:

  • prefill 和首次 setup 的 shape、控制流与资源需求更动态;
  • decode 会重复一百余次,收益可在每个 codec token 上累积;
  • 只扩大 decode 覆盖范围的风险小于强制图化整个请求。

这是单变量配置实验:Stage 0 保持 PIECEWISE,Stage 2 保持优化一中的精确签名 NPUGraph 和 max_graphs=6。

4.4 Trace A/B

对比 trace:

  • Before:minicpmo-npugraph-stage1/.../2544680f4271_1986541_20260826222746117_ascend_pt
  • After:minicpmo-stage1-full-decode/.../2544680f4271_2052740_20260827000857185_ascend_pt
Trace 指标PIECEWISEFULL_DECODE_ONLY变化
Stage span1477.57 ms1146.53 ms-22.40%
NPU Computing301.28 ms301.74 ms+0.15%
NPU Free1176.29 ms844.79 ms-28.18%
Graph executions2415115-95.24%
稳定 decode 间隔 mean12.560 ms9.670 ms-23.01%
稳定 decode 间隔 median12.391 ms9.385 ms-24.26%
稳定 decode 间隔 P9513.740 ms11.036 ms-19.68%

稳定 decode 间隔排除了第一个 interval,因为它包含首次 setup/capture 等一次性 行为。优化后的图执行数满足:

115 graph executions / 115 codec decode steps = 1 graph execution per step

NPU Computing 再次基本不变,而 NPU Free 和 decode 间隔下降。这证明改动合并了 host dispatch 边界,没有减少 Transformer 层数、codec token 数或模型计算量。

4.5 性能 A/B

Before 使用 Stage 2 graph-only 的代表性 warm JSON,After 在相同数据、顺序、 单并发和 Stage 2 配置下仅切换 Stage 1 图模式:

指标Stage 1 PIECEWISEFULL_DECODE_ONLY相对变化
Mean E2EL1696.49 ms1587.15 ms-6.45%
Mean TTFT287.39 ms290.02 ms+0.92%
Mean Audio TTFP911.86 ms861.59 ms-5.51%
Mean Audio RTF0.40340.3788-6.10%
P99 E2EL2356.42 ms2374.73 ms+0.78%
P99 Audio TTFP1095.04 ms1039.66 ms-5.06%
P99 Audio RTF0.46430.4516-2.74%

TTFT 主要位于 Stage 0 Thinker critical path,因此 Stage 1 改动不应显著改善 TTFT;观测到的 +0.92% 属于当前环境噪声量级。TTFP、RTF 和 E2EL 按假设改善, 与 Talker 所在的音频生成关键路径一致。

P99 E2EL 没有随均值改善,说明单次 32 请求仍不足以刻画共享环境的 tail latency, 也不能只依据 mean 宣称所有尾部行为均已改善。

5. 两项优化的累计效果

指标本地 eagerStage 2 GraphStage 1 Full Decode + Stage 2 Graph
Mean E2EL1835.63 ms1696.49 ms1587.15 ms
Mean TTFT294.81 ms287.39 ms290.02 ms
Mean Audio TTFP980.10 ms911.86 ms861.59 ms
Mean Audio RTF0.44000.40340.3788

相对本地 eager 的累计改善为:

E2EL: 13.54%
TTFP: 12.09%
RTF:  13.91%
TTFT:  1.62%