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 优化。
1. 先建立正确的系统模型
Section titled “1. 先建立正确的系统模型”CosyVoice3 这类语音生成系统不是单一 Transformer,而是一条多阶段 pipeline:
reference audio ↓S3-Tokenizer / speaker encoder ↓AR model(文本/语义 token 自回归生成) ↓DiT / Flow Decoder(多步连续生成) ↓HiFT Vocoder(波形生成) ↓audio stream这带来一个非常关键的结论:
局部最快 ≠ 端到端最快。
如果 AR、DiT、Vocoder 的生产/消费速率不匹配,某一阶段即使独立 benchmark 变快,也可能只是把排队压力推给下游。
因此优化顺序应该是:
- 先测每个 stage 的真实运行时间;
- 再做单阶段工程优化;
- 然后做 batch / chunk / streaming;
- 最后把所有 stage 放回同一个调度器里看 p50/p95/p99 RTF;
- 在工程瓶颈解决后,再考虑蒸馏、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 阶段更应该回答:
- 它是不是实际瓶颈?
- 多 reference audio 是否真的同时存在?
- cache / single-flight 是否已经让重复工作消失?
- CPU 与 GPU 之间是否有更大的准备/同步开销?
4. AR:把它当成标准 LLM Serving 问题
Section titled “4. AR:把它当成标准 LLM Serving 问题”CosyVoice3 的 AR stage 本质上仍然是自回归 Transformer,因此大量成熟的 LLM serving 技术可以直接复用。
4.1 Streaming output
Section titled “4.1 Streaming output”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 尽早填满”。
4.2 Continuous batching
Section titled “4.2 Continuous batching”多请求下,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.compilefor DiT backbone;- TensorRT acceleration;
- flow auto-cast bug 修复;
- 可选的 step-distillation。
5.1 Batch inference
Section titled “5.1 Batch inference”DiT 通常比 AR 更“GEMM-friendly”。多个请求同时进入 DiT 后,batching 可以明显提高 Tensor Core 利用率。
但 batch size 不能只看单 stage throughput,需要同时考虑:
更大 batch → 更高 GPU utilization → 更长排队时间 → 更差 first-chunk latency / p99 RTF所以 scheduler 需要在 throughput 与 latency 之间做动态平衡。
5.2 Chunk-wise inference
Section titled “5.2 Chunk-wise inference”Streaming 的核心不是简单把 tensor 切小,而是要保证:
- chunk 能独立或近似独立地推进;
- 边界条件正确;
- 上下文依赖被保留;
- 音质不因为 chunk 过小而明显下降;
- chunk 足够小,首包延迟才会下降。
chunk size 实际上是一个系统参数:
小 chunk:低延迟、高调度/launch 开销、GEMM 更小大 chunk:高吞吐、高首包延迟、batch 更容易做大5.3 torch.compile 与 TensorRT
Section titled “5.3 torch.compile 与 TensorRT”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 原本需要 个 flow/ODE steps,纯工程优化只能让每一步更快;step distillation 则直接尝试把:
这意味着总 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。
因此优先级通常是:
- Batch inference;
torch.compile;- 有稳定 shape 后再考虑 TensorRT;
- 再看卷积、激活、重排、上采样等 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_imel_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时,约束近似为
- 多条 mel right-pad 成一个
[B, 80, T_max]后只跑一次 HiFT; - 根据
hop_len \times \prod upsample_rates推导 mel→wave 的 stride,再裁回每条真实长度; - 加载阶段 fold 掉
weight_normparametrization,避免 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 越大越好”。
7.1 一个简单的优化目标
Section titled “7.1 一个简单的优化目标”设请求 的音频长度为 ,端到端延迟为 :
线上通常关心:
同时满足:
以及质量约束:
于是 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 被击穿。
建议每次改动都记录:
| 指标 | Baseline | Optimized | Delta |
|---|---|---|---|
| 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 反复尝试之前已经证明无效的优化路径。
10. 如何理解上游 #1652 Roadmap
Section titled “10. 如何理解上游 #1652 Roadmap”截至 2026-09-08,上游 Issue 展现出的方向非常清晰:
| Stage | 主要方向 | 系统意义 |
|---|---|---|
| S3-Tokenizer | multi-thread / batch | 让 reference encoding 不阻塞主路径 |
| AR | streaming / overlap | 尽快把 token 交给下游,并尝试隐藏阶段间空洞 |
| DiT | batch / chunk / compile / TensorRT | 同时优化吞吐、streaming 与单步执行效率 |
| DiT algorithm | step distillation / LoRA | 从根本上减少 flow steps |
| Vocoder | batch inference | 提升下游消费速率,避免 streaming queue 堵塞 |
| General | kernel fusion | 在确定热点后继续压缩算子开销 |
| NPU | Ascend support | 把同一套多阶段运行时模型迁移到不同硬件 |
其中很值得注意的两个结果是:
- S3-Tokenizer batch inference:tested no effect;
- AR overlap schedule:tested no effect。
它们并不是失败的优化,而是在告诉我们:
多阶段生成模型中,最重要的不是“优化技术有没有用”,而是“它是不是当前 critical path”。
这也是这份 Roadmap 最值得学习的地方。
11. Related Work:Qwen3-Omni #1022 是更完整的多阶段 serving 样板
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 streamTalker AR + code predictor ↓ codec framesCode2Wav ↓audio stream但系统问题高度同构。#1022 把工作分成四类:
- Thinker:并发正确性、admission、prefill CUDA Graph、多模态 merge / M-RoPE、mixed prefill/decode;
- Pipeline handoff:stage 之间尽早启动、减小 payload、减少 event-loop / relay 开销;
- Talker / predictor:采样状态复用、GQA attention、device-resident state;
- 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 上,它在高并发下的收益非常明显:
| Concurrency | QPS | Audio TTFP mean | RTF 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 大约产生:
个额外 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 #1844 | Qwen3-Omni Code2Wav #1237 |
|---|---|---|
| 输入变长 | 允许变长,按 padding waste 分组 | 主动把每步工作量对齐成固定 chunk |
| 合批手段 | right padding | chunk-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 streamfp32 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 调研流程里的原则:
- Tracker 与 evidence 分离:#1022 只管 ownership/status,#1018 保存 benchmark、gate、negative result;
- 先 correctness 再 performance:例如先修 mixed-batch KV cache correctness,再讨论 admission;
- 每个优化声明具体 gate:输出一致性、TTFT/TTFA、RTF、吞吐、显存、失败率都明确;
- 保留 negative results:compile switch 无效、某些 batching policy 低并发退化、E2E-neutral 都不隐藏;
- micro 与 E2E 分开汇报:predictor replay +3.9% 可以成立,同时明确 E2E-neutral;
- 调度器也要 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”** 的组织方式。
12. 一句话方法论
Section titled “12. 一句话方法论”对于 CosyVoice、Index-TTS、MiniMax-Music 一类多阶段生成系统,可以把优化方法压缩成:
先拆 runtime,再做单阶段加速;先把 streaming/batching 做成 pipeline,再优化 scheduler;稳定 shape 后再谈 CUDA Graph / engine;最后才用蒸馏、LoRA 和 kernel fusion 去继续压极限。所有改动都必须回到真实并发下的 TTFA、ITL、p95/p99 RTF 与质量约束验证。
References
Section titled “References”- SGLang-Omni #1652: Optimization for CosyVoice3
- SGLang-Omni #1844: CosyVoice3 Vocoder acceleration
- SGLang-Omni #1022: Qwen3-Omni Serving Optimization Tracker
- SGLang-Omni #1018: Qwen3-Omni Serving Optimization Roadmap
- SGLang-Omni #1381: Qwen3-Omni Breakable Prefill CUDA Graph
- SGLang-Omni #1574: Thinker→Talker stream payload optimization
- SGLang-Omni #1384: Pipeline outbox drain
- SGLang-Omni #1164: Predictor SDPA GQA
- SGLang-Omni #1101: Code2Wav exact-shape CUDA Graph
- SGLang-Omni #1237: Chunk-aligned batched Code2Wav CUDA Graph
- SGLang-Omni #1567: Code2Wav output overlap
- SGLang-Omni
- SGLang