Tokenizer 不是可以从 checkpoint 旁边单独换掉的文本文件,它本身就是 checkpoint ABI 的一部分。Liquid AI 的公开案例证明,词表可以从 65,536 原地扩到 128,000,并复用已经投入巨大算力的模型,但迁移仍用了精确 token 映射、1T tokens 适配训练和真机性能验证。本文把这套案例整理成一份可执行的迁移契约,同时说明它在哪些情况下有效,哪些指标会制造虚假的成功感。
阅读时间: 约 10 分钟 | 字数: 约 3,300 汉字
核心结论
- 不要拿一个无关 tokenizer 直接替换旧文件。应冻结原 BPE merge 顺序,在其后继续学习新 merge,尽量保持旧 token ID 和语义不变。
- 旧 token 复制原 embedding 行,新 token 用其精确旧子词分解对应 embedding 的均值初始化。
- 适配分两步。Liquid 先用 600B tokens 只训练新增行,再用 400B tokens 的平衡多语言数据解冻全模型。
- 词表变大存在固定性能税。128K 词表让每个 decode step 慢 7.4% 至 9.4%,高压缩语言才有明显净收益。
- tokenizer、权重、config、special token、chat template 和 GGUF 等转换产物必须作为同一个版本发布,不能各自滚动升级。
先把 Tokenizer 当成 checkpoint ABI
很多迁移事故都来自一个过于简单的理解:tokenizer 把文本变成整数,模型只负责读取整数。预训练完成后,每个整数已经对应一个学到的 embedding 行,并且通常还对应 LM head 的输出行。整数的实际含义同时依赖 merge 顺序、normalizer、byte fallback、special token 和 chat template。
因此,一次 tokenizer 更新至少同时触碰六个契约面:
| 契约面 | 必须保持的一致性 | 失配后的典型结果 |
|---|---|---|
| Token 身份 | 旧文本仍映射到预期的旧 ID | 常见词拿到无关 embedding |
| Embedding | 行号与 token 语义一致 | 生成混杂、重复或失去连贯性 |
| LM head | 输出行与输入 token 使用同一词义 | 模型预测出错误表面 token |
| Special token | BOS、EOS、padding、角色与工具 token 稳定 | 对话无法正确停止,工具调用失效 |
| 配置 | vocab_size、权重绑定和 tensor shape 一致 |
加载失败或运行时截断词表 |
| 部署制品 | GGUF、MLX、ONNX、缓存和移动端包来自同一版本 | 不同后端表现不一致 |
这就是为什么原地扩容首先是一场多制品 checkpoint 迁移,而不是一次 tokenizer 训练任务。Hugging Face 上的 LFM2.5-8B-A1B 配置明确写着 vocab_size: 128000 和 tie_word_embeddings: true。其模型卡还专门提醒,首发后的 tokenizer 曾因 llama.cpp 工具调用问题而更新,旧下载和 GGUF 也要重新获取。权重正确但 tokenizer 或转换包陈旧,组合起来仍是一个错误模型。
Liquid 的原地扩容配方
这套方法有一个重要前提:模型方掌握原 tokenizer、完整 merge 顺序和 special token 配置。它不是任意第三方 tokenizer 的无损替换方案。
第一步:延续旧 BPE merges
源 tokenizer 是词表大小 65,536 的 byte-level BPE。Liquid 把原有有序 merge 列表作为新 tokenizer 的起点,冻结这些规则,再用多语言语料继续 BPE 训练,直到词表达到 128,000。
这样做保住了两个关键不变量。多数旧 token 可以一对一继承,新 token 则一定能精确分解成一串旧 token。论文的映射分析显示,在 64,400 个 active source entries 中,63,151 个实现了一对一转移。
这个数字不能被简写成“所有旧 token 完全不变”。工程上仍要为每个旧 ID 生成映射报告,列出 special token、非活跃项和所有例外,并给每个例外指定处理策略。
第二步:按行迁移 embedding
若目标 token 与旧 token 一对一对应,就原样复制旧 embedding 行。若新 token 可精确分解为旧子词 (s_1, s_2, ..., s_k),则用这些旧行的均值初始化:
E_new(token) = mean(E_old(s_1), E_old(s_2), ..., E_old(s_k))
这不是随机初始化,也不需要额外学习跨 tokenizer 对齐。LFM2.5 绑定了输入 embedding 与输出 embedding,因此同一矩阵也承担 LM head。若模型没有绑定权重,输入矩阵和输出矩阵必须分别迁移,并验证两边使用同一份 token 映射。
第三步:先固定旧能力,再适配全模型
Liquid 把迁移后的训练拆成两个阶段:
| 阶段 | 可训练参数 | 数据量 | 目标 |
|---|---|---|---|
| Stage 1 | 仅新增 embedding 行 | 600B tokens | 让新 token 建立表示,不扰动旧表示空间 |
| Stage 2 | 全模型参数 | 400B tokens | 用平衡多语言数据把新词表整合进模型主体 |
所以“原地升级”不等于“免训练”。这次公开案例的专门适配总量是 1T tokens。不从头训练的真正含义,是复用昂贵的源 checkpoint,而不是只运行一次 resize_token_embeddings()。
训练前先写迁移契约
团队不应等训练结束才核对制品。下面这类版本化契约应该在投入算力前通过评审:
source:
checkpoint_revision: immutable-hash
tokenizer_revision: immutable-hash
vocab_size: 65536
merge_table_digest: sha256:...
target:
vocab_size: 128000
preserves_source_merges: true
old_id_policy: identity_or_documented_exception
new_row_initializer: exact_source_subtoken_mean
adaptation:
stage_1: {trainable: new_rows_only, tokens: 600B}
stage_2: {trainable: all_parameters, tokens: 400B}
release_unit:
- tokenizer 与模型权重
- config、special token map 与 chat template
- GGUF、MLX、ONNX 与 serving manifest
- 评测报告和回滚 revision
这里的 hash 和 special token 值应从固定的源 revision 读取,不能手填猜测。契约的价值在于把所有耦合制品、不可变条件和例外放到同一个评审面上。
正式训练前至少要设置三个硬失败条件:
- 每个源 token ID 都有且只有一个目标处理结果。
- 每个新增 token 都能被源 tokenizer 精确分解。
- tokenizer metadata、tensor shape、config、template 和所有导出格式对词表与 special token 的理解完全一致。
如何正确解读质量收益
Liquid 在八个 benchmark 的非加权聚合上,报告了四个受控节点:
| Checkpoint | 聚合得分 | 能说明什么 |
|---|---|---|
| 源模型 | 44.7 | 迁移前基线 |
| Zero-swap | 38.9 | 只有结构化初始化仍不足以保持质量 |
| Stage 1 后 | 43.7 | 只训练新增行可恢复大部分损失 |
| Stage 2 后 | 48.3 | 全模型继续预训练后超过源模型 |
48.3 不能全部记到 tokenizer 名下。Stage 2 额外使用了 400B tokens,Liquid 官方也明确认为,超过源模型的部分很可能来自额外预训练。稳妥结论是:扩容模型经两阶段继续训练后恢复并超过了基线,而不是“词表翻倍直接带来 8% 质量提升”。
Global MMLU 总体从 41.4 提升到 43.7。原 tokenizer 切分最严重的语言在 Stage 2 后获得了较大提升:
| 语言 | Global MMLU 变化 |
|---|---|
| 越南语 | +11.6 分 |
| 印尼语 | +9.1 分 |
| 印地语 | +7.6 分 |
| 马来语 | +6.8 分 |
| 孟加拉语 | +4.8 分 |
这些结果来自一个模型系列和一套训练配方。技术报告是 2026 年 7 月发布的预印本,尚无独立同行评审。它适合作为细节充分的一级工程案例,不应被外推成普遍规律。
负向消融揭示了真正的红线
聚合分数告诉我们结果,失败消融则告诉我们哪些不变量不能破坏。
Stage 1 放开旧行,生成能力可能直接崩溃
当旧 embedding 行也可以在适配阶段更新时,HumanEval+ 从 43.9 跌到 1.8,repetition 指标从 0.92 跌到 0.19。与此同时,部分选择题指标仍可能持平甚至上涨。
旧 embedding 行定义了冻结模型主体已经理解的输入坐标系。移动这些行,相当于在不调整后续层的情况下改变基础表示。误差会穿过每一层,并在绑定的输出矩阵再次出现。Stage 1 不只需要配置“冻结旧行”,还应在每个训练阶段之后断言所有旧行 byte-for-byte 未变化。
英语偏置数据会制造看似健康的 checkpoint
英语占比过高的 Stage 2 数据混合产生了更隐蔽的失败:
| 指标 | 平衡数据 checkpoint | 英语偏置版本 |
|---|---|---|
| MATH500 | 61.8 | 27.0 |
| MGSM | 61.2 | 28.4 |
| MMLU | 64.7 | 64.9 |
| MMMLU | 43.8 | 48.3 |
| Repetition | 0.88 | 0.49 |
MMLU 表面稳定,MMMLU 甚至上涨,但数学生成和重复控制已经严重退化。若发布门槛只有选择题准确率,这个 checkpoint 会被误判为合格。迁移评测必须同时包含自由生成、可执行代码、数学 exact match、重复率和逐语言样本。
建立真实性能账本
更大的词表能减少弱势语言需要生成的 token 数,却也会扩大 embedding 和 LM head。batch size 为 1 的端侧推理常受内存带宽限制,每个 decode step 都要读取更大的输出矩阵,因此固定成本不可忽略。
Liquid 报告的语料级压缩比定义为“旧 tokenizer token 数除以新 tokenizer token 数”:
| 语言 | Token 压缩比 |
|---|---|
| 泰语 | 4.00x |
| 孟加拉语 | 3.35x |
| 越南语 | 2.59x |
| 印地语 | 2.38x |
在 M4 Max CPU、M4 Max GPU 和 Snapdragon 参考设备上,128K 词表让单 token 解码慢了 7.4% 至 9.4%。英语、代码和部分欧洲语言几乎没有压缩红利,因此按字符计算最多也会慢约 9%。继续扩到 256K 时,Snapdragon 的吞吐损失最高达到 37%,这也是团队止步 128K 的原因。
官方给出的 2.2x 至 3.7x 每字符速度提升是综合估算,不是直接测得的端到端应用延迟。它把实测单 token 吞吐和实测 token 压缩比合成在一起。写方案或对外沟通时,必须保留这个限定。
自己的性能账本至少要分开记录:
- 真实语言与代码分布下的 prompt tokens per character。
- 代表性回答的 generated tokens per character。
- 每种设备与 backend 的 prefill 和 decode 吞吐。
- 峰值内存、模型包大小和冷启动时间。
- 包含 template、采样、工具调用和网络的端到端任务延迟。
词表升级只有在真实流量上的压缩收益超过 LM head 固定税时才划算。跨语言平均值很容易同时掩盖泰语用户的大幅收益和纯英文代码场景的回退。
适用边界与替代路线
以下条件同时成立时,这套原地扩容方案才值得进入设计阶段:
- 团队掌握原 BPE tokenizer、merge 顺序、normalizer、special token 和源 checkpoint。
- 源 checkpoint 的训练成本足够高,1T tokens 适配仍比从头训练划算。
- 真实业务中存在被明显过度切分的重要语言。
- 有能力构造平衡继续预训练语料,并执行生成式与选择题双重评测。
- 能控制完整部署制品,并在真实目标硬件上做 benchmark。
如果目标是无关的第三方 tokenizer、原 merge 规则已经丢失、旧 ID 无法稳定,或团队没有继续预训练预算,就不应照搬这套配方。Zero-shot tokenizer transfer 解决的是另一类迁移问题。若源 tokenizer 的 normalizer、special token 布局和语言分配从根本上都不合理,从头训练也可能比维护大量例外更干净。
这套方法也不能直接推广到所有 tokenizer 类型。“继续旧 merges”是 BPE 的结构性优势,不是 Unigram 或 WordPiece 的通用操作。
评测与发布清单
训练前:
- 用不可变 revision 固定权重、tokenizer、config、merge table、template 和 special token map。
- 在真实语言、代码和格式分布上测 token fertility 与 characters per token。
- 检查全部旧 ID、全部新 token 精确分解和每个例外。
- 估算扩大后的 embedding 与 LM head 对内存、带宽和包体的影响。
Stage 1 后:
- 证明旧行没有变化,包括 optimizer state 和 tied weights 行为。
- 对比 source、zero-swap 和 Stage 1 的生成、代码、数学、重复率与逐语言结果。
- 分别检查只含旧 token 的 prompt 与新旧混合 prompt 的 token log probability。
Stage 2 后:
- 公布继续训练数据混合,把 tokenizer 收益与额外训练收益分开表述。
- 在每个支持 backend 上测 prefill、单 token decode、每字符 decode、内存和端到端延迟。
- 回归 chat template、停止行为、结构化输出与工具调用。
- 重建并校验所有转换制品,用干净下载环境测试,不能依赖本地缓存。
- 把 tokenizer 与 checkpoint 作为一个原子 revision 发布,并保留明确回滚版本。
下一步行动: 在申请训练算力前,先产出 source-to-target token 映射报告和目标硬件 break-even 表。任何一份无法被确定性复核,都说明迁移还没有准备好。
FAQ
能否直接替换 tokenizer,再 resize embedding?
通常不安全。Resize 只解决 tensor shape,不解决 token 身份和已有语义。Liquid 的结构化初始化完成后,zero-swap 聚合仍只有 38.9,低于源模型的 44.7。
原地扩容是否等于免训练?
不是。公开案例先用 600B tokens 训练新增行,再用 400B tokens 继续训练全模型。它省掉的是从零预训练,不是继续预训练。
为什么 Stage 1 不能训练全部 embedding 行?
因为旧行是冻结模型主体已经理解的表示坐标。公开消融中,放开旧行伴随 HumanEval+ 从 43.9 跌到 1.8,重复控制也明显崩溃。
Token 变少是否一定更快?
不一定。更大的 LM head 会让每一步变慢。高压缩语言可以获得明显净收益,英语和代码则可能无法覆盖 7.4% 至 9.4% 的单 token 性能税。
这套配方能否用于任意第三方 tokenizer?
不能。它依赖原 tokenizer 所有权和原 BPE merges 的精确延续。无关 tokenizer 需要另一类 transfer 方法,也要接受更高的对齐风险。
References
- Liquid AI,Tokenizer Expansion: Upgrading a Model's Tokenizer in Place,2026-07-21。
- Smith 等,In-Place Tokenizer Expansion for Pre-trained LLMs,arXiv:2607.15232,2026 年 7 月预印本。
- Liquid AI,LFM2.5-8B-A1B 模型卡,Hugging Face。
- Liquid AI,LFM2.5-8B-A1B config.json,Hugging Face。
- Liquid AI,LFM2.5-8B-A1B tokenizer 制品,Hugging Face。
- Minixhofer、Ponti 与 Vulić,Zero-shot Tokenizer Transfer,NeurIPS 2024。