把图像量化成离散 id、与文本 BPE 合成一张表,多模态生成就退化为纯粹的 next-token prediction——统一 token 空间的全部收益与全部代价,都来自这一步。
统一词表买到了什么
合表之后,模型侧不再有「多模态」这件事:一张 embedding 表、一个 softmax、一套交叉熵,图文交错生成与纯文本续写走完全相同的代码路径。这带来三处实质简化——训练目标唯一(不需要对比损失或 diffusion 分支)、图文可任意交错而非固定「图在前文在后」、图像输出天然继承 LLM 的采样与约束工具链。
代价同样集中:量化是有损的,码本重建误差成为视觉质量的硬上限;词表变大后模态在共享 softmax 里互相挤压。两条路线的分野见 视觉 Tokenizer,本篇只谈合表这一侧。
词表合并的机械细节
文本 id 占低位、码本 id 整段追加在高位,模态边界 token 从文本词表里预留——这是所有实现的共同骨架:
import torch
# 单一 id 空间:文本 BPE 占低位,VQ 码本整段追加在高位
V_TEXT, V_IMAGE = 57_344, 8_192 # Chameleon 量级
BOI, EOI = 57_342, 57_343 # 文本词表内预留的模态边界 token
IMG_BASE, VOCAB = V_TEXT, V_TEXT + V_IMAGE # 65_536
# 512×512 图 → 32×32 码本网格 → 1024 个 id,首尾包边界
codes = [(r * 32 + c) % V_IMAGE for r in range(32) for c in range(32)]
seq = [BOI, *(IMG_BASE + c for c in codes), EOI]
print(VOCAB, len(seq), seq[:2]) # 65536 1026 [57342, 57344]
def mask_modality(logits, modality):
"""共享 softmax 必须外挂约束:否则图像段中途会蹦出文本 token。"""
out = torch.full_like(logits, float("-inf"))
lo, hi = (0, IMG_BASE) if modality == "text" else (IMG_BASE, VOCAB)
out[..., lo:hi] = logits[..., lo:hi]
out[..., EOI] = logits[..., EOI] # 边界 token 恒可达,用于收尾
return out
nxt = mask_modality(torch.randn(1, VOCAB), "image").argmax(-1).item()
assert nxt >= IMG_BASE or nxt == EOI三条容易踩的工程约束:
- 码本 id 绝不能进 merge 表。它们是纯追加 token,必须绕过 pre-tokenizer 与 BPE 合并逻辑,否则会被当作普通字节序列拆开。Chameleon 用 SentencePiece 训文本侧 BPE,把 8192 个码本 token 直接纳入 65,536 的词表,正是靠这种「保留符号」机制,用法见 SentencePiece
- 边界 token 承担模态切换语义,
<image>/</image>的角色与对话模板里的角色标记同构,注册方式见 特殊 Token 与 Chat Template - embedding 与 lm_head 同步扩容,8192 个新 token 在 下是 33.5M 参数,不共享权重时翻倍;词表膨胀对显存与输出层计算的影响见 词表设计与裁剪
Chameleon:同表自回归的样板
Meta 的 Chameleon 是 early-fusion 路线最干净的公开实现:Gumbel-VQ 图像 tokenizer,码本 8192,512×512 图编码为 1024 个 token;文本 BPE 与码本合并为 65,536 词表;图文交错序列上做单一 next-token prediction,7B/34B 两档。
真正的贡献不在架构而在稳定性。混合模态训练在规模放大后会发散,根因是 softmax 的平移不变性叠加模态竞争:文本与图像 token 各自把自己的 logit 范数往上推,无界增长直至数值崩溃。论文给出的处方是 QK-Norm(对 attention 的 query/key 做 LayerNorm,直接掐住 logit 增长),7B 额外加 dropout,34B 改用 norm reordering。这个失效模式是统一词表特有的——纯文本训练不会遇到。
另一处实测教训:该 tokenizer 对含大量文字的图像重建极差,OCR 类任务上的短板来自 tokenizer 而非 LLM。统一词表把视觉能力的天花板前移到了量化器。
跨模态对齐的真实难题
| 症状 | 根因 | 常见对策 |
|---|---|---|
| 训练 loss 发散 | 模态争夺共享 softmax,logit 范数无界增长 | QK-Norm、norm reordering |
| 单模态遗忘 / 偏斜 | 图像 token 数量级压过文本,梯度被视觉主导 | 按模态加权损失、控制数据混比 |
| 「统一」只是名义上的 | 文本与图像 embedding 收敛到近乎不相交的子空间 | 交错数据、跨模态注意力监督 |
| 错一个 token 全图崩 | 码本 id 是扁平原子,无前缀结构、无字节兜底 | 加大码本、残差多级量化 |
| 空间关系错乱 | 二维网格被展平成一维 raster 序列 | 行分隔 token、多维位置编码 |
第三行最反直觉:合表并不自动产生语义对齐。码本 id 之间没有 BPE 算法原理 里那种 merge 层级——id 100 与 101 毫无关系,也没有字节级兜底保证未见内容可表达。文本 token 的可组合性在视觉侧完全不存在。
第四行对推理的影响最直接:自回归逐 token 生成图像时,一次采样偏差会沿 raster 顺序向后污染整张图,且无法像文本那样靠上下文自我纠正。解码约束与采样敏感性参见 Tokenizer 对推理的影响。
向音频与视频扩展
瓶颈从词表大小换成序列长度。音频离散化普遍用残差向量量化(RVQ),每帧产出 个码本 token,总量为 :
| 模态 / 编码器 | token 率 | 1 分钟 |
|---|---|---|
| 512×512 图像(VQ-8192) | 1024 / 图 | — |
| HuBERT 语义 token | 50 Hz × 1 | 3,000 |
| EnCodec 24 kHz @6 kbps | 75 Hz × 8 码本 = 600/s | 36,000 |
| Mimi(Moshi) | 12.5 Hz × 8 码本 = 100/s | 6,000 |
| 视频 8 fps,时间维 4× 压缩 | ≈2,048/s | ≈123,000 |
这张表解释了为什么实时语音对话必须压到 12.5 Hz 量级:600 token/s 的码率下,一分钟音频就吃掉 36k 上下文。Mimi 的做法是把语义信息蒸馏进第一个码本,低帧率下仍保住可懂度。
多码本还带来结构问题:朴素展平把序列拉长 倍。延迟模式(delay pattern)用阶梯错位换取每步并行输出 个 token:
# RVQ 每帧 K 个码本:朴素展平 K×T 步,延迟模式只需 T+K-1 步
K, T = 4, 6
frames = [[f"c{k}t{t}" for k in range(K)] for t in range(T)]
flat = [tok for f in frames for tok in f]
delay = [[frames[t - k][k] if 0 <= t - k < T else "·" for k in range(K)]
for t in range(T + K - 1)] # 第 k 个码本整体后移 k 帧
print(len(flat), len(delay)) # 24 9
print(*(" ".join(r) for r in delay[:3]), sep="\n")Gemini 系的「原生多模态」常被读成全离散统一词表,实际是混合的:音频以 16 kHz 特征形式进入统一序列,图像输出则走离散 image token。输入侧可以连续、输出侧必须离散——需要自回归生成的模态才真正需要进词表。BAAI 的 Emu3 走了更彻底的一端:32,768 码本覆盖图像与视频,纯 next-token prediction 一套目标打通理解与生成。
离散 vs 连续注入的架构分野
| 路线 | 视觉表示 | 词表变动 | 原生生图 | 代表 |
|---|---|---|---|---|
| 连续注入 | CLIP/SigLIP 特征经 projector 进输入层 | 无 | 否 | LLaVA、Qwen-VL |
| 统一离散词表 | VQ 码本 id | 文本 + 码本合并 | 是 | Chameleon、Emu3 |
| 双通路解耦 | 理解走连续、生成走离散,共享 transformer | 合并但输入分流 | 是 | Janus-Pro |
| 单模型双目标 | 连续 latent + diffusion 损失 | 无 | 是 | Transfusion |
分野的判据是是否愿意为架构统一支付量化损失。连续注入在理解任务上始终占优——没有信息瓶颈;统一词表换来生成能力与目标函数的唯一性。
后两行是对这个二选一的正面反抗。Janus-Pro 的观察是理解与生成需要不同粒度的视觉表示,强行共用一个 tokenizer 必然两头妥协,于是保留统一 transformer、拆开视觉编码前端。Transfusion 更激进:不量化,图像在连续 latent 上算 diffusion 损失、文本算 LM 损失,两个目标共存于一个序列——统一的是模型而非词表。