Skip to content

CosyVoice3 多阶段生成模型优化:从单阶段加速到端到端 RTF

对应上游:sgl-project/sglang-omni#1652(CosyVoice3 Optimization Roadmap)。

Related Work:#1022(Qwen3-Omni Serving Optimization Tracker)与 #1018(Qwen3-Omni Perf RFC)。

本文关注的不是“某个 kernel 怎么快 10%”,而是:多阶段生成模型怎样从单阶段 benchmark,走到真实并发下的端到端 RTF 优化。

CosyVoice3 这类语音生成系统不是单一 Transformer,而是一条多阶段 pipeline:

reference audio
↓
S3-Tokenizer / speaker encoder
↓
AR model(文本/语义 token 自回归生成)
↓
DiT / Flow Decoder(多步连续生成)
↓
HiFT Vocoder(波形生成)
↓
audio stream

这带来一个非常关键的结论:

局部最快 ≠ 端到端最快。

如果 AR、DiT、Vocoder 的生产/消费速率不匹配,某一阶段即使独立 benchmark 变快,也可能只是把排队压力推给下游。

因此优化顺序应该是:

  1. 先测每个 stage 的真实运行时间;
  2. 再做单阶段工程优化;
  3. 然后做 batch / chunk / streaming;
  4. 最后把所有 stage 放回同一个调度器里看 p50/p95/p99 RTF;
  5. 在工程瓶颈解决后,再考虑蒸馏、LoRA、算子级 fusion 等算法优化。

2. Runtime Calculation:第一步永远是拆时间

Section titled “2. Runtime Calculation:第一步永远是拆时间”

在真实 workload 上做一次完整的 runtime dump,至少覆盖:

  • 短句 / 长句;
  • streaming / offline;
  • 有 reference audio / 无 reference audio;
  • 单请求 / 并发请求;
  • 不同 batch size;
  • 不同 DiT chunk size / step 数。

建议记录:

T_total
├── T_tokenizer
├── T_AR
├── T_DiT
├── T_vocoder
├── T_queue
└── T_copy / framework overhead

真正有价值的不是只看 CUDA kernel 时间,而是同时看:

  • compute time:GPU 真正在算多久;
  • queue time:请求在 stage 入口等待多久;
  • bubble time:上下游速率不匹配造成多少空洞;
  • TTFA / first-chunk latency:多久能吐出第一段音频;
  • RTF:生成耗时 / 音频时长;
  • p50 / p95 / p99:并发场景下尾延迟是否恶化。

很多多阶段系统的早期性能下降,并不是 kernel 本身慢,而是调度器中的请求排队。


3. S3-Tokenizer:并行的是独立参考音频

Section titled “3. S3-Tokenizer:并行的是独立参考音频”

上游 Roadmap 已经包含两类尝试:

  • Multi-thread speaker encoder encoding;
  • Batch inference for S3-Tokenizer(上游标注 tested no effect)。

这里很适合作为一个反例:“支持 batch”不代表一定有效。

如果 speaker/reference encoding 本来只占端到端很小一部分,或者受到 CPU 预处理、缓存命中、单请求 reference 数量的限制,那么 batch 化即使在局部 benchmark 中成立,也不会显著改善整体 RTF。

因此 Tokenizer 阶段更应该回答:

  1. 它是不是实际瓶颈?
  2. 多 reference audio 是否真的同时存在?
  3. cache / single-flight 是否已经让重复工作消失?
  4. CPU 与 GPU 之间是否有更大的准备/同步开销?

4. AR:把它当成标准 LLM Serving 问题

Section titled “4. AR:把它当成标准 LLM Serving 问题”

CosyVoice3 的 AR stage 本质上仍然是自回归 Transformer,因此大量成熟的 LLM serving 技术可以直接复用。

AR 不应该等整段 token 生成完再交给下游,而应该尽快把可消费的 token chunk 推给 DiT。

这样可以把:

AR 全部完成 → DiT → Vocoder

改造成:

AR chunk 0 ─→ DiT chunk 0 ─→ Vocoder chunk 0
AR chunk 1 ─→ DiT chunk 1 ─→ Vocoder chunk 1
AR chunk 2 ─→ ...

目标从“缩短总 compute”变成“让 pipeline 尽早填满”。

多请求下,AR decode 每轮只生成很少 token,非常适合 continuous batching:

  • 新请求动态加入;
  • 已完成请求立即退出;
  • 避免静态 batch 被最慢请求拖住。

如果请求存在共享前缀,还可以进一步利用类似 SGLang RadixAttention 的 prefix cache 思路。

4.3 torch.compile / CUDA Graph / TensorRT-LLM

Section titled “4.3 torch.compile / CUDA Graph / TensorRT-LLM”

AR stage shape 相对规整,因此通常适合:

  • torch.compile;
  • CUDA Graph;
  • TensorRT-LLM;
  • fused RMSNorm / RoPE / attention 等算子。

但要特别注意:Streaming 会增加动态性。如果 sequence length、batch size、chunk boundary 高频变化,图捕获与 shape specialization 的收益可能被重新编译或 graph 数量膨胀抵消。

所以工程上通常需要 bucket:

batch bucket × sequence-length bucket × decode mode

而不是追求一个“万能 graph”。

4.4 AR overlap schedule 为什么可能没效果

Section titled “4.4 AR overlap schedule 为什么可能没效果”

上游 Roadmap 中 AR overlap schedule 被标注为 tested no effect。这并不奇怪。

如果 AR 本身不是 dominant stage,或者下游 DiT/Vocoder 才是 critical path,那么单独把 AR 内部 overlap 做得更激进,端到端 RTF 仍可能不变。

这再次说明:优化必须回到整条 pipeline 的 critical path。


5. DiT / Flow Decoder:最值得系统优化的阶段

Section titled “5. DiT / Flow Decoder:最值得系统优化的阶段”

相比 AR,DiT/Flow Decoder 的特点完全不同:

  • 不是 token-by-token 自回归;
  • 往往需要多次 ODE / flow step;
  • 单步计算重;
  • shape 与 chunk size 可能动态变化;
  • 每一步对最终质量的贡献并不完全相同。

上游 Roadmap 已覆盖:

  • Batch inference for Flow decoder;
  • Chunk-wise inference for streaming;
  • torch.compile for DiT backbone;
  • TensorRT acceleration;
  • flow auto-cast bug 修复;
  • 可选的 step-distillation。

DiT 通常比 AR 更“GEMM-friendly”。多个请求同时进入 DiT 后,batching 可以明显提高 Tensor Core 利用率。

但 batch size 不能只看单 stage throughput,需要同时考虑:

更大 batch
→ 更高 GPU utilization
→ 更长排队时间
→ 更差 first-chunk latency / p99 RTF

所以 scheduler 需要在 throughput 与 latency 之间做动态平衡。

Streaming 的核心不是简单把 tensor 切小,而是要保证:

  1. chunk 能独立或近似独立地推进;
  2. 边界条件正确;
  3. 上下文依赖被保留;
  4. 音质不因为 chunk 过小而明显下降;
  5. chunk 足够小,首包延迟才会下降。

chunk size 实际上是一个系统参数:

小 chunk:低延迟、高调度/launch 开销、GEMM 更小
大 chunk:高吞吐、高首包延迟、batch 更容易做大

DiT backbone 往往具有大量重复结构,因此编译优化通常有价值;但动态 axis、动态 chunk size 会使 TensorRT / compile 的 profile 设计更困难。

实际工程中应优先尝试:

  • 固定少量 chunk bucket;
  • 固定常见 batch bucket;
  • 对 backbone 做 graph/engine specialization;
  • 把难以静态化的前后处理留在 eager path。

而不是强行把整条 pipeline 塞进一个静态 engine。

5.4 Step Distillation:真正改变算法复杂度

Section titled “5.4 Step Distillation:真正改变算法复杂度”

如果 DiT 原本需要 NN 个 flow/ODE steps,纯工程优化只能让每一步更快;step distillation 则直接尝试把:

N→N′(N′<N)N \rightarrow N' \quad (N' < N)

这意味着总 FLOPs 近似按步数下降。

但它属于算法优化,风险也更高:

  • 音质退化;
  • speaker similarity 变化;
  • 需要重新训练/微调;
  • 不同模型可能需要不同 distillation recipe。

所以合理顺序通常是先把工程 pipeline 做对,再做 step distillation。

上游还提到 framework-level LoRA 支持,这一点很重要:如果 distillation / adaptation 可以作为 LoRA 插件提供,就能避免给每个用户维护一套完整模型权重。


6. Vocoder:单请求不一定慢,但非常容易成为并发瓶颈

Section titled “6. Vocoder:单请求不一定慢,但非常容易成为并发瓶颈”

HiFT Vocoder 通常是 causal convolution / upsampling 类结构,并不像 Transformer 那么天然适合现成 LLM serving runtime。

因此优先级通常是:

  1. Batch inference;
  2. torch.compile;
  3. 有稳定 shape 后再考虑 TensorRT;
  4. 再看卷积、激活、重排、上采样等 fusion。

上游 Roadmap 已包含 Batch inference for HiFT Vocoder。

这里最重要的是看并发系统行为:

一个 vocoder 单请求只需几毫秒,不代表它不会成为瓶颈。

如果上游 AR/DiT 很快地产生大量 chunk,而 vocoder 一次只能消费一个或很小 batch,就会形成典型的 producer-consumer 堵塞:

AR/DiT producer rate > vocoder consumer rate
↓
queue grows
↓
p95/p99 爆炸

所以 Vocoder 优化的核心指标不是单 kernel latency,而是在目标并发下的稳定消费速率。

6.1 实际案例:#1844 的 HiFT length-aware batching

Section titled “6.1 实际案例:#1844 的 HiFT length-aware batching”

#1844 把 CosyVoice3 中原先“Flow 已经 batch,但 HiFT 仍逐请求调用”的路径改成真正的 batched vocoder:

Flow batch
↓
mel_0 ─┐
mel_1 ─┼─→ length-aware group → right padding → HiFT(B>1) → crop → wav_i
mel_2 ─┘

它不是修改 HiFT 算法,而是修改调用编排:

  • scheduler 最大 batch 从 8 调到 16,最大等待从 2 ms 调到 30 ms;
  • Flow admission budget 从 2000 提高到 8000 mel frames;
  • 变长 mel 按长度排序,只有 padding waste 不超过阈值时才合批;
  • hift_max_padding_waste=1.5 时,约束近似为
BLmax⁡∑iLi≤1.5;\frac{B L_{\max}}{\sum_i L_i} \le 1.5;
  • 多条 mel right-pad 成一个 [B, 80, T_max] 后只跑一次 HiFT;
  • 根据 hop_len \times \prod upsample_rates 推导 mel→wave 的 stride,再裁回每条真实长度;
  • 加载阶段 fold 掉 weight_norm parametrization,避免 inference 时重复构造权重;
  • preprocessing 并发与 ONNX intra-op threads 也同时提高,避免 GPU 更快后 CPU feeder 变成新瓶颈。

这个 PR 最值得学习的地方不是“batch 能提速”,而是它把 batch 当成调度问题:必须让 scheduler 真的形成 batch,局部模型才有机会利用 batch dimension。

同时也存在 correctness 边界:不同长度 mel 的 zero-padding 会改变短样本真实 endpoint 附近的 HiFT/STFT 上下文,因此尾部 waveform 需要真实 checkpoint 做 serial-vs-padded 验证,不能仅靠最终 crop 假设语义完全等价。


7. 调度器才是多阶段系统优化的中心

Section titled “7. 调度器才是多阶段系统优化的中心”

单阶段优化完成后,最重要的问题变成:

AR batch、DiT batch / chunk、Vocoder batch 分别设多大,才能让整条 pipeline 的 RTF 最优?

可以把三个阶段近似看成三个服务站:

AR queue → AR workers
↓
DiT queue → DiT workers
↓
VOC queue → Vocoder workers

每个 stage 都有自己的:

  • service time;
  • batch efficiency curve;
  • queue length;
  • memory footprint;
  • latency SLO。

真正合理的 scheduler 应该基于运行时状态做选择,而不是固定“batch 越大越好”。

设请求 ii 的音频长度为 LiL_i,端到端延迟为 TiT_i:

RTFi=TiLiRTF_i = \frac{T_i}{L_i}

线上通常关心:

min⁡  p95(RTF)\min \; \mathrm{p95}(RTF)

同时满足:

p99(RTF)<τ\mathrm{p99}(RTF) < \tau

以及质量约束:

Q(x)≥Qbaseline−ϵQ(x) \ge Q_{baseline} - \epsilon

于是 batch size、chunk size、DiT steps、streaming window 都不再是独立参数,而是联合优化变量。

7.2 为什么“换一种生成方式”可能反而更慢

Section titled “7.2 为什么“换一种生成方式”可能反而更慢”

例如把一次性生成改成 streaming:

  • 第一包确实更快;
  • 但 chunk 变小后 GEMM 效率下降;
  • kernel launch 次数增多;
  • scheduler 事件更多;
  • vocoder 被更频繁唤醒;
  • queue contention 增加。

所以正确判断标准不是“streaming 已经做出来了”,而是:

在目标并发与 SLO 下,它是否改善了 TTFA、p95/p99 RTF,并保持质量?


8. Kernel / KDA 优化应该放在最后一层

Section titled “8. Kernel / KDA 优化应该放在最后一层”

当系统 profiling 已经确认某个算子是稳定热点,才值得继续做 kernel-level 优化,例如:

  • RoPE fusion;
  • RMSNorm fusion;
  • activation fusion;
  • conv + bias + activation;
  • layout transform fusion;
  • quantization / low precision;
  • custom Triton / CUDA kernel。

原因很简单:

如果一个 kernel 只占端到端 2%,即使提速 2×,Amdahl 定律下整体收益仍然很小。

因此最有效的 Agent 工作流不是“看到算子就优化”,而是:

profile → 找 critical path → 提假设 → 做最小改动 → benchmark → 质量验证 → 保留/回滚

9. 测试:每次优化都必须留下可复现证据

Section titled “9. 测试:每次优化都必须留下可复现证据”

多阶段生成模型最容易出现的问题,是某个方案局部 benchmark 很漂亮,但:

  • 长句退化;
  • streaming 音质下降;
  • corner case 崩溃;
  • p99 变差;
  • 显存峰值上升;
  • 并发时 scheduler 被击穿。

建议每次改动都记录:

指标BaselineOptimizedDelta
TTFA
p50 RTF
p95 RTF
p99 RTF
Throughput
Peak VRAM
GPU util
AR time
DiT time
Vocoder time
Queue time
Quality metric

并至少覆盖:

  • 短 / 中 / 长文本;
  • 单请求 / 中并发 / 高并发;
  • streaming / offline;
  • reference audio 有 / 无;
  • 常见语言、特殊字符、极端长度等 corner cases。

这种测试矩阵对 Agent 尤其重要,因为它可以防止 Agent 反复尝试之前已经证明无效的优化路径。


截至 2026-09-08,上游 Issue 展现出的方向非常清晰:

Stage主要方向系统意义
S3-Tokenizermulti-thread / batch让 reference encoding 不阻塞主路径
ARstreaming / overlap尽快把 token 交给下游,并尝试隐藏阶段间空洞
DiTbatch / chunk / compile / TensorRT同时优化吞吐、streaming 与单步执行效率
DiT algorithmstep distillation / LoRA从根本上减少 flow steps
Vocoderbatch inference提升下游消费速率,避免 streaming queue 堵塞
Generalkernel fusion在确定热点后继续压缩算子开销
NPUAscend support把同一套多阶段运行时模型迁移到不同硬件

其中很值得注意的两个结果是:

  • S3-Tokenizer batch inference:tested no effect;
  • AR overlap schedule:tested no effect。

它们并不是失败的优化,而是在告诉我们:

多阶段生成模型中,最重要的不是“优化技术有没有用”,而是“它是不是当前 critical path”。

这也是这份 Roadmap 最值得学习的地方。


Section titled “11. Related Work:Qwen3-Omni #1022 是更完整的多阶段 serving 样板”

#1022 不是一个单点优化 issue,而是 Qwen3-Omni 的 live PR tracker;详细的测量合同、benchmark gate、negative results 放在 #1018。

它的 pipeline 与 CosyVoice3 不同:

input
↓
Thinker
↓ token / hidden stream
Talker AR + code predictor
↓ codec frames
Code2Wav
↓
audio stream

但系统问题高度同构。#1022 把工作分成四类:

  1. Thinker:并发正确性、admission、prefill CUDA Graph、多模态 merge / M-RoPE、mixed prefill/decode;
  2. Pipeline handoff:stage 之间尽早启动、减小 payload、减少 event-loop / relay 开销;
  3. Talker / predictor:采样状态复用、GQA attention、device-resident state;
  4. Code2Wav:CUDA Graph、batching、chunk 对齐、输出 overlap。

这几类工作刚好给 CosyVoice3 提供了一套非常具体的 related work。

11.1 Thinker:Prefill 的最大问题可能不是算力,而是 host dispatch

Section titled “11.1 Thinker:Prefill 的最大问题可能不是算力,而是 host dispatch”

#1018 的 profiling 给出了一个很典型的例子:Thinker 单请求 prefill window 中,设备实际 compute 只有几毫秒,而大量时间花在数千次 CUDA API / host dispatch 上。因此 #1381 把 Qwen3-Omni 接入 Breakable Prefill CUDA Graph,而不是继续微调某个小 kernel。

#1381 的 text-only sweep 中:

  • c1 TTFT p50:55.2 ms → 26.3 ms,约 -52%;
  • c1 input throughput:约 +107%;
  • c16 TTFT p50:约 -27%,input throughput +37%。

更严格的 B→C 图执行对照里,text→text c1 request throughput 甚至提升 +182.5%、TTFT 降 70.2%。但高并发时出现了一个非常重要的反例:throughput 仍提高约 20%~40%,mean TTFT 却可能回退 10%~20%。

所以 CUDA Graph 的结论不是“开了就赢”,而是:

图执行会同时改变 host overhead、batch formation 和调度行为;必须同时看 throughput 与 TTFT tail,不能只看一个 microbenchmark。

这和 CosyVoice DiT 的 torch.compile / TensorRT bucket 问题本质一致。

11.2 Pipeline handoff:每个 token 的小开销也会累积成大瓶颈

Section titled “11.2 Pipeline handoff:每个 token 的小开销也会累积成大瓶颈”

Qwen3-Omni 的 Thinker→Talker 边界每生成一个 token 都会经过,因此 per-chunk overhead 是按 token rate 支付的。

#1574 做了三件事:

  • 只传 Talker 真正需要的一份 generated assistant tensor,去掉冗余 hidden;
  • 小于 16 KiB 的 CPU stream chunk 直接 inline 到控制消息,不再走共享内存 relay;
  • Talker prefill tensor 保持 tensor 形态,去掉 cpu().tolist() 再重建 tensor 的往返。

在 2×H100 streaming SeedTTS 上,它在高并发下的收益非常明显:

ConcurrencyQPSAudio TTFP meanRTF mean
c8+10.68%-15.79%-11.51%
c16+11.15%-18.53%-10.60%
c32+23.55%-40.42%-20.24%
c64+26.08%-31.49%-21.30%

这说明多阶段系统的 data plane 不是“胶水代码”,它本身就是性能路径。

另一个很小但很典型的工作是 #1384:以前每个 outbox message 都做一次 run_in_executor();现在一次 blocking wakeup 后最多顺手 drain 63 条 ready message,而且不额外等待凑 batch。

C16 上:

  • TTFT p95 -8.9%;
  • TTFA p95 -17.1%;
  • output throughput +4.4%;
  • audio xRT +4.2%。

这类优化非常适合放在“调度器/消息通路”层,而不是误判成 GPU kernel 问题。

11.3 Talker predictor:正确的 micro-optimization 也可能 E2E-neutral

Section titled “11.3 Talker predictor:正确的 micro-optimization 也可能 E2E-neutral”

#1164 是一个很漂亮的底层例子。

Qwen3-Omni predictor 是约 16-step 的 AR loop;以前 GQA attention 会显式 _repeat_kv,每个 talker token 大约产生:

5 layers×(K+V)×16 steps=1605\ \text{layers} \times (K+V) \times 16\ \text{steps} = 160

个额外 copy kernels。

PR 直接用 PyTorch SDPA 的 enable_gqa=True,让 KV broadcast 在 attention kernel 内完成:

  • 每 frame 精确少 160 个 copy kernel;
  • predictor graph replay 提升约 3.7%~3.9%;
  • codec token 与 waveform 做到了严格一致验证。

但是 full E2E c8 基本在噪声带内:吞吐约 -0.57%、TTFA 约 -2.15%,没有可辩护的整体提升。

这是本文最重要的 Amdahl 案例之一:

microbenchmark 上机制完全成立、kernel 数也精确减少,并不代表它已经位于 E2E critical path。

11.4 Code2Wav:先稳定 shape,再谈 batch + CUDA Graph

Section titled “11.4 Code2Wav:先稳定 shape,再谈 batch + CUDA Graph”

Qwen3-Omni 的 Code2Wav 工作对 CosyVoice 的 Vocoder 很有参考价值。

#1101 先做最保守的 exact-shape CUDA Graph:只捕获 serving 中可达的 B=1, T∈{10,20,30,35} 四种窗口,unsupported shape 和 final tail 继续 eager。

结果在 H100/H200 上大致是:

  • request throughput +8%~12%;
  • audio xRT +7%~12%;
  • latency p50 -6%~11%;
  • TTFA 基本不变,因为优化发生在首个音频之后的 steady-state decode。

接下来 #1237 解决了一个更深的问题:普通 dynamic batching 会因为每条请求积累的 frames 不同而产生 shape churn,batch 根本凑不起来,同时又失去 serial CUDA Graph 的收益。

它的做法不是“多等一会儿凑 batch”,而是先把执行单位正规化:

variable backlog
↓
每次只消费一个固定 stream_chunk_size
↓
uniform windows
↓
B1/B2/B4/B8 × fixed T buckets
↓
batched CUDA Graph replay

这就是 chunk-aligned dispatch。

生产显存预算下:

  • zero-wait 在 c8+ 的 xRT 提升约 +11%~15%,TTFA 基本持平或更好;
  • heavy-wait 在 c16+ 可达到 +41%~55%;
  • 但 c1/c8 heavy-wait 会退化约 4%~9%。

所以真正的结论是:

batching 的前提不是“有并发”,而是“请求能在同一个 shape contract 上相遇”。先稳定 shape,再设计 wait/floor policy。

这与 CosyVoice #1844 的做法形成了很好的对照:

问题CosyVoice HiFT #1844Qwen3-Omni Code2Wav #1237
输入变长允许变长,按 padding waste 分组主动把每步工作量对齐成固定 chunk
合批手段right paddingchunk-aligned dispatch
主要目标提高 HiFT batch utilization同时保住 batching 与 CUDA Graph
风险padding 改变短样本边界语义graph 显存预算、wait policy、低并发退化

11.5 Output overlap:隐藏 D2H 不等于可以推迟输出

Section titled “11.5 Output overlap:隐藏 D2H 不等于可以推迟输出”

#1567 把 Code2Wav 每个窗口后的同步 .cpu() 改成:

CUDA Graph replay N
↓ same stream
fp32 convert
↓
async D2H → pinned slot + CUDA event
↓
CPU scheduler 去做别的事
↓
Event ready 后再发 chunk

同时把每 frame 一次的 codec EOS .item() sync 改成每 window 一次的 batched scan。

机制级结果非常明显:

  • Code2Wav scheduler thread p50 occupancy:约 9 ms → 0.65 ms(c1),-93%;
  • consecutive graph launch 之间的 blocking CUDA API:约 32 ms → 1.95 ms,-94%;
  • cudaStreamSynchronize 总时间几乎被消掉。

但这个 PR 更值得学习的是它的第一次设计犯过的错误:最初把 window N 的结果拖到 window N+1 到达时才发,虽然 scheduler stall 下降了,却让 inter-chunk latency p95 恶化 28%~49%。

最终方案改成每个 talker frame 都 Event.query(),第一个观察到 copy 完成的 frame 立即发出去。

这说明 streaming 系统必须单独测:

  • TTFA;
  • inter-chunk latency / ITL;
  • steady-state xRT;
  • E2E latency。

只看“线程不阻塞了”甚至“throughput 变高了”都可能掩盖 streaming 体验回退。

11.6 #1022 最值得复用的是它的工程方法,而不只是 PR 列表

Section titled “11.6 #1022 最值得复用的是它的工程方法,而不只是 PR 列表”

#1022 / #1018 有几个非常值得直接搬到 CosyVoice/Index-TTS/MiniMax-Music 调研流程里的原则:

  1. Tracker 与 evidence 分离:#1022 只管 ownership/status,#1018 保存 benchmark、gate、negative result;
  2. 先 correctness 再 performance:例如先修 mixed-batch KV cache correctness,再讨论 admission;
  3. 每个优化声明具体 gate:输出一致性、TTFT/TTFA、RTF、吞吐、显存、失败率都明确;
  4. 保留 negative results:compile switch 无效、某些 batching policy 低并发退化、E2E-neutral 都不隐藏;
  5. micro 与 E2E 分开汇报:predictor replay +3.9% 可以成立,同时明确 E2E-neutral;
  6. 调度器也要 profile:queue、event loop、relay、payload conversion 都是正式性能对象。

截至 2026-09-08,#1022 仍在推进 partial-start threshold、异步 output construction、chunk-boundary message batching、encoder batch wait、CUDA-graph shape telemetry、preprocessing 并行、hybrid Thinker prefill routing、Code2Wav BF16/fusion、exact EOS graphs 与 Thinker speculative decoding 等工作。

因此如果要把 CosyVoice3 的 #1652 做成一个更成熟的性能工程 tracker,最值得借鉴的不是某一个 CUDA Graph PR,而是 #1022 这种**“stage × mechanism × evidence gate”** 的组织方式。


对于 CosyVoice、Index-TTS、MiniMax-Music 一类多阶段生成系统,可以把优化方法压缩成:

先拆 runtime,再做单阶段加速;先把 streaming/batching 做成 pipeline,再优化 scheduler;稳定 shape 后再谈 CUDA Graph / engine;最后才用蒸馏、LoRA 和 kernel fusion 去继续压极限。所有改动都必须回到真实并发下的 TTFA、ITL、p95/p99 RTF 与质量约束验证。