分词 (Tokenization)

将文本分割为令牌 (词、子词或其他处理单位) 的过程。

分词 (tokenization) 是将文本分割为令牌 (token) 的过程,令牌是文本处理的基本单位。它是自然语言处理 (NLP) 和大语言模型 (LLM) 不可或缺的预处理步骤,分割的粒度和方式会显著影响后续处理的精度。令牌的单位可以是词、子词、字符或字节,根据目的灵活选择,同一文本使用不同的分词器会产生不同的分割结果。

代表性的分词方法包括词级分割、子词分割和字符级分割。词级分割对于英语等以空格分隔的语言来说很直观,但存在无法处理未登录词 (词汇表中不存在的词) 的问题。解决这一课题的是子词分割,算法上广泛使用的是 BPE (Byte Pair Encoding)、WordPiece、Unigram 语言模型这几个系统。BPE 通过反复合并高频出现的字符串对来构建词汇表,被 GPT 系列的分词器 (tiktoken) 所采用。WordPiece 则是 BERT 系模型一直使用的方法。这里容易混淆的是 SentencePiece,它并不是算法的名称,而是同时实现了 BPE 与 Unigram 语言模型的库。它的特点是可以直接对原始句子进行训练,不需要事先做词语切分,因此仅凭 "使用了 SentencePiece" 这一信息并不能确定分割方式。

日语的分词比英语复杂得多。由于日语词与词之间没有空格,需要使用形态素分析器 (MeCab、Sudachi、Janome 等) 来推断词边界。此外,面向 LLM 时通常使用 SentencePiece 这类与语言无关的子词分词器,日语的汉字和假名会被分割为细粒度的子词。例如 "東京都" 可能被分割为 "東京" + "都",也可能被分割为 "東" + "京" + "都",结果会随分词器的词汇量大小而变化。

在实际工作中,分词特别重要的场合是 LLM 的使用成本管理。ChatGPT、Claude 等 API 根据输入输出的令牌数计费,因此相同内容下令牌数更少的提示词能够压低成本。中文、日语这类 CJK 文本的令牌效率往往低于英语 (相同含义的文本令牌数更多),1 个日语字符被分割为 1 到 3 个令牌的情况也不罕见。因此在用日语设计提示词时,有意识地关注令牌数并让文本更加简洁就很重要。

一个常见的误解是把字符数等同于令牌数。实际上英语中 1 个单词大致是 1 到 2 个令牌,而日语中 1 个字符可能变成多个令牌,字符数与令牌数并不一致。而且分词器因模型而异,同一文本在 GPT-4 和 Claude 中得到的令牌数也不相同。要准确掌握令牌数,需要使用各模型专用的分词器事先计算。

按目的区分使用也是需要掌握的一点。在创建搜索索引、统计关键词这类希望得到 "人能读出含义的单位" 的场合,形态素分析更合适;而在把输入交给模型的场合,只能使用该模型专用的子词分割。若把前者的结果拿来代替后者,令牌数的估算就会与实际计费对不上。此外,分割结果受 "词典或词汇表的版本" 的影响甚至超过分割器本身。同样是 MeCab,把词典从 IPAdic 换成 UniDic,词语的切分位置和词性都会改变,统计结果随之偏移。LLM 一侧也是如此,更换模型或升级到新的世代时词汇表会被替换,以前测出的估算值不能照旧使用。当要以令牌数为依据来设计上限或费用时,把所使用的分割器及其版本记录下来,日后就能追查差异的成因。

在与字符计数的关联上,实际工作中会用字符数、字节数、令牌数这三种尺度来衡量文本的 "长度"。社交媒体的发帖限制以字符数管理,LLM 的输入输出限制以令牌数管理,而数据库列的上限按字符数还是字节数计算,则取决于产品以及类型的指定方式。这三种尺度之间无法互相换算,因此先分辨清楚究竟撞到了哪一种限制,是不把截断与拆分的设计做错的前提。

分享这篇文章