想象你是一位米其林大厨,正准备开一家“多国料理餐厅”。你有巨大的厨房仓库,可以提前储备各种“半成品食材”:切好的姜丝、盘好的鱼丸、发好的鲍鱼。问题来了:仓库里到底该备多少种食材? 如果只备32种基础食材,几乎任何菜都能靠现场“改刀”拼出来——但做“佛跳墙”时,你得把鲍鱼海参现场拆解成几十道工序才能还原风味,出餐极慢;如果备128种、甚至256种食材,绝大多数菜一步到位,可仓库租金、保鲜成本、翻找开销也成倍上涨,更别提很多珍稀食材一年都用不上一次。 这正是词表大小(Vocabulary Size)选择的核心矛盾。词表就是那间“半成品仓库”,每个 Token 就是一份“切好的菜料”。词表太小,生僻词汇只能被暴力细切成碎片,产生未登录词(OOV),语义受损还拖长序列;词表太大,嵌入层内存、Softmax 开销、训练成本层层加码,模型反而可能“死记菜谱”、泛化变差。 32K、128K、256K,到底选哪个?答案取决于你的“餐厅定位”:顾客说几种语言、预算多少、菜品的精致标准是什么。本文就用这个贯穿始终的比喻,带你搞懂词表大小的权衡之道。

岗位关联

掌握词表大小权衡,你就能在多语言大模型、领域 Tokenizer 的选型中做出量化决策,而不是拍脑袋定词表——这是 AI 数据工程师与 Tokenizer 工程师的核心硬技能。

目录
  1. 可视化演示
  2. 词表基础概念
  3. 压缩率权衡
  4. 多语言覆盖
  5. OOV问题
  6. 训练效率
  7. 模型效果
  8. 选型决策
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

本节配有交互动效(进入视口后自动加载,约 3KB)。

词表规模对比 词表大小在多语言压缩率与OOV之间的权衡:大词表降低OOV但增加参数量和推理延迟

词表基础概念

你走进餐厅后厨的第一件事,是搞清楚“仓库里到底有些什么”。这就是词表(Vocabulary)的直观含义:它是模型能够直接理解和生成的所有“半成品”的集合。每个半成品叫一个 Token——可以是一个中文单字、一个英文单词、甚至一个子词片段。Tokenization(分词)就是厨师“切菜”的过程:把顾客点的一整句话,按仓库里现有的食材切成若干份。

所谓“32K 词表”,就是仓库里备了大约 32000 种半成品食材;128K 就是 128000 种。规模数字本身没有对错,但它决定了一件关键的事:嵌入层(Embedding) 的规模。模型要把每个 Token 都转换成一个向量——好比给每种食材建立一份“营养档案”——这份档案表的总存储量,直接由词表大小决定。

回到厨房:如果你把仓库从 32 种扩到 128 种,档案柜的体积直接翻四倍——还没开始做菜,房租就涨了。理解这层关系,是后面所有权衡的基础。

Pemb=V×dmodel\displaystyle P_{emb} = V \times d_{model}
嵌入层参数量 = 词表大小 × 每个 Token 的向量维度。词表越大,光“食材档案柜”就要占掉巨大的显存。
  1. P_emb(嵌入层参数量)它是“全部食材编号本”的总条目存储量,即需要保存多少个向量参数。
    PembP_{emb}
  2. V(词表大小)词表里有多少个 Token,好比仓库里备了多少种食材。
    VV
  3. d_model(隐藏维度)每个 Token 用多少维向量表示,好比每种食材的“营养档案”要记录多少个项目。
    dmodeld_{model}
  4. 乘积关系总档案存储量等于“食材种类数 × 每份档案的字段数”。
    V×dmodelV \times d_{model}

压缩率权衡

有了仓库,接下来最关心的是出餐效率。同样一句话,32K 词表可能因为“天安门”不在仓库里,被迫切成“天”+“安”+“门”三步;128K 词表可以直接端出一份“天安门”整体食材。我们把“每个 Token 平均覆盖多少字符”称为压缩率——数值越大,意味着切出的 Token 数越少,序列越短,模型处理得越快。

实测经验中,32K 词表压缩率约 2.5 字符/Token,128K 能到 4.1,256K 约 4.6。注意 128K→256K 只提升了 0.5,而 32K→128K 提升了 1.6——边际收益在快速递减。你在仓库里多塞 12 万种食材,换来的出餐提速却越来越少,这菜还怎么做?

C=NcharNtoken\displaystyle C = \frac{N_{char}}{N_{token}}
压缩率 = 语料总字符数 ÷ 分词后 Token 总数。它衡量的是“每份食材能做多少活”。
  1. C(压缩率)出餐效率的核心指标,代表每个 Token 平均扛起多少个字符。
    CC
  2. N_char(字符总数)语料里总共有多少个字符,即顾客总共点了多少“原料量”。
    NcharN_{char}
  3. N_token(Token总数)切完之后总共得到多少个 Token,即后厨实际切出的“菜料份数”。
    NtokenN_{token}
  4. 比值关系用原料总量除以菜料份数,就得到每份菜料的“平均含金量”。
    NcharNtoken\frac{N_{char}}{N_{token}}

多语言覆盖

你的餐厅要服务来自中国、日本、印尼、尼日利亚的顾客。每种语言的“食材习惯”差异巨大:中文以字为单位,英文以词为单位,日语混着平假名和汉字,印尼语则有大量词缀变形。如果词表太小,每种语言分到的“食材配额”就少,小语种的常用词都进不了仓库,出餐质量必然惨不忍睹。

共享子词(Subword)是解决之道:与其给每种语言单独存一份完整词汇表,不如把不同语言中共同的字母、偏旁、词缀作为“通用基础料”共享。比如拉丁字母 a、tion、-ing 同时服务英语、印尼语、法语;汉字“中”“国”“语”直接服务中文和日文。128K 词表有了更大的空间,可以把这些共享料备得更全,低资源语言(如斯瓦希里语)的常用词也因此有了入场券。

但这不意味着词表越大越好。词表在语言间的“分配”才是关键:如果一味堆英文词条,中文和印尼语的覆盖率可能纹丝不动。聪明的做法是先统计目标语料的字频/词频,把稀缺的配额优先让给“高性价比”的共享子词,而不是盲目追求总量。这就像给多国菜单配菜——与其每种菜都备 100 道,不如精心设计 40 道能覆盖多国口味的“通用菜”。

OOV问题

顾客点了一道“罗望子炖羊肉”,你的仓库里根本没有“罗望子”这味料——这就是OOV(Out-of-Vocabulary,未登录词)。词表再大,也总有没见过的词:人名、地名、新造词、专业术语、网友自创的“栓Q”。OOV 率就是衡量“菜单上多少菜是你的仓库做不了的”。

在模拟多语言语料中,32K 词表的 OOV 率可能高达 12%,128K 降到 3%,256K 可以压到 0.8% 左右。但注意两个关键事实:第一,小词表碰到 OOV 并非完全无解——子词分词器会把“罗望子”拆成“罗”+“望”+“子”三个已知料,硬把菜做出来,只是味道变形;第二,即使 256K 词表也无法把 OOV 率降到 0,因为语言是活的,新词每天都在诞生。追求 OOV=0 就像指望仓库备齐全世界所有可能的菜,既不现实也不经济。

ROOV=NOOVNtotal\displaystyle R_{OOV} = \frac{N_{OOV}}{N_{total}}
OOV率 = 未登录词条数 ÷ 全部词条数。它直接反映词表对目标语料的“食材覆盖度”。
  1. R_OOV(未登录词率)仓库缺料程度,即无法直接处理的词占多大比例。
    ROOVR_{OOV}
  2. N_OOV(未登录词数量)不在词表中的词条总数,好比顾客点了多少种仓库里没有的食材。
    NOOVN_{OOV}
  3. N_total(词条总量)语料中出现的所有不同词条,即顾客全部点过的菜品种类。
    NtotalN_{total}
  4. 比值关系拿缺料品种数除以顾客点过的总品种数,就知道“缺料率”有多高。
    NOOVNtotal\frac{N_{OOV}}{N_{total}}

训练效率

仓库每多一种食材,就要多占一份货架;词表每多一个 Token,就要多占一份内存和算力。这种开销首先砸在嵌入层上:前面算过,32K×4096 维≈131M 参数,128K≈524M,256K 直接飙到 1048M——光“档案柜”就占了 10 亿参数,训练时每一步前向反向都要读写它们,显存和带宽压力直线上升。

更隐蔽的成本在 Softmax 层。模型最后要从整个词表里挑出下一个 Token——相当于厨师要从全部食材里选出“下一道要用的料”。词表越大,这个选择过程要计算的条目就越多。256K 词表的 Softmax 计算量是 32K 的 8 倍,即使有各种加速技巧,训练吞吐量依然会肉眼可见地下降。

实操中,32K 词表的训练吞吐通常比 128K 高 20%~30%,比 256K 高 40% 以上。也就是说,如果你只有 8 张 A100,堆 256K 词表意味着每个 epoch 都要多等近一倍的时间。做菜快但备料慢,出餐快但翻仓库更累——这就是训练效率的残酷真相。

模型效果

词表大小最终要落到“菜好不好吃”上。从下游任务看,128K 词表通常比 32K 有 better 的语义完整度,因为“天安门”整体入表,模型更容易学到完整概念;但 256K 并不会带来同比例的性能提升——在英文任务上,256K 相比 128K 的收益甚至常常可以忽略不计,反而引入了额外的稀疏风险。

收敛速度也受词表影响:32K 词表的嵌入表小,参数更新更充分,前期收敛往往更快;128K 词表则需要更多数据把“新食材”喂熟。反过来,过拟合是大词表的隐形杀手——256K 词表里大量词条在语料中只出现几次,模型容易把它们“死记下来”,遇到新文本时泛化能力反而下降。这就像厨师背熟了仓库里每袋调味料的位置,但面对没见过的客人点菜就乱了阵脚。

所以模型效果和词表大小不是简单正相关,而是一条先升后平的曲线:32K 到 128K 是明显的爬坡,128K 到 256K 基本进入平台期,甚至在小数据场景会掉头向下。核心原因是词表大小必须与语料规模匹配:语料只有几十亿字符,硬上 256K 词表,平均每个词条分到的学习样本少得可怜——食材太多太偏,厨师根本练不熟。

选型决策

现在回到你的餐厅定位。如果你做的是“社区家常菜馆”(中文单语模型),顾客点菜偏好稳定,32K 词表已经足够覆盖 99% 的常见表达,还能省下大量训练预算;如果你要开“机场国际美食广场”(多语言模型),面对几十种语言的乘客,128K 词表几乎是起步线——它能用共享子词同时服务中日韩和欧洲语系,压缩率和 OOV 率都处于甜点区间。

256K 适合谁?通常是超大语料、超多语种的“旗舰餐厅”,比如覆盖 100+ 语言的互联网级语料,且你有充足的 GPU 集群和时间预算。这时 256K 把 OOV 压到 1% 以下的价值才体现得出来。选型没有绝对公式,但有可复用的决策流:先量化目标语料的语言分布和词频,再根据硬件预算算出嵌入层和 Softmax 的可承受上限,最后用 32K/128K/256K 各训一个小比例模型做比对实验,看压缩率、OOV 率与下游指标的真实变化。

这就像先画菜单再定仓库,而不是先租仓库再想菜式。记住一个经验锚点:单语 32K 起步,多语言 128K 起步,256K 只在超大语料和充足算力时入场。用数据说话,你的“餐厅”才不会在开业后才后悔备错了货。

AI 应用场景

多语言大模型训练中的Tokenizer选型

阶段:数据预处理 / Tokenizer 训练

解决的问题:传统做法直接照搬英文 32K 词表,导致中文、阿拉伯语等语言的 OOV 率奇高,压缩率低至 1.5 字符/Token,训练成本虚高。基于本文的权衡方法,团队用多语言语料统计字频词频,比较 32K/128K/256K 三档词表的压缩率与 OOV 率后发现:128K 共享子词词表能把低资源语言的 OOV 率从 18% 压到 4%,训练 Token 总量减少约 35%。

具体案例:某出海大模型公司要训练覆盖 25 种语言的基础模型,工程师用 SentencePiece 分别训练三档词表,在 1% 数据的小模型上对比困惑度与吞吐,最终选定 128K。上线后模型在多语言下游任务平均分提升 7.2%,训练成本节省约 20%。

领域模型的自定义词表设计

阶段:模型架构设计 / 增量训练

解决的问题:通用词表对垂直领域(如代码、医疗)的“黑话”覆盖不足。比如代码模型需要容纳"React"“Kubernetes“等专名,医疗模型需要”心肌梗死”"CYP2D6"等术语。通过本文的权衡框架,可以评估在 32K 基础词表上追加 N 个领域词条的成本收益。

具体案例:某医疗 AI 公司对 128K 中文通用词表做领域增强,统计电子病历语料后新增 8000 个医疗子词,OOV 率从 5.1% 降至 2.3%,命名实体识别 F1 值提升 4.8%;同时通过嵌入层参数计算确认新增开销仅约 33M 参数,完全在显存预算内。

低资源语言的词表预算分配

阶段:语料分析 / 数据平衡

解决的问题:小语种语料稀缺,在共享词表中常“抢不到位置”。运用多语言覆盖策略,可以按语言权重和子词复用度给词表做配额分配,而不是让英语主导词表结构。

具体案例:公益组织开发非洲多语言翻译模型,考察斯瓦希里语、豪萨语等语言后,把 32K 词表中英语词条占比从 70% 调降到 45%,腾出的配额给班图语系共享词缀。结果低资源语言 BLEU 平均提升 3.1,英语仅下降 0.2,整体覆盖面显著改善。

Python 演示

python42 行
"""词表大小权衡分析工具对比 32K / 128K / 256K 词表在多语言场景下的关键指标"""  def embedding_params(vocab_size: int, hidden_dim: int = 4096) -> int:    """计算词表嵌入层参数量: vocab_size * hidden_dim"""    return vocab_size * hidden_dim  def estimate_tokens(total_chars: int, chars_per_token: float) -> int:    """估算给定压缩率下, 语料产生的 token 总数"""    return int(total_chars / chars_per_token)  def main():    hidden_dim = 4096    corpus_chars = 5_000_000     # (名称, 词表大小, 每token覆盖字符数, OOV率)    configs = [        ("32K",  32000,  2.5, 0.120),        ("128K", 128000, 4.1, 0.030),        ("256K", 256000, 4.6, 0.008),    ]     print("词表大小权衡对比 (hidden_dim=4096)")    print("-" * 60)    for name, vocab, cpt, oov in configs:        params = embedding_params(vocab, hidden_dim)        n_tokens = estimate_tokens(corpus_chars, cpt)        print(f"{name}: 嵌入参数={params/1e6:.1f}M, "              f"token数={n_tokens/1000:.1f}K, OOV率={oov*100:.1f}%")     print("-" * 60)    print("结论: 资源充足且多语言覆盖优先 -> 128K 更均衡")    print("     资源受限或单语场景 -> 32K 更高效")  if __name__ == "__main__":    main()
目的:一键对比三种词表规模的嵌入参数量、语料 Token 总数与 OOV 率,为选型提供量化依据。
  1. def embedding_params(vocab_size, hidden_dim=4096)定义计算嵌入层参数的函数。
  2. return vocab_size * hidden_dim核心公式:参数量 = 词表 × 维度。
  3. estimate_tokens(total_chars, chars_per_token)用压缩率反推语料会被切成多少 Token。
  4. configs = [...]存入三档词表的关键参数(词表大小、压缩率、OOV率)。
  5. for name, vocab, cpt, oov in configs循环遍历三档配置,逐个分析。
  6. params / 1e6把参数换成 M(百万)为单位,输出更可读。
  7. print("结论: 资源充足...")根据权衡逻辑给出选型建议。

常见误区

误区我总觉得把词表从 128K 换成 256K,模型肯定更强,反正多备点食材总没错,词表大就意味着覆盖全、效果好。

正解词表越大,嵌入层和 Softmax 的参数量、显存占用、训练时间都大幅上涨,但在语料有限时,256K 反而可能带来过拟合和稀疏问题。就像仓库里堆满 1000 种调味料,但一年只用不到 100 种,大部分食材放到过期还占地方。效果曲线先升后平,32K→128K 收益大,128K→256K 常常得不偿失。

为何常见:人脑容易把“更多”等同于“更好”,尤其在看到压缩率和 OOV 率数字变好时,忽略了背后的成本维度。

误区我认为好的词表应该把 OOV 率压到 0,只要 OOV 率高就是词表设计不合格,所以必须无限扩大词表。

正解语言是活的,人名、新词、专业术语、网络流行语层出不穷,任何固定词表都无法保证 0 OOV。子词分词本身就是为了应对未知词:把未知词拆成已知子词是一种优雅的兜底。大词表把 OOV 从 12% 降到 0.8% 已经很好,追求 0 的边际成本是极端昂贵的,相当于为了万分之一罕见的“私房菜”,给整个厨房装上顶级保险柜。

为何常见:初学者看到 OOV 的定义后,容易把它当成一个“必须消灭的错误指标”,不理解 OOV 是 Open Vocabulary 场景下的固有现象。

误区既然英文用 32K 效果不错,那中文、日语、阿拉伯语也直接用 32K 就行,反正都是 Tokenizer,一套配置走天下。

正解不同语言的字符集和词法结构差异巨大。英文用 32K 能覆盖绝大多数词,中文因单字表意、词边界模糊,32K 可能 OOV 率高企;日语混合三种文字系统,32K 会捉襟见肘。多语言场景要按语料分布和子词共享率重新设计词表大小与配额,而不是简单复用一个语言的经验值。就像同一套餐具不能既满足中餐也满足法餐——筷子配牛排,终究别扭。

为何常见:主流开源模型的默认词表常以英语为中心,容易让人误以为这是“标准配置”。

误区我觉得压缩率越高越好,Token 越少模型跑得越快,所以专门挑压缩率最高的 256K 词表,以为这样模型效果也一定最好。

正解压缩率只衡量“切得省不省”,不衡量“切得准不准”。词表太大可能把语义拆得过于粗放,比如把“人工智能”整体存成一个 Token,模型虽然少算了一步,却没学会“人工”和“智能”的组成关系,面对“人工智障”这类衍生词反而无所适从。压缩率高是必要不充分条件,必须同时看下游任务指标来验证效果。

为何常见:压缩率是训练效率的直观指标,容易被当成评估模型质量的捷径,忽略了语义合成能力这一层。

面试题

Q1. 词表从32K增大到128K,当隐藏维度为4096时,嵌入层参数量大约增加了多少?

单选题 · easy

  • A.大约131M
  • B.大约262M
  • C.大约393M← 正确答案
  • D.大约524M

答案:C。32K 词表嵌入参数量为 32000×4096≈131M,128K 为 128000×4096≈524M,差额约 393M,对应 C 选项。用“食材档案柜”比喻,词表每多一种食材,就要多一份 4096 维的档案,从 32K 扩到 128K 相当于档案柜容量翻了四倍。

Q2. 关于压缩率的表述,以下哪个正确?

单选题 · mid

  • A.每字符所需Token数越低越好← 正确答案
  • B.每Token覆盖字符数越低越好
  • C.词表越大压缩率必然越低
  • D.压缩率与词表大小毫无关系

答案:A。压缩率 C = 字符数 ÷ Token 数,每个 Token 覆盖的字符越多,同样的文本切出的 Token 越少,模型处理越快,所以“每 Token 覆盖字符数高”才代表高压缩率。A 选项“每字符所需 Token 数越低”等价于高压缩率,正确。B 说反了;C 和 D 都忽略了压缩率与词表大小的正向但非必然的关联。

Q3. 词表从32K扩到128K通常会带来哪些代价?

多选题 · mid

  • A.嵌入层参数量增大← 正确答案
  • B.Softmax计算开销上升← 正确答案
  • C.训练吞吐量必然提高
  • D.内存占用明显增加← 正确答案

答案:ABD。嵌入参数量从约 131M 涨到 524M,内存占用随之上升;Softmax 要在更大的词表上计算词概率,开销也增大。C 说“吞吐量必然提高”是错的——更大的词表通常让每步训练更慢,吞吐量往往下降而不是提高。这是词表权衡中“备料成本”的直观体现。

Q4. 多语言场景中,共享子词词表的主要优势是?

单选题 · mid

  • A.每种语言单独编码效率最高
  • B.跨语言共享字符子词提升低资源语言覆盖率← 正确答案
  • C.词表可以无限增大而无需任何代价
  • D.子词共享必然降低所有语言的效果

答案:B。共享子词的核心价值在于让不同语言复用共同的字符、词缀,比如拉丁字母和常用汉字,这样低资源语言也能获得较高的覆盖率。A 是“各自为政”的思路,恰恰违背共享理念;C 忽略了词表增长的显存和计算代价;D 过于绝对,多数场景下共享子词是增益而非损失。

Q5. 遇到OOV未登录词时,子词分词器通常如何处理?

单选题 · easy

  • A.丢弃该词不参与训练
  • B.拆解成已知子词← 正确答案
  • C.直接报错终止任务
  • D.随机替换词表内词

答案:B。子词分词的核心能力就是把未知词拆成已知的子词或字符,比如把“罗望子”拆成“罗”+“望”+“子”,保证任务能继续。A 会丢失信息,C 完全不可用,D 引入噪声。用餐厅比喻,这道菜缺原料,厨师不会拒单,而是用手头的基础食材“改刀”出一份替代品。

Q6. 多语言模型中,某种低资源语言OOV率过高,最合理的改进措施是?

单选题 · mid

  • A.把词表增大到256K并重新训练整个模型
  • B.为该语言增加专用词条并调整词表配额← 正确答案
  • C.大幅减少其他语言的词条数量
  • D.忽略OOV继续训练不做任何调整

答案:B。低资源语言 OOV 高的根源是词表配额分配不均,针对性地为它增加词条并优化配额是最直接有效的办法。A 盲目增大词表成本高但不一定能解决分配问题;C 削足适履会损害其他语言;D 相当于对顾客说“这道菜我们做不了”,没有改进价值。

Q7. 关于词表大小与模型效果,下列说法正确的是?

多选题 · hard

  • A.大词表可能带来过拟合风险← 正确答案
  • B.词表过小会因切分过碎损失语义← 正确答案
  • C.词表越大下游性能线性提升
  • D.词表大小会影响收敛速度← 正确答案

答案:ABD。大词表里很多词条出现次数极少,模型容易死记它们导致过拟合,A 对;词表过小时“天安门”被切成单字,语义受损,B 对;词表大小确实影响收敛——小词表嵌入参数更新更充分,前期收敛更快,D 对。C 错在“线性提升”并不存在,效果曲线是先升后平的平台形态。

Q8. 256K词表相比128K词表,压缩率提升的典型规律是?

单选题 · hard

  • A.线性同比例增长且无成本
  • B.大幅提升且训练更快
  • C.边际递减且伴随成本上升← 正确答案
  • D.几乎完全看不到提升

答案:C。128K→256K 的压缩率提升通常只有 0.5 左右,远小于 32K→128K 的 1.6,呈现明显边际递减;同时嵌入参数量从 524M 涨到 1048M,训练更慢。C 准确描述了这一规律。A、B 违背实际经验,D 则过于极端——提升存在但很小。

Q9. 32K词表相比128K词表,最突出的优势是?

单选题 · easy

  • A.嵌入层和Softmax开销更小← 正确答案
  • B.对所有语言覆盖度更高
  • C.无需Tokenizer即可训练
  • D.压缩率和OOV表现更好

答案:A。32K 词表在嵌入层参数量、Softmax 计算量、显存占用上都明显更小,训练吞吐更友好,这是它在权衡中的核心筹码。B 说反了,大词表通常覆盖更高;C 说不需要分词器是错误的,任何词表都依赖 Tokenizer;D 中压缩率和 OOV 表现 32K 反而更差。

Q10. 选择词表大小时,需要考虑哪些关键因素?

多选题 · mid

  • A.目标语言的资源丰富度← 正确答案
  • B.硬件显存与训练预算← 正确答案
  • C.下游任务的实际需求← 正确答案
  • D.模型整体参数量规模← 正确答案

答案:ABCD。词表选型是多因素权衡:语言资源决定了多语言覆盖难度,硬件预算决定了嵌入层和 Softmax 的可承受上限,下游任务决定了语义精度要求,模型参数量影响词表占比是否合理。四个选项都指向权衡的关键维度——就像开餐厅前要同时考察客群口味、房租预算、菜系定位和厨房面积。