分词 (Tokenization) —— 把句子切成有意义的“积木”

计算机不认识“字”或“词”,它只认识数字。分词的第一步,就是把一句话切分成一个个最小的、有意义的单元,我们称之为 “Token” 。

  • 什么是 Token?

    • 对于英文,Token 通常是单词(如 “help”)或子词(如 “generating” 可能会被切成 “generat” 和 “ing”)。
    • 对于中文,Token 可以是单个汉字,也可以是词语。现代 LLM 的中文分词器通常是字词混合的。
  • 例子:“请帮我生成一首诗”

    1. 切分 :一个现代的分词器(比如 Google 的 SentencePiece 或 OpenAI 的 Tiktoken)可能会将这句话切分成如下的 Tokens: [“请”, “帮”, “我”, “生成”, “一首”, “诗”] (这是一个简化的例子,实际分词可能更细,但原理相同)

    2. 查字典(Vocabulary Lookup) :LLM 拥有一个巨大的“字典”(Vocabulary),这个字典在训练阶段就已经构建好了,包含了它所认识的所有 Tokens。字典的大小可能在 5万到 20万之间。每个 Token 在字典里都有一个独一无二的整数 ID。
      假设字典的一部分是这样的:

      • “请”: 8
      • “帮”: 121
      • “我”: 33
      • “生成”: 556
      • “一首”: 982
      • “诗”: 105
    3. 转换成 ID 序列 :于是,句子就从一串文字,变成了一串整数: [8, 121, 33, 556, 982, 105]

至此,分词完成。我们得到了一串代表您输入指令的数字 ID。


Tokenization算法

Tokenization 的核心任务是“切分”,即决定文本的最小单元是什么。现代大模型主要使用基于子词(Subword) 的分词算法。其中最主流的两种是:

  1. BPE (Byte-Pair Encoding) :GPT 系列(包括 ChatGPT)、BERT 等模型广泛使用。
  2. SentencePiece :Google 的 T5、BERT 等模型使用,它将 BPE 和另一种叫做 Unigram 的算法封装得很好。
    我们以 BPE 为例,来详细解释这个过程。

BPE (Byte-Pair Encoding) 分词算法详解

BPE 的核心思想非常优雅: 在效率和词汇表大小之间找到一个完美的平衡点。

  • 如果完全按 词 来分,词汇表会爆炸(比如 “apple” 和 “apples” 是两个词),而且会遇到大量 未登录词(Out-of-Vocabulary, OOV) ,比如一个新造的网络词或拼写错误。
  • 如果完全按 字符 来分,词汇表很小(比如英文26个字母+符号),不会有 OOV 问题,但一个单词会被切得太碎,失去了很多语义信息,而且序列会变得非常长,计算效率低。
    BPE 巧妙地结合了两者的优点。它的工作流程分为两个阶段:
阶段一:构建词汇表(在模型训练前完成)

这个阶段的目标是学习出一套最高效的“合并规则”,并最终形成一个固定大小的词汇表(比如 50,000 个)。

  1. 初始词汇表 :

    • 首先,我们从最基础的单元开始。对于英文,就是 26 个字母和各种符号。对于中文,就是所有单个的汉字(比如 GBK 字符集里的几千个汉字)和符号。
    • 假设我们的初始词汇表是 [‘a’, ‘b’, ‘c’, …, ‘z’, ‘!’, ‘?’, …] 。
  2. 准备语料库 :

    • 拿出我们庞大的训练语料库(比如维基百科的所有文章)。
  3. 迭代合并 :

    • 第 1 步 :统计语料库中,所有相邻的两个字符(Byte Pair)出现的频率。假设我们发现 “t” 和 “h” 这对组合出现的频率最高。
    • 第 2 步 :将这个最高频的组合 (“t”, “h”) 合并成一个新的、更大的单元 “th” 。
    • 第 3 步 :将这个新的单元 “th” 添加到我们的词汇表中。现在的词汇表就变成了 [‘a’, …, ‘z’, …, “th”] 。
    • 第 4 步 :回到语料库,将所有 “t”, “h” 的地方都替换成 “th” 。
    • 重复 :不断重复上面的 1-4 步。下一次,可能会发现 “th” 和 “e” 组成的 “the” 频率最高,于是我们再合并 “the” ,并加入词汇表。再下一次,可能是合并 “i” 和 “n” 得到 “in” ,然后是 “ing” …
    • 这个过程会一直持续下去,直到词汇表的大小达到我们预设的上限(比如 50,000)。
      这个阶段完成后,我们就得到了一个包含“基础字符”和大量高频“子词”的最终词汇表。
  • 对于英文 ,这个词汇表里会有 a , b , c … 这样的单字符,也会有 th , ing , ation 这样的子词,还会有 the , a , is 这样完整的高频词。
  • 对于中文 ,词汇表里会有 我 , 你 , 他 … 这样的单字,也会有 的 , 了 … 这样的助词,还会有 生成 , 模型 , 北京 … 这样高频的词语。
阶段二:对新输入进行分词(提问时发生)

现在,我们已经有了固定的词汇表和通过学习得到的一系列“合并规则”。当您输入新句子时,分词器会严格按照这些规则来切分。

例子 1:一个认识的词

  • 输入: “generation”

  • 分词过程:

    1. 首先切成基础字符: [‘g’, ‘e’, ‘n’, ‘e’, ‘r’, ‘a’, ‘t’, ‘i’, ‘o’, ‘n’]
    2. 然后,分词器会应用它在训练阶段学到的合并规则。它知道 “ge” 是一个单元, “ner” 是一个单元, “ation” 是一个单元(这只是一个假设的例子)。
    3. 最终结果可能是: [“ge”, “ner”, “ation”]
      例子 2:一个不认识的词(OOV 问题)
  • 输入: “tokenizationaaa” (假设 “aaa” 是一个无意义的后缀)

  • 分词过程:

    1. 分词器会成功地将 “tokenization” 切分成它认识的子词,比如 [“token”, “ization”] 。
    2. 当它遇到 “aaa” 时,它发现在词汇表里找不到任何包含 a 的、更大的合并单元。
    3. 于是,它只能将 “aaa” 切分成最基础的字符单元。
    4. 最终结果可能是: [“token”, “ization”, “a”, “a”, “a”]
      例子 3:您的中文输入
  • 输入: “请帮我生成一首诗”

  • 分词过程:

    1. 分词器在它的中文词汇表里查找。它发现 “生成” 和 “一首” 是非常高频的词,并且存在于词汇表中。
    2. 而 “请” , “帮” , “我” , “诗” 作为单个字也非常常见,也在词汇表中。
    3. 因此,最有效率的切分方式就是: [“请”, “帮”, “我”, “生成”, “一首”, “诗”] 。
    4. 如果输入是“请帮我生成一首藏头诗”,而“藏头诗”这个词在训练时出现频率不高,没有被合并成一个单独的 Token,那么结果就可能会被切分成 [“藏”, “头”, “诗”] 。

总结与优势

现代大模型使用的 BPE (子词) 分词法 ,相比于“独热编码”时代,其优势是压倒性的:

  1. 解决了 OOV 问题 :任何新词、拼写错误、甚至无意义的字符串,最终都可以被切分成基础的字符单元,模型总能处理,永远不会遇到“不认识的词”。
  2. 平衡了效率与语义 :常见词被保留为完整单元,保留了语义,减少了序列长度;生僻词被切分成子词或字符,保证了模型的泛化能力。
  3. 词汇表大小可控 :我们可以预先设定词汇表的大小,这是一个非常重要的工程考量。
    所以,Tokenization 是一个纯粹的、基于统计和规则的“文本切分”过程。它本身不涉及任何向量运算,它的唯一目的就是将一长串文本,转换成一串整数 ID,为下一步的**词嵌入(Embedding)**做好准备。

参考资料:
https://zhuanlan.zhihu.com/p/27312309014
https://zhuanlan.zhihu.com/p/28806013939

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐