M*:多模态模型的推理,应该怎样交给运行时?

笔记日期: 2026-10-15
论文题名: M*: A Modular, Extensible, Serving System for Multimodal Models
论文作者: Atindra Jha, Naomi Sagan, Keisuke Kamahori, Irmak Sivgin, Rohan Sanda, Steven Gao, Mark Horowitz, Luke Zettlemoyer, Olivia Hsu, Jure Leskovec, Baris Kasikci, Stephanie Wang
论文标识与版本: arXiv:2606.12688v2,2026-06-13 修订,初稿提交于 2026-06-10
资源: 论文与附录 · 官方资源入口

1. 先换一个问题:运行时到底需要看见什么?

如果只服务文本模型,系统经常可以围绕两件事组织:先处理提示词,再不断生成下一个 token。多模态模型却未必沿着这条简单路径运行。一次图片编辑,可能先编码图片、预填充 Transformer,再反复执行多条引导分支、合并结果、更新图像潜变量,最后交给 VAE 解码。一次语音请求则可能让 Thinker、Talker 和音频解码器同时推进,后一个组件不必等前一个组件完全结束。

M* 关心的是:这些执行结构怎样被服务系统理解?它提出的 Walk Graph,把模型组件之间的张量依赖、不同任务经过的路径、循环和并行关系表达出来,再把物理设备放置单独交给部署配置。模型作者负责计算含义,运行时负责批处理、缓存、调度和传输。系统不必理解“这段声音说了什么”,却必须知道“这个消费者还缺哪些输入、当前属于第几轮、能不能开始下一块”。

这篇论文值得读的地方是接口边界。接口过粗,优化机会藏在组件内部,运行时看不见;接口过细,调度与协调本身又可能变成负担。M* 选择以模型组件的一次前向为重要边界,让图像生成、语音生成和世界模型循环复用服务系统已有的优化。它展示了多类模型上的收益,但并未证明所有未来模型都能零成本接入,也没有证明一份设备配置对所有流量都最优。

本笔记依据 20 页 v2 全文和附录。引用的论文原图来自 Jha 等作者,按论文的 CC BY 4.0 许可注明来源。下文标为“解释性”的公式、算法和示意图是为阅读而作的推导,不是论文新增实验,也不是作者逐字给出的算法。实验数值均属于原论文报告;我会把它们与自己的分析分开。

复合多模态模型的执行结构

图 1. 论文原图 1,截取自第 3 页。BAGEL 的图像循环与 Qwen-Omni 的语音流水线需要不同的依赖表达。图中箭头代表计算结构,不能直接当成固定的 GPU 分工。来源:Jha 等,arXiv:2606.12688v2,CC BY 4.0。

2. 前置知识:图、状态和指标是三件不同的事

2.1 计算图并不等于执行时间表

计算图回答“某个操作需要哪些输入”。设备调度回答“它在哪张卡上、什么时候、和哪些请求一起执行”。同一张逻辑图可以全部放在一张 GPU 上,也可以拆到多张卡,或者复制其中的某些组件。把这两层分开,部署拓扑变化时才不必重写模型控制逻辑。

例如,把整个扩散引擎当成一个 stage,接口很简单,但一次 stage 调用可能包含几十次迭代。系统看不到每次迭代的边界,就难以在边界处加入其他请求。反过来,若连每一个矩阵算子都交给通用分布式调度,控制开销可能抵消算子本身的收益。M* 的组件级粒度处在两者之间:它不是越细越好的主张,而是希望暴露足够多、又仍然可高效执行的信息。

循环也不能简单等同于普通 DAG。固定次数循环确实可以展开成很长的无环图,但展开会重复结构,并让跨轮共享状态更难表达。生成到 EOS 为止的动态循环尤其需要明确的结束规则。即使每一轮调用的节点名称相同,运行时仍必须分清请求编号和迭代编号,不能把上一轮的输出误送到下一轮尚未满足的输入槽位。

2.2 KV 缓存、CUDA Graph 和连续批处理各自解决什么?

KV 缓存保留不变前缀的键和值,避免重复计算。分页缓存进一步把这些状态按块组织,让不同长度的请求可以独立增长,减少内存分配浪费。它不意味着所有中间张量都能跨轮复用。图像潜变量每一轮改变时,依赖该潜变量的状态可能需要重算;固定条件前缀则可能继续有效。能否缓存取决于数学依赖,不取决于模型被叫作语言模型还是世界模型。

CUDA Graph 则主要减少重复的 GPU 启动开销:先记录一组兼容的执行操作,再在形状和存储条件允许时回放。它不会自动创造分支并行,也不会替模型解决任意动态形状。连续批处理解决的是请求生命周期不齐的问题:在迭代边界处,新请求可以进入,已结束请求可以退出,不必等整批请求一起完成。

这三类机制可以同时存在,但因果关系不能混写。一次加速可能来自少算了前缀、少发了 kernel,也可能来自更少的等待。理解 M* 时,要问接口让哪种优化变得可复用,而不能把所有收益都归结为“用了图”。

2.3 语音指标最容易混淆

文本常看首 token 延迟和吞吐量;图像常看端到端完成时间。语音还需要考虑播放能不能持续进行。论文使用 RTF,也就是处理时间与生成音频时长的比值,并报告每秒墙钟时间能生成多少秒音频:

RTFi=TiprocessingDiaudio,Qaudio=∑iDiaudioTwindow.(1)\mathrm{RTF}_i=\frac{T_i^{\mathrm{processing}}}{D_i^{\mathrm{audio}}},\qquad Q_{\mathrm{audio}}=\frac{\sum_i D_i^{\mathrm{audio}}}{T_{\mathrm{window}}}. \tag{1}

RTF 小于 1,说明整体处理速度快于音频播放速度,但不能单独保证流畅播放。第一段声音仍可能很晚才到;中间也可能出现长空档,再靠最后一段集中产出把平均值拉回来。因此,还要看首音频延迟和分块到达是否赶上播放截止时间。并发负载下,p50 RTF 的倒数也不等于整体音频吞吐量,两者的统计对象不同。

3. Walk Graph:模型行为和物理部署分开描述

论文把模型写成计算图与一组具名 Walk 的组合。一个 Walk 对应请求的一段行为,例如文本预填充、图像预填充、文本解码或图像生成。模型作者再提供状态机,根据输入模态及当前 Walk 的结果,决定接下来走哪一段。运行时不需要硬编码“图片编辑请求接下来必然干什么”,而是执行状态机选出的结构。

为了把职责讲清楚,可以用下面这组解释性记号:

G=(N,E),W={w1,…,wm},δ(r,w,o)=wnext.(2)G=(N,E),\quad \mathcal W=\{w_1,\ldots,w_m\},\quad \delta(r,w,o)=w_{\mathrm{next}}. \tag{2} π(n,w)⊆R.(3)\pi(n,w)\subseteq\mathcal R. \tag{3}

GG 表示节点和边,W\mathcal W 是具名路径集合;δ\delta 根据请求、当前路径和输出选择下一条路径。π\pi 则把节点以及可选的路径条件映射到 GPU rank 集合。前者决定“要算什么”,后者决定“放在哪里”。这些式子是帮助理解职责的形式化,不是对全部 API 行为的完整定义。

四个组合原语分别是 Sequential、Parallel、Loop 和 DynamicLoop。Sequential 串联子图;Parallel 表示子任务允许并发;Loop 表示有界循环;DynamicLoop 增加每个请求独立提前结束的能力。GraphNode 和 GraphEdge 是基础计算单元与张量连接。StreamingGraphEdge 给边增加流式输入策略,不应把它与上述四个组合原语混算成同一类五个原语。

这里有两个细节很重要。第一,Parallel 只说明依赖关系允许并行;如果几条分支实际都在同一张忙碌的卡上,物理执行仍可能受限。第二,循环的“只输出最后一轮结果”与“累积所有轮结果”必须区分。附录 B 把两类通道分开命名:前者只把最终张量交给下游,后者保留并拼接每轮贡献。把两者混淆,既可能算错,也可能让显存需求从常数级状态增长为随轮数累积。

逻辑路径和 GPU 执行的关系

图 2. 论文原图 2,第 4 页。左边描述模型路径,右边描述组件如何交给 Worker。该图展示设计关系,不是每个实验的精确设备配置。来源:Jha 等,CC BY 4.0。

算法 1:按依赖推进一个请求

下面的编号伪代码根据论文第 3 节重述主要语义,省略具体传输协议、内存所有权及故障恢复。为了代码块在中英文 PDF 中稳定排版,伪代码使用英文关键句。

01  Choose the initial named walk from the request modalities.
02  Initialize node inputs, loop state, and per-edge stream buffers.
03  Until the request is complete:
04      Find nodes with all dependencies and chunk conditions satisfied.
05      Map ready nodes through placement(node, walk).
06      Batch compatible work for the selected engines.
07      Execute; tag outputs with the request and iteration identity.
08      Route outputs to successors or append to stream buffers.
09      At a loop boundary, retain or accumulate outputs as declared.
10      Advance the loop, or leave it when its stop rule is satisfied.
11      At walk completion, let the model state machine choose the next.
12      Emit final outputs and release state after its last use.

正确性的核心不是“生产者算完就调消费者”,而是消费者的全部依赖是否属于同一请求、同一逻辑迭代,并且已经齐备。有些节点需要三条分支都完成,有些节点需要一个完整音频块。一个 Walk 结束,也不代表所有请求状态都该释放,后续 Walk 可能还会复用前缀缓存。图接口减少模型专用调度逻辑,靠的是把这些边界显式化,而不是省略它们。

4. BAGEL:循环内部还有并行分支

BAGEL 同时处理图像理解、图像生成和图像编辑,多个任务共享 Transformer 主干,但经过的编码器、输出头和迭代方式不同。M* 把它们描述成共享组件上的不同 Walk。这样,部署者可以保留同一个主干实例,同时让不同请求选择需要的计算路径。

带引导的图像生成可以分为四步:把当前潜变量送进多条条件分支;等待各分支结果;执行引导组合与 Euler 更新;将更新后的潜变量送回下一轮。循环结束后才调用 VAE 解码器。论文附录 F 的代码把更新次数写为 num_timesteps - 1,即 49 次 Euler 更新;实验描述使用 50 步 flow schedule。这里要区分时间网格点与相邻点之间的更新区间,不能直接把它们解释成矛盾的 49 或 50 次同一种操作。

如果用 vbv_b 表示各分支输出、aba_b 表示配置中的组合系数,一个简化的解释性形式是:

vguided=∑b=1Babvb,zk+1=zk+Δtkvguided(zk,tk).(4)v_{\mathrm{guided}}=\sum_{b=1}^{B}a_bv_b,\qquad z_{k+1}=z_k+\Delta t_kv_{\mathrm{guided}}(z_k,t_k). \tag{4}

这个式子只用于解释分支合并与循环状态,不是完整 BAGEL 引导公式。论文实验还涉及引导重归一化,具体数值规则属于模型组件。运行时需要知道的是 fan-out、join 和回边:哪些结果要齐备,谁更新潜变量,什么时候可以进入下一轮。

并行收益也有清晰的边界。设各分支耗时为 t1,…,tBt_1,\ldots,t_B,合并更新耗时为 uu,额外通信调度耗时为 cc。串行与理想并行的关键路径可以写成:

Tserial=∑b=1Btb+u,Tparallel≥max⁡btb+u+c.(5)T_{\mathrm{serial}}=\sum_{b=1}^{B}t_b+u,\qquad T_{\mathrm{parallel}}\geq\max_b t_b+u+c. \tag{5}

从两式相减可以看到,真正可节省的是“其他分支原本占用的串行时间”,再扣掉协调成本。一条特别慢的分支会成为下限;通信很重时,多卡也可能得不偿失。此外,多张卡可能复制权重和条件状态。因此延迟更低,不代表每张图像的 GPU 秒数也更低,成本结论需要另算。

算法 2:带引导的图像生成 Walk

01  Prepare conditioning state and the initial latent z.
02  For each scheduled Euler update k:
03      Send z and the time index to all required guidance branches.
04      Evaluate each branch using its conditioning context.
05      Join only after all required branch outputs arrive.
06      Apply the model's guidance combination and renormalization.
07      Update z and carry it to iteration k+1.
08  Decode the final latent with the VAE decoder.
09  Emit the image and release state after downstream consumption.

论文还解释了另一个收益来源:将三种 CFG 上下文作为同一个分页 KV 池中的不同标签,而不是分别维护模型专用的稠密缓存。标签是缓存身份的一部分,不表示三个条件上下文的 K、V 内容相同。其价值在于不同上下文都能使用分页等公共机制,避免每层、每步反复拼接张量。这里能看见接口设计怎样帮助性能:原本封装在专用状态管理里的工作,被接入了成熟的缓存路径。

5. 流式边:什么时候“够一块”也是调度语义

Thinker 输出一个隐藏状态后,Talker 可能就能前进一步;音频解码器却可能需要攒够若干 codec 帧,还要带上一段左侧上下文。若系统只提供一种统一的“有输出就触发”,就可能让某些组件等待过久,或者让另一些组件拿到不完整的上下文。

M* 把决定何时触发消费者的规则放在边上。固定块策略每 KK 个元素触发一次;滑动窗口策略等到 WW 个元素后,以 SS 为步长推进;左上下文策略为每 CC 个新帧补上 LL 个旧帧。Qwen3-Omni 的 Thinker 到 Talker 使用大小为 1 的固定块,Talker 到 Code2Wav 使用左上下文策略。传输基础设施可以相同,准备输入的规则则由策略表达。

固定块、滑动窗口和左上下文

图 3. 本笔记自绘示意图。绿色表示新发出的块,橙色表示重叠窗口或保留上下文;图中的参数仅为解释性示例,不是论文实验配置。

固定块在收到 nn 个元素后,完整块数是 ⌊n/K⌋\lfloor n/K\rfloor。但流结束时的残余元素如何处理,需要另外定义:可能补齐、单独处理,也可能依模型规则采用其他办法,不能从原语名字推断。最后一块处理错误,往往不会表现为调度死锁,而会表现为尾部音频丢失、重复或不连续。

滑动窗口的计数可以逐步推出。先等 WW 个元素得到第一个窗口;之后每增加 SS 个元素再得到一个窗口,因此:

Nwindows(n)={0,n<W,1+⌊n−WS⌋,n≥W.(6)N_{\mathrm{windows}}(n)= \begin{cases} 0,&n<W,\\ 1+\left\lfloor\dfrac{n-W}{S}\right\rfloor,&n\geq W. \end{cases} \tag{6}

当 S<WS<W 时,重叠是有意的。在消费者计算量近似与输入长度成正比的简化模型里,长序列中每个新元素平均要承担约 W/SW/S 个位置的处理量。重叠能保留上下文,也增加重复计算,真实解码器未必严格线性,但这个计数能提醒我们:更细的流式粒度不是免费的。

左上下文策略也有类似代价。稳定阶段每增加 CC 个新帧,消费者处理 C+LC+L 个输入帧,输入工作量放大系数近似为:

Acontext≈C+LC=1+LC.(7)A_{\mathrm{context}}\approx\frac{C+L}{C}=1+\frac LC. \tag{7}

若生产间隔近似为 Δ\Delta,从一个块的首个新帧到完整块形成,大约要等 (C−1)Δ(C-1)\Delta,之后再加消费者排队和计算时间。减小 CC 可以缩短攒块等待,但会增大相对上下文开销、调用频率和传输次数。块大小应由播放需求、消费者效率和链路开销共同决定。

算法 3:带上下文的流式就绪判断

01  Append each arriving frame to this request's edge buffer.
02  Ask the chunk policy whether a valid consumer input can be formed.
03  Select its new frames and any required retained context.
04  Dispatch when the consumer's other dependencies are also ready.
05  Advance the logical position according to the chunk policy.
06  Keep only frames required by future windows or left context.
07  At end of stream, resolve the final fragment using model rules.
08  Close the edge after all outstanding consumer work finishes.

缓冲区还带来容量问题。若生产速率 λ\lambda 长期高于消费速率 μ\mu,即使每一次计算都正确,队列仍会增长。简化流体模型中,非空队列的增长速度约为 λ−μ\lambda-\mu。稳定服务需要足够容量、限流或反压。论文提供了容纳这些策略的执行结构,但不能据此声称已经验证所有流式应用在过载下的内存上界和服务质量。

6. Placement:把选择暴露出来,不代表选择已经做好

M* 允许把一个节点放到一个或多个 rank 上,也允许同一节点在不同 Walk 使用不同 rank。于是预填充和解码可以分离,某个组件可以独立扩容,频繁交换小张量的组件也可以共置。张量并行在节点级配置,不过模型作者仍需使用系统提供的分片层;这不是随便写一个 TP 数字就能自动分布式执行任意模型。

把两个组件拆到不同设备,可能提高并发和独立扩容能力,同时也增加传输成本。一个简单模型是:

Ttransfer=α+Btensorβ.(8)T_{\mathrm{transfer}}=\alpha+\frac{B_{\mathrm{tensor}}}{\beta}. \tag{8}

α\alpha 是固定开销,BtensorB_{\mathrm{tensor}} 是字节数,β\beta 是有效带宽。很多很小的流式块,可能主要付的是固定开销,而不是带宽成本。把块合并能摊薄开销,却增加等待;把组件放在一起能减少进程或传输边界,却让它们争用同一设备的计算和内存带宽。

论文的 Qwen3-Omni 双卡实验把 Thinker 放在一张 H200,Talker 与 Code2Wav 放在另一张。关键是后两者共置,而不是 rank 必须叫 0 还是 1。正文与附录对数字标签的叙述互换,不影响拓扑本身。附录 A 另有三个分区各自放置的抽象示例,它不是双卡实验的精确配置,不能把两者拼接成一套自相矛盾的设备数。

规划还必须满足显存约束:权重、活跃 KV、激活、流式缓冲区、图回放工作空间都要算进去,只统计模型参数不够。请求类型与长度分布变化,活跃状态和瓶颈也会变化。因此 M* 首先解决“能表达哪些部署”,自动搜索高质量部署是另一项问题。今天加入后续阅读的 Cornfigurator 正好补上这个方向。

7. 运行时:隐藏准备开销,但不能越过依赖

论文的结构包括 HTTP 入口、维护请求 Walk 状态的 Conductor,以及每张 GPU 对应的单进程 Worker。控制工作通过 ZeroMQ 分发,张量可以在 Worker 之间直接流动。数据面支持共享内存以及 Mooncake 提供的传输方式;不过本文实验实际使用单机共享内存,不能把 RDMA 支持直接当成跨机加速结果。

Worker 可以承载多个 engine。论文将有状态 Transformer 路径称为 KVCacheEngine,将简单无状态组件交给 StatelessEngine;二者复用连续批处理、CUDA Graph 和编译。Worker 的本地调度采用 round-robin。轮流运行容易理解,但“每个 engine 轮到一次”不等于“每个请求占用同样时间”:一个图像迭代可能比一个语音步骤长得多,公平性与截止时间保证还要单独分析。

一个重要优化是让 CPU 准备第 N+1N+1 批时,GPU 仍在执行第 NN 批。论文特别提到对 FlashInfer attention plan 使用双缓冲,并在独立线程和 CUDA stream 上准备下一份计划。调度既推进当前 Walk 中可预期的后续工作,也处理已经就绪的无关请求,以减少队头阻塞。

CPU 准备与 GPU 计算重叠

图 4. 本笔记自绘时间线。数字表示批次,横轴使用虚构时间单位,仅说明准备与计算如何重叠,不是 M 的真实 profiler 结果。*

设每批 CPU 准备耗时 cc,GPU 执行耗时 gg。完全串行时,NN 批要花 N(c+g)N(c+g)。理想重叠后,首批仍要先准备再执行,后续每批受较慢阶段约束,于是:

Tserial(N)=N(c+g),Tpipe(N)=c+g+(N−1)max⁡(c,g).(9)T_{\mathrm{serial}}(N)=N(c+g),\qquad T_{\mathrm{pipe}}(N)=c+g+(N-1)\max(c,g). \tag{9}

将两者相除,再令批次数很大,可以得到:

S∞=c+gmax⁡(c,g)≤2.(10)S_{\infty}=\frac{c+g}{\max(c,g)}\leq2. \tag{10}

这个上界只针对“把这两个原本串行的阶段重叠”这一项优化,不是整个系统的加速上限。系统若另外减少了重复计算,当然可能超过两倍。反过来,如果 GPU 计算远大于 CPU 准备,能隐藏的时间就很有限,不能把很大的端到端加速全部解释为异步调度。

理想重叠的收益边界

图 5. 本笔记的解析示例。取 c=4c=4、g=6g=6 个任意时间单位,理想加速随批次数增多趋近 10/6≈1.6710/6\approx1.67;短任务还受启动开销影响。这里没有使用 M 实测数据。*

DynamicLoop 让预先准备更微妙:当前一轮还没返回,下一轮可能已经开始准备,但当前结果可能意味着应该停止。论文把终止判断推迟到下一边界,因此每次停止最多浪费一步,并允许按节点禁用这种推测。这是执行调度的推测,不是草稿 token 接受机制,也不应把多算出的输出暴露给用户。

可以用一个局部期望成本来理解:每次预先准备隐藏 hh 的 host 工作,结束概率为 pp,多算一步成本为 gextrag_{\mathrm{extra}},忽略资源竞争时,收益条件近似为 h>pgextrah>p g_{\mathrm{extra}}。长循环多数边界不会停止,可能值得做;短循环或昂贵步骤则未必。若操作有外部可见副作用,额外一步甚至不是性能问题,而是语义上不允许。能够禁用因此是设计的一部分,不是无关紧要的开关。

8. BAGEL 实验:一定要说清楚相对哪个基线

BAGEL 的评估包括文生图、图像编辑和看图生成文本。生成任务采用 1024 尺度的图像输出与 50 步 flow schedule;三卡版本把 CFG 分支分给三张 H100;图像理解实验则使用一张 H100。它们都属于 BAGEL,但不是同一套硬件配置,不能把不同子任务的结果混成“同一系统在同一资源下统一提升多少”。

论文比较了 vLLM-Omni 的两种配置。默认配置把 Thinker 和扩散阶段分开,单 stage 配置避免了这个边界。图像编辑尤其容易被默认配置中的状态转移拖慢。M* 可以在不同 Walk 之间保留共享组件和缓存路径,因此相对默认配置的优势很大;但单 stage 基线已经去掉一部分明显的转移负担,比较剩余差距时更有参考价值。

BAGEL 三卡图像生成延迟

图 6. 论文原图 3,第 8 页。批大小 1,三张 H100 并行运行 CFG 分支。实心柱为 p50,斜线延伸部分为 p95。来源:Jha 等,CC BY 4.0。

从图中读数,文生图的 p50 约为 M* 6.9 秒、两个基线配置均 8.7 秒。图像编辑约为 M* 6.5 秒、默认基线 17.2 秒、单 stage 基线 8.0 秒。正文给出的精确比例是:相对单 stage,文生图 1.25 倍、图像编辑 1.22 倍;相对默认配置,图像编辑达到 2.64 倍。图上只保留一位小数,因此用图中标签重新相除,与正文比例略有差别是正常的。

“多少倍”和“降低百分之多少”不能混用。设旧耗时为 TbaseT_{\mathrm{base}}、新耗时为 TnewT_{\mathrm{new}},则:

S=TbaseTnew,R=Tbase−TnewTbase=1−1S.(11)S=\frac{T_{\mathrm{base}}}{T_{\mathrm{new}}},\qquad R=\frac{T_{\mathrm{base}}-T_{\mathrm{new}}}{T_{\mathrm{base}}} =1-\frac1S. \tag{11}

1.25 倍对应的是 20% 延迟下降,不是 25%。2.64 倍对应约 62% 延迟下降,但它的分母是代价更高的默认 pipeline。若只摘最大倍数,就会隐藏更强的单 stage 对照,也无法看清究竟有多少收益来自消除原配置的状态转移瓶颈。

图像理解的主实验强制忽略 EOS,让输出长度均匀分布在 64–256 token,避免不同生成长度污染服务效率比较。批大小 16 时,论文报告吞吐量提升 32.7%、每请求端到端延迟下降 25.5%。这种控制实验很有用,却拿掉了自然停止行为;真实对话中的可变长度、提前结束及混合请求,需要另外测量。

附录还报告不使用多卡 CFG 的单 H100 生成结果:文生图相对基线为 1.13 倍;图像编辑相对默认配置 1.66 倍、相对单 stage 1.25 倍。它说明收益并不完全来自分支放到多张卡,缓存与执行组织本身也有作用。但这里仍不是把每个优化逐一开关后的完整消融,不能给各部分精确分配贡献比例。

9. 语音实验:整条流水线比一个语言模型更重要

9.1 Qwen3-Omni 的双 H200 结果

Qwen3-Omni 的 Thinker 产生文本和隐藏状态,Talker 将其变成 codec token,Code2Wav 再生成声音。双卡实验把 Thinker 单独放一张 H200,Talker 与 Code2Wav 共用另一张,使用 Seed-TTS。这个例子很适合检验:图级结构能否与组件级优化同时成立。

Qwen3-Omni 语音服务结果

图 7. 论文原图 5,第 9 页。两张 H200;左图为 RTF,越低越好;右图为每秒墙钟时间生成的音频秒数,越高越好。右图既不是 token/s,也不是请求数/s。来源:Jha 等,CC BY 4.0。

批大小 16 时,论文报告 M* 的音频吞吐量约为 vLLM-Omni 的 2.7 倍、SGLang-Omni 的 4.0 倍。作者主要给出两项解释:其一,组件级 CUDA Graph 捕获可以包含 Talker 内部的多 token predictor 循环;其二,Talker 与 Code2Wav 放在同一个 Worker,减少细碎音频 token 的跨进程交换。加速来自这些具体执行选择,而不是原语名称本身让计算更快。

批大小 32 时,图中右侧终点标注约为 114、42 和 22 音频秒/墙钟秒,依次对应 M*、vLLM-Omni、SGLang-Omni。这组数字不能写成批大小 16 的结果。同样,摘要里最大的 RTF 改善,也不一定与某个吞吐量倍数出现在同一并发点。读图时先固定横轴条件,再比较纵轴,是最基本也最容易被省略的一步。

论文还把 Thinker 做成 2 路张量并行,总计使用三张 H200,与 SGLang-Omni 比较。作者表示无法让相应的 vLLM-Omni 配置正常运行,所以没有给出该对照。缺少结果只能叫缺少证据,不能被当成基线吞吐量为零,更不能把有限配置的比较扩大为所有配置上的支配关系。

9.2 Orpheus 的文字与图存在不一致

Orpheus-3B 对照面向语音的 VoxServe,正文和图注明单张 H200、Seed-TTS,并对五次试验取平均。其逻辑路径是语言模型通过流式边接到 SNAC 音频解码器。作者把收益归因于可复用的模型层优化与异步 attention plan,适合观察通用运行时能否接近甚至超过专用服务系统。

Orpheus 与 VoxServe 比较

图 8. 论文原图 7,第 10 页。批大小 16 的吞吐量标签约为 24.2 与 20.1,相除得到约 20% 提升,与引言写的 39% 不同。此处保留原图,并在正文解释差异。来源:Jha 等,CC BY 4.0。

先看相对一致的部分:批大小 16 的 p50 RTF 约为 0.58 和 0.67,与“下降 13.6%”基本吻合。吞吐量则出现冲突。引言说批大小 16 提高 39%,图中 24.2/20.1 却约为 1.20。批大小 8 的图中值约为 17.5/12.7,提升约 38%,正文第 4.3 节却把该点写为 20%。这看起来像文字中的批大小或百分比发生错配,但仅凭论文无法确定作者原本想表达的对应关系。

因此,本笔记涉及计算时采用图中明确标注的值,并把冲突写出来,不自行交换批大小来“修复”作者实验。稳妥结论是:所展示配置下,曲线整体支持 M* 的优势;精确的文字摘要需要澄清。附录还列出了 Orpheus 两个 rank 的部署描述,而正文和图注明一张 H200,这也不能直接当成该图的精确配置。

这类问题并不要求否定所有结果,但会影响证据强度。系统论文通常有许多配置和基线,若同一结论在摘要、正文、图和附录之间不一致,读者应先固定可定位的数据,再讨论总体趋势。把各处最大数字拼在一起,会得到一套原论文并未真正展示的“综合最优结果”。

10. V-JEPA 2:12.5 倍背后,主要少做了什么?

世界模型实验在单张 H100、批大小 1 上运行 action-conditioned rollout,预测跨度分别为 4、15、30,输入取自 DROID 的前 50 个 episode。根据论文描述,原生基线每一轮都重新处理增长中的前缀,没有 KV 缓存;M* 用 DynamicLoop 表达 rollout,并复用前面步骤的 K、V。

V-JEPA 2 rollout 延迟

图 9. 论文原图 8,第 11 页。纵轴为对数刻度;三个跨度的 p50 标注分别约为 192/400 ms、425/1596 ms、499/6254 ms,前者为 M,后者为原生基线。来源:Jha 等,CC BY 4.0。*

正文给出的加速比分别是 2.08、3.76、12.5。随着跨度增长,避免重复前缀计算的收益自然可能扩大。但这不是 M* 发明新注意力算法的证据,而是一个世界模型循环成功接入成熟缓存机制的例子。这个区别不削弱工程价值,却决定了我们如何理解因果归属。

可以先只数投影工作量。假设初始前缀长度为 PP,每轮追加一个 token 等价位置,基线第 hh 轮重新处理全部前缀,那么总处理位置数为:

Wrepeat=∑h=1H(P+h)=HP+H(H+1)2.(12)W_{\mathrm{repeat}}=\sum_{h=1}^{H}(P+h) =HP+\frac{H(H+1)}2. \tag{12}

如果旧状态始终有效,缓存路径只需处理初始 PP 个位置,再为每轮新位置追加状态,对应约 P+HP+H。但这只是可复用投影的计数,不是整个 attention 的复杂度:每个新 query 仍需读取不断变长的缓存。若每次重算完整因果注意力,将逐步增长的二次成本求和,对 HH 的贡献可能达到三次量级;增量缓存路径则累加每个新 query 对历史的访问,仍有二次贡献。真实运行时间还受内存带宽、kernel 效率、初始编码和固定开销影响,不能用这两个简化计数直接预言 12.5 倍。

缓存有效性本身也有条件。如果世界模型会改写历史状态,使用会改变旧位置表征的双向交互,或在每轮切换导致旧 K、V 不再有效的 mask,那么直接复用就可能改变模型结果。正确的问题是“哪些历史状态在下一轮保持不变”,而不是“这个模型名字里是否有自回归”。运行时可以管理缓存,但模型依赖决定它能否被复用。

若想进一步区分图调度与缓存本身的贡献,更有力的对照是给原生 rollout 加上等价 KV 缓存及相近批处理,再比较剩余差距。现有结果说明相对给定基线的端到端收益很大,但不能把整个 12.5 倍都归因于 Walk Graph 调度器。

11. 设计替代方案:什么时候简单系统反而更合适?

固定 stage pipeline 并不是没有价值。如果模型执行方式稳定,每个 stage 已经有高效引擎,较少的调度边界能降低控制开销,也更容易理解故障与资源归属。它的问题出现在循环跨越 stage、不同请求走不同子路径,或者同一组件需要跨阶段共享状态时。

完全专用的单体引擎可以针对一个模型做跨步骤融合,减少通用分发开销。但每当模型结构改变,缓存、分块和调度可能又要重做。M* 试图在公共执行结构与模型专用数值组件之间找到中间层。这个中间层是否成功,关键在于接口能否表达状态和依赖,而不是把所有模型都强行压成一种数据形状。

record-and-replay 一类方法可从命令式程序中恢复任务依赖,可能更适合接入现有程序。M* 则要求作者事先明确描述结构,让优化器更早看到组件与循环边界。两者在接入成本、分析机会和运行时开销之间取舍。论文讨论 Cornserve 时引用的 2512.14098,目前在 arXiv 上题名已经是 Cornfigurator,后续阅读需按论文 ID 与版本区分,不能把名字相近的系统与规划器当作完全相同的对象。

选择为什么可能有效什么时候可能适得其反
把组件拆到多卡独立扩容、请求间重叠小块调用或状态传输占主导
Talker 与 codec 共置减少进程边界开销同卡争用或显存压力增大
暴露每轮边界复用批处理和调度计算太短,分发成本占比高
增大流式块摊薄传输和调用成本首包变慢、错过播放截止时间
提前准备下一轮隐藏 CPU 准备时间频繁停止导致昂贵的多算步骤

这些都是带条件的取舍。图表达让选择可见,但不会自动提供完美成本模型、过载控制和最优搜索。一个可扩展服务系统的下一步,往往是用真实工作负载识别哪一项成本最值得优化,而不是继续增加抽象层的功能数量。

12. 局限:哪些结论还不能从现有实验推出?

第一,支持范围与量化验证范围不同。论文描述了 BAGEL、Qwen3-Omni、Orpheus、V-JEPA 2 和 π0.5\pi_{0.5},但实际性能图覆盖前四者。不能把“能够表达或接入第五类模型”写成“五类模型都经过同等深度的性能验证”。

第二,全部实测均在单机硬件内,使用共享内存传输和机内 NVLink。跨机后会增加网络时延、带宽竞争、状态迁移和故障恢复等因素。M* 的 placement 接口使这些部署成为可能,实验却没有量化证明跨机时仍能保留相同比例收益。

第三,当前 engine 与三类分块策略覆盖了所测模型,但还不代表覆盖完整多模态空间。附录 H 明确把更多 engine、边策略、sequence/context/pipeline parallelism、先进异步调度以及更多模态专用优化列为后续方向。“接口可扩展”说明未来有接入位置,不等于未知模型接入后一定高效。

第四,实验协议描述有几处需要澄清。正文第 4 节写 5–10 个 warmup,附录 I 写 3–5 个并给出默认 3 个;附录 E 的图 10 标题写输出长度 16–128,邻近文字却写 16–64。再加上前述 Orpheus 的吞吐量及放置描述冲突,读者无法仅凭文字无歧义还原每一项配置。这些问题不抹去整体趋势,但限制了精确比例被直接迁移到部署预估中的可靠程度。

第五,离线分波并发不等于在线生产流量。它适合观察容量,却不能充分覆盖突发到达、图文语音混合请求、取消及过载。共享组件可以节省资源,也可能造成任务间干扰。若长图像步骤阻塞短语音步骤,整体吞吐量仍可能很好,语音体验却已经变差。

第六,生成质量也需要与速度共同评价。贪心设置、相同长度和同一 checkpoint 能减少部分比较偏差,但图像、音频和机器人任务上的广泛输出质量等价性,不是几张延迟图就能证明的。尤其当缓存、执行顺序或分块上下文变化时,应明确哪些转换保持数学等价,哪些仍需要任务级质量证据。

13. 独立批判性分析:表达能力、工程收益和因果归属

13.1 最有说服力的贡献是什么?

我认为最强的证据是:M* 的接口携带了优化需要的信息。循环不是藏在黑盒里的 Python 逻辑,分支汇合有明确依赖,流式消费者有自己的就绪条件,有状态组件可以进入公共缓存机制。多类真实模型能用这套结构表达,且在论文给出的配置下表现有竞争力。这支持“跨模态复用运行时机制”这条系统设计路线。

开发效率的证据则没有同样充分。简洁的图定义很有吸引力,但完整接入还包括数值组件、权重加载、分片、采样、形状约束和状态生命周期。论文没有控制变量地统计接入工时、修改行数或长期维护成本。因此“day-zero support”更适合作为设计目标,不能当成已经量化保证的接入时间。

13.2 不要把所有加速都归到图接口

论文实际同时改变了多个层面:图表达、缓存组织、CUDA Graph 覆盖、组件共置、attention plan 准备和基线配置。完整系统更快是一个端到端结论;到底哪一层贡献多少,则需要匹配条件的消融。V-JEPA 的例子尤其说明,去掉重复前缀计算本身就可能带来很大收益,不必先证明调度器单独更优。

可以把耗时粗分为以下几项:

T=Tuseful+Tredundant+Tlaunch+Tplan+Ttransfer+Tqueue.(13)T=T_{\mathrm{useful}}+T_{\mathrm{redundant}}+T_{\mathrm{launch}} +T_{\mathrm{plan}}+T_{\mathrm{transfer}}+T_{\mathrm{queue}}. \tag{13}

这是解释性的记账模型;当各阶段重叠时,并不能把 profiler 数值机械相加。缓存主要减少重复工作,图回放减少启动开销,异步准备隐藏计划时间,共置减少一部分传输。某个部分降低时,队列等待却可能上升。要归因,就应观察这些项怎样变化,而不是把端到端差值全部贴上抽象名称。

13.3 哪些后续实验最有信息量?

第一项是匹配优化的对照:相同缓存语义、相近 CUDA Graph 覆盖、等价 placement,然后比较通用运行时还有多少代价或收益。即使速度只是持平,如果模型接入与维护确实更容易,也仍然是有价值的系统结果。

第二项是混合负载:同一个主干交替处理文本和图片,同时语音请求有播放期限。此时应看满足服务目标的 goodput,而不是只看平均吞吐量。目标可以定义为:在预先规定的首输出与尾延迟门槛下,单位时间真正达标的请求数。这样的测试更接近共享组件在实际业务中的难点。

第三项是在相同总 GPU 预算下扫 placement,同时报告延迟、每请求 GPU 秒数、显存峰值和传输量。第四项是将首音频延迟、分块截止时间违约率加入 RTF。第五项是跨机部署,在真实网络代价下比较共置与拆分。以上是本笔记提出的研究评价方向,并非已经执行或已经得到结果的实验。

最有帮助的读法,是既不把 M* 看成“只是把已有优化包了一层”,也不把每个加速数字都归功于图 API。让已有优化跨模型复用,本身可以是重要贡献。问题在于这套接口是否足够精确、通用执行是否足够便宜,以及这些好处能否持续到更复杂流量和更远的设备边界。

14. 结论

M* 提醒我们,多模态服务系统需要理解的东西已经超出 prefill 与 decode。具名 Walk、循环、并行分支、流式策略和独立 placement,让模型执行结构进入公共运行时。论文中最直观的收益,往往出现在减少重复状态计算,或把原本被粗粒度 stage 隐藏的优化机会重新暴露出来时。

真正可迁移的经验是:接口应暴露优化器需要的依赖,同时保留模型组件对数值语义的所有权。图像、语音和世界模型实验给出了积极信号,但结论仍受单机硬件、具体配置和若干报告不一致的限制。理解这些边界,比记住最大的 12.5 倍更有助于判断自己的系统是否值得采用同类设计。

参考资料与图源

  1. Atindra Jha 等:M*: A Modular, Extensible, Serving System for Multimodal Models, v2。模型与运行时见第 2–3 节,实验见第 4 节,语义、额外图表及局限见附录 A–I。本笔记引用原论文图 1、2、3、5、7、8,并按 CC BY 4.0 注明来源。
  2. Keisuke Kamahori 等:VoxServe: Streaming-Centric Serving System for Speech Language Models。后续可继续阅读流式语音的专用调度目标。
  3. Jeff J. Ma 等:Cornfigurator: Automated Planning for Any-to-Any Multimodal Model Serving。后续可继续阅读自动选择部署计划;此为该 arXiv 标识目前的题名,M* 参考文献仍使用旧 Cornserve 题名。

本笔记的编号解释性算法、推导以及图 3–5 由 Zhongzhu Zhou 为阅读而整理,不包含新增实测性能结果。