和 Omni 模型视频通话时,你随口一句「刚才画面里那个红色的瓶子是什么」,它答得上来——这意味着它不仅看了画面、听了声音,还知道你说「刚才」的时候,画面正播到哪一帧

上一篇拆了 Omni 模型的输出侧:Thinker-Talker 怎么边想边说。结尾埋了一句「输入侧的另一个故事」,说的就是今天的主角——TMRoPE(Time-aligned Multimodal RoPE),Qwen 系列给音视频装的那块共享时钟。

看电影时玻璃杯落地、「哐当」一声,你从不怀疑声音属于那个画面——音画同步对人是免费的。对模型不是:它看到的世界只是一串 token,谁和谁「同时发生」,序列自己不会说。这篇讲清楚「时间」是怎么被装进模型坐标系的:从 RoPE 的表盘,到 M-RoPE 的三维拆分,再到 TMRoPE 的 40ms 时钟。

一、Transformer 看世界:一串没有座位号的 token

所有输入进模型前都会变成 token 序列:文字切成词元,图像切成小方块(patch),音频切成一小段一小段的帧。而 Transformer 的自注意力有个出名的特点:天生不知道顺序。把一句话的词打乱喂给它,注意力算出来的结果一模一样。「我打你」和「你打我」总得不一样吧,所以必须往 token 里注入位置信息——这就是位置编码。

如今的主流方案是 RoPE(旋转位置编码)。不用公式,一个比喻就够:

「今」「天」「很」「热」位置 0位置 1位置 2位置 3每前进一个位置,指针多转一个固定角度;注意力只看两根指针的夹角差——这就是「相对位置」
RoPE:位置每前进一格,指针多转一个固定角度;注意力只看两根指针的夹角差

给每个 token 发一块表:位置每前进一格,指针就多转一个固定角度。妙处在于,两个 token 做注意力时,模型看到的只有两根指针的夹角差。第 3 个词和第 7 个词的夹角差,跟第 103 个词和第 107 个词的完全一样——「相对距离」就这样被优雅地织进了注意力本身。

二、一维序号装不下多维世界

文本天然一维,一路排号没毛病。但图像是二维的(高 × 宽),视频是三维的(时间 × 高 × 宽),音频是一条纯粹的时间轴。硬把它们压回一维序号,「距离」就开始撒谎:一张切成 24×24 块的图,横向相邻两块序号差 1,纵向相邻两块序号差 24;换个分辨率,又全变了。模型不是不能硬学,但坐标系本身在帮倒忙。

Qwen2-VL 的 M-RoPE 把这件事理顺了:位置不再是一个数,而是三个数 (t, h, w)——时间、行、列,各转各的表盘。

文本图像视频第 5 个词(t, h, w) = (5, 5, 5)三个通道同一个数=普通 RoPE,兼容旧能力(t, h, w) = (0, 1, 2)t 不动,(h, w) 按行列走t=0t=1t=2(t, h, w) = (2, 1, 2)空间坐标不变,时间在走位置从一个数变成三个数,各自旋转各自的表盘
M-RoPE:位置拆成 (t, h, w) 三个通道;文本三通道同值,向下兼容普通 RoPE
  • 文本:三个通道填同一个数,如 (5, 5, 5)——数学上完全退化成普通 RoPE,语言能力无损继承;
  • 图像:t 不动,(h, w) 按行列走——「左右相邻」和「上下相邻」终于是两种不同的关系;
  • 视频:t 逐帧递增,(h, w) 管画面内的空间。

三、「第几帧」不等于「第几秒」

M-RoPE 的 t 是帧序号,这里还藏着两个问题。

第一个问题:抽帧率一变,t 的含义就变。1fps 抽帧时,Δt=1 代表一秒钟;25fps 时只代表 40 毫秒。模型对「过了多久」没有稳定的感觉,「视频第 37 秒发生了什么」这类问题就很难答好。Qwen2.5-VL 的升级是把 t 对齐到绝对时间:每帧的 t 由它的时间戳决定,而不是由「它是第几帧」决定。

第二个问题是 Omni 场景独有的:音频进场了。声音也是时间的艺术,但在原始的排法里,音频 token 和视频帧各排各的队——「这声哐当属于哪个画面」,坐标系里完全没有表达。

TMRoPE 的答案朴素得可爱:规定 1 个时间刻度 = 40 毫秒,音视频共用这个钟。

没有共享时钟:只按排队序号,音画对应全靠猜帧1帧2帧3帧4音1音2音3音4音5音6音7音801234567891011✕ 帧 1 和「音 1」本是同一时刻,序号却差 4;换个视频长度差得更多——对应关系全要靠学TMRoPE:规定 1 刻度 = 40ms,音视频同一个钟时间040ms80120160视频(12.5 fps → 每帧 80ms,t 逐帧 +2)t=0t=2t=4t=6t=8t=10音频(每 token 40ms,t 逐个 +1)t=0t=1t=2t=3t=4t=5t=6t=7t=8t=9t=10t=11✓ 同一时刻 → 相同的 t:杯子在 1.0s 落地,那一帧(t=25)和「哐当」的音频 token(t=25)天然对齐换成 25fps,每帧 t 改为逐 1 递增——无论怎么抽帧,t 始终等于「第几个 40ms」
上:只按排队序号,音画对应全靠猜;下:TMRoPE 让同一时刻的画面和声音拿到相同的 t
  • 音频:编码后每个 token 恰好代表 40ms,t 逐个加一,天生合拍;
  • 视频:每帧的 t = 时间戳 ÷ 40ms。抽帧率随便变——25fps 时 t 逐帧加 1,12.5fps 时逐帧加 2——t 永远落在正确的刻度上;
  • 于是,同一时刻的画面和声音,拿到相同的 t。杯子在 1.0 秒落地:那一帧的 t 是 25,「哐当」对应的音频 token 也在 t=25 附近。模型不需要费劲学习「这声音大概属于哪个画面」,坐标系已经替它说了。

这就是标题里的「共享时钟」:音画对齐不再是需要从海量数据里悟出来的规律,而是表示与生俱来的性质。

四、排队的艺术:两秒一块,视频在前

时钟解决了「什么时候」,还剩一个纯工程的问题:一维序列里,音视频 token 究竟按什么物理顺序排队

  • 全分开排(先所有视频、后所有音频):同一时刻的音画在序列里隔得老远,注意力够得着但费劲;
  • 严格按时间戳逐个交错:音视频 token 的产出节奏不同,切得太碎,工程上很难受;
  • Qwen2.5-Omni 的折中:按 2 秒切块,块内视频在前、音频在后
0s2s4s视频流(每 0.5s 一帧,示意)帧1帧2帧3帧4帧5帧6帧7帧8音频流(每 40ms 一个 token)按 2 秒切块 → 块内:视频在前,音频在后0–2s 块2–4s 块帧1帧2帧3帧4音 ×50(0–2s)帧5帧6帧7帧8音 ×50(2–4s)「什么时候」由 t 表达;排队只管两件事:同刻音画在序列里相邻 + 攒够 2 秒就能流式进模型
两秒一块交错:时间语义交给 t,排队顺序只管注意力就近与流式

这个设计一石二鸟。其一,就近性:同一个两秒里的画面和声音,在序列里也是邻居,注意力不用跨越千山万水。其二,流式:上一篇提过,Qwen2.5-Omni 的音视频编码器本来就按 2 秒分块处理——和这里的交错块严丝合缝,视频通话时模型每攒够两秒就消化一块,边看边听边想。

顺带交代衔接规则:每个新模态片段的位置,从前面所有位置的最大值加一继续;文本照旧三通道同值。整个序列里,文字、画面、声音就这样在同一个坐标系里排好了队。

值得停下来品的一点:排队顺序不再承担表达时间的职责——那是 t 的事;它只服务于注意力就近和流式工程。又是一次职责分离,和上一篇 Thinker-Talker 的「说什么 / 怎么说」如出一辙。

五、同一道题,几份答卷

TMRoPE 不是这道题的唯一解法。把「让模型拥有时间感」当成一道公共题目,近两年各家交的卷子恰好铺出一条光谱——

Qwen 自家的续集:坐标系继续进化,排队光荣退休。 Qwen3-Omni 沿用 TM-RoPE,但做了三处非常具体的升级。

改动一:钟的刻度从 40ms 换成 80ms。 新的音频编码器 AuT 每秒输出 12.5 个 token(即一个 token 管 80ms),时间刻度跟着一起换。同样是 2 秒的声音:Qwen2.5-Omni 里是 50 个音频 token,t 从 0 走到 49;Qwen3-Omni 里是 25 个,t 走到 24。数字全变了,却没有任何东西坏掉——因为视频帧也换用同一把新尺子(每帧 t = 时间戳 ÷ 80ms)。这恰好反过来印证第三节的观点:刻度取多大不重要,音视频共享一个钟才是本质

改动二:表盘从「切三段」改成「交错发牌」。 第一节说 RoPE 给每个 token 发一块表,其实说少了——实际发的是一整排转速不同的表盘(Qwen3-Omni 里共 64 个):快针擅长分辨近处的先后,慢针擅长跨很远还不绕圈,就像手表要靠秒针和时针配合才能报全时间。旧 M-RoPE 把这排表盘按位置切成三段,t、h、w 各领一段,而 t 领到的恰好是转得最快的一段——手里全是秒针,没有时针。

快慢差多少?拿一组常用参数把这笔账算清楚(64 对旋转角、基频 10000;不同模型取值不同,量级感受相通)。RoPE 规定表盘转速构成一个等比数列

  • 最快的表每个刻度转 1 弧度,转满一圈 2π ≈ 6.28,所以约 6 个刻度一圈
  • 往后每块表比前一块慢一个固定倍率——把基频 10000 开 64 次方,得约 1.155 倍(每块慢 15% 左右);
  • 走到最慢的第 64 块:1.155 自乘 63 次约 8700 倍,6.28 × 8700 ≈ 5.5 万个刻度一圈

(配图只画 12 块示意盘、覆盖同一跨度,所以相邻示意盘慢约 2.3 倍,数字为等比取整。)按 TMRoPE 的 80ms 一刻度换算:

  • 切段方案下,t 只分到最快的一段,手里「最慢」的表也大约 4 秒就转完一圈——两帧画面隔开超过几秒,t 的每一块表都已经绕过圈了,「转过的角度差」不再能区分远近,对表失败;
  • 交错发牌后(t、h、w 轮流抓,各拿 24、20、20 个),t 手里最慢的表,转满一圈要一小时量级——跨半部电影也不迷路。

值得注意的是,表盘本身一块没换、转速一点没变,变的只是归属。后来有研究专门验证了「t 困在高频段」确实是长视频建模的瓶颈之一,这笔账算得值。

改动三:2 秒切块退休。 第四节讲过 Qwen2.5-Omni 的排法——音视频按 2 秒切块、块内视频在前,排队顺序还在替时间语义打一份工。Qwen3-Omni 直接取消了这套切块:技术报告原话是,不再切成固定的 2 秒块,音视频表示直接靠 temporal ID 对齐。物理排列自由了,时间语义完全由坐标系承担。

表盘怎么分:切三段 vs 交错发(示意 12 个,实际 64 个;数字=转一圈所需的刻度数)快(秒针)慢(时针)转速为等比数列:12 块示意盘相邻慢 ≈2.3 倍(实际 64 块相邻仅慢 ≈1.155 倍,首尾跨度相同)旧 M-RoPE:按段划分——t 全是快针tttthhhhwwww614327216538087020004600105002400055000↑ t 只拿到最快一段:最慢的针 72 个刻度就转满(×80ms ≈ 6 秒),画面隔远了全在绕圈Qwen3:交错发牌——每个轴从快到慢都有thwthwthwthw614327216538087020004600105002400055000↑ 表盘一块没换、转速没变,只换归属:t 的最慢针到 10500 刻度(64 盘实配约 5.5 万刻度 ≈ 一小时)排队方式:固定切块 vs 只靠 t 对齐Qwen2.5-Omni:按 2 秒切块,块内视频在前、音频在后VVAAAVVAAA块 1(0–2s)块 2(2–4s)Qwen3-Omni:不再固定切块(排列为示意),同一时刻只靠相同的 t 对上V t=0V t=2A t=0A t=1V t=4A t=2A t=3↑ V t=0 和 A t=0 隔了两个位置也没关系——t 相同,坐标系知道它们同时发生
Qwen3-Omni 的两处关键升级:表盘从切段改为交错发牌(上);2 秒切块退休,对齐只看 t(下)

当坐标系足够可靠,排队就不必再兼职表达时间——功成身退。

Qwen3-VL:把时间戳明写在卷面上。 纯视觉这边走得更直接——除了升级版的 Interleaved-MRoPE,它把「秒级定位」从位置编码的隐式体感,升级成显式的文本-时间戳对齐:时间以看得见的 token 形式和画面绑定,模型回答「第 37 秒发生了什么」时可以直接引用,而不是靠转过的角度去猜。

MiniCPM-V 4.5 / 4.6:把时间压进 token 包里。 端侧的死穴是 token 预算:一帧 448×448 切成小块就有上千个 patch,6 帧就是六千多个——直接喂给手机上的小模型根本吃不消。3D-Resampler 的解法是一次把 6 帧「打包重采样」成固定的 64 个 token。

它的做法借自 Perceiver。先准备 64 个可学习的查询向量(query)——把它们想成 64 个「带工牌的采集员」,每张工牌事先写好两栏地址:空间上「我负责画面的哪一块」,时间上「我对应第几帧」。这 64 个采集员通过 cross-attention(交叉注意力)一起扑进 6 帧那六千多个 patch 的大池子,各自按工牌上的地址捞取相关信息,每人汇总成一个输出 token。于是六千多 → 64,官方称约 96 倍压缩;而时间就写在工牌上——LLM 主干收到的每个「token 包」,内部谁先谁后早已编码在 query 的时间栏里,不需要另设时钟。

输入:6 帧 patch 池×6 帧6 帧 × 上千 patch≈ 六千多个cross-attention各按工牌捞一份64 个 query,各带一张工牌工牌:空间(0,1) · 帧 t=1工牌:空间(2,1) · 帧 t=3工牌:空间(3,2) · 帧 t=6(示意 3 个,实际 64 个)输出:1 个 token 包64 tokens≈ 96× 压缩工牌 = 空间地址 +「第几帧」:时序在压缩这一步就编进 token 包,主干不必另设时钟相邻 6 帧高度重复(杯子几乎没动)→ cross-attention 一眼认出冗余,只留一份
3D-Resampler:64 个带「空间+时间」工牌的 query,用交叉注意力从 6 帧 patch 池里各捞一份,压成一个自带时序的 token 包

为什么敢压这么狠?因为相邻几帧高度重复——同一个杯子在连续 6 帧里几乎没动,逐帧编码等于把它记 6 遍。cross-attention 联合看 6 帧,一眼认出这份冗余、只留一份。这也解释了它为何吃得下 10fps 的高刷视频:帧率越高、冗余越大、打包越划算。今年五月的 MiniCPM-V 4.6 把这套推到 1.3B 的手机身板:128 帧输入、可配置的帧堆叠、4×/16× 混合压缩。

MiniCPM-o 4.5:把时间切成一秒一格的连环画。 全双工(一边听、一边说、随时能被打断)是个更棘手的时间问题:输入的画面、输入的声音、输出的语音,三条流同时在跑,怎么塞进 LLM 那条一维序列?

TDM(时分复用)的办法是把连续交互切成 1 秒一格,每格里按固定顺序装三样东西:先是这一秒看到的(视觉 token),再是这一秒听到的(音频 token),最后才是这一秒模型要说的(输出 token)——记作 [看; 听; 说]。一格一格首尾相接,就拼成了喂给 LLM 的那条序列。

三条流并行,按 1 秒切格0s1s2s3s看(视觉)听(音频)说(输出)每格内重排成 [看; 听; 说],再首尾相接拼成喂给 LLM 的一维序列→ …第 1 格(0–1s)第 2 格(1–2s)第 3 格(2–3s)格内「先感知后输出」:这一秒说的话,排在这一秒所见所闻之后 → 永远基于最新观察每过一秒就追加新格 → 说话时仍在读入新画面新声音 → 你一插话它下一格就看见(全双工)
TDM:三条流按 1 秒切格,每格重排成 [看; 听; 说] 再首尾相接;先感知后输出、每秒追加新格,于是能边说边听、随时打断

「先感知后输出」是关键:模型这一秒要说什么,永远排在这一秒的所见所闻之后,于是每句话都基于最新观察。而因为每过一秒就追加新的一格——新画面、新声音——模型在开口的同时仍在源源读入新输入,你一插话它下一格就「看见」了,这正是「能被打断」的由来。(论文实测 1 秒最优;切到 0.1 秒,每格信息太少,模型反而决策不稳。)底座是 Qwen3-8B + 0.3B 语音解码器,这套流式框架叫 Omni-Flow。

① 坐标系 — TMRoPE(Qwen-Omni)帧 t=4音 t=4t 相同 ⇒ 同时发生时钟长在位置编码里:同一时刻,同一个 t② 显式时间戳 — Qwen3-VL00:0100:02时间戳作为 token 写进序列,答题可直接引用③ 压缩内嵌 — MiniCPM-V 4.5/4.664 token3D-Resampler:6 帧压成一包,时序在压缩时注入④ 时间片排队 — MiniCPM-o TDM片 1(≈1s)片 2按 ~1s 切片重排,座位即时钟;全双工的地基
同一道题的四种答卷:坐标系、显式时间戳、压缩内嵌、时间片排队

这四招并不互斥:Qwen2.5-Omni 曾经坐标系与排队并用,坐标系成熟后便让排队退休;MiniCPM 的时间片内部同样讲究先后。工程上往往是几招合用,区别只在谁当主角。

六、写在最后

回头看,这条演进线其实是同一句话说了三遍:好的位置编码,就是给数据一个合适的坐标系。

  1. RoPE:给一维序列以「相对距离」;
  2. M-RoPE:给图像和视频以「空间结构」;
  3. TMRoPE:给所有模态一个「物理时钟」。

坐标系选对了,「对齐」就从一个要费劲学习的任务,变成了表示本身的性质——最好的学习是不用学。

一进一出,Omni 模型的两块基石就齐了:输入侧,TMRoPE 让看到的和听到的共享同一条时间轴;输出侧,Thinker-Talker 让它边想边说。下次它接住你那句「刚才」时,你知道:在它的世界里,每一帧画面和每一声响动,都戴着同一块表。

参考