分词与词表

想让计算机读懂句子,第一步是把它拆成最小单元,再给每个单元发个编号

知识课 · 约 25 分钟 · 更新于 2026-08-14

第一种切法:按词分词

要把一段文本切成一个个 token,最符合直觉的单位就是「词」。 对英文来说,词与词之间有空格,所以最朴素的做法是 按空格把句子切开,再把紧贴单词的标点单独拆出来 。 例如 "I love nlp!" 会被切成 i love nlp ! 。

中文没有空格,无法直接按空格切,需要借助专门的分词工具来判断词的边界。 但无论中英文,「按词切分」的 思路 是一致的, 把文本拆成若干个独立的词(和标点),每个词就是一个 token。

词表:给每个 token 发一个编号

切出 token 之后,它们还是文字,神经网络依然没法直接用。 接下来要做的,是给每个 token 配一个唯一的整数编号。 承担这件事的,是一张叫做 词表(vocabulary,简称 vocab) 的对照表。

词表的构建很简单,把语料里出现过的所有 token 收集起来、去重, 然后给每个 token 分配一个唯一的整数 ID ,建立起 token ↔ ID 的双向映射 , 既能把 token 查成 ID(用于编码),也能把 ID 查回 token(用于解码)。 词表里 token 的总数,称为 词表大小( ) 。

有了词表,「编码」就是把一句话里的每个 token 依次查成 ID,得到一串整数; 「解码」则是反过来,把一串整数依次查回 token,拼回文本。

动手:从分词到编解码

下面用一小段语料,完整走一遍「分词 → 建词表 → 编码 → 解码」的流程。 语料只有两句话,真实场景里会是成千上万句,但步骤完全一样。

按词分词的三个痛点

按词分词直观好懂,但放到真实的大规模语料上,会暴露出三个明显的问题。

另一个极端:按字符分词

既然「按词」颗粒太粗、词表太大,那干脆走到另一个极端, 把每个字符都当成一个 token 。英文就是 26 个字母加上数字、 标点等少数符号;中文则是单个汉字。

这样做有两个立竿见影的好处:

  • 词表极小 :字符的种类远少于词,词表一下子就压到很小的规模。
  • 几乎没有 OOV :任何词都是由字符拼成的,只要字符在词表里, 再生僻的词也能逐字符拼出来,不会整词丢失。

但代价同样明显:

  • 序列变得很长 :一句话本来几个词,拆成字符后 token 数量翻好几倍, 网络要处理的序列更长,计算量随之上升。
  • 单个字符几乎没有语义 :一个孤立的字母 n 、 一个单独的「自」字,本身承载的意思非常有限,模型更难从中学到词义。

夹在中间的最佳粒度

于是分词陷入了一个两难:

最理想的,应该是一种 介于「词」和「字」之间 的粒度, 常见的词整体保留,罕见的词拆成更小但仍有意义的片段。 这种「子词」粒度,正是现代大模型实际采用的分词方式, 其中最有代表性的算法是 BPE。 它不靠人工规则,而是从语料中自动学出「哪些词保留整体、哪些词拆成片段」, 具体的工作原理会在《BPE 子词分词》中展开。

附录: <unk> 是怎么来的

在按词分词里,遇到词表里没有的未登录词(OOV)时,没法凭空造一个 ID, 通用做法是把它们 统一映射到一个专门的特殊 token ,记作 <unk> (unknown 的缩写)。词表里会预留这一个位置, 所有不认识的词都归到它名下。

这意味着「这里有个词,但我不知道是什么」,信息有损失,是按词分词为 OOV 付出的代价。还有几个常见的特殊 token(如用于补齐长度的占位符), 会在用到的时候再介绍。