BPE、WordPiece、SentencePiece 分词有什么区别?
BPE、WordPiece、SentencePiece 分词有什么区别?
一句话核心:这是当前主流大语言模型(如BERT、GPT、T5)底层文本处理的核心技术,通过将单词拆解为有意义的子词单元,解决OOV问题并平衡词表大小与语义信息。面试常考以区分候选人对NLP基础和大模型工程的理解深度。
核心概念(术语表)
- Tokenization (分词/切词):将原始文本流切分成模型可处理的单元(token)的过程。
- Subword Tokenization (子词切分):介于字符和单词之间的切分粒度,是当前主流方法。例如"transformers"被切分为"transform"和"ers"。
- BPE (Byte-Pair Encoding,字节对编码):一种基于频率合并的子词切分算法,核心思想是不断将出现最频繁的相邻字符对合并为新token。
- WordPiece:一种基于似然合并的子词切分算法,为BERT等模型使用,合并时选择能使语言模型概率提升最大的字符对。
- Unigram:一种基于概率裁剪的子词切分算法,从一个大词表出发,逐步删除对整体概率损失影响小的子词,常与SentencePiece联用。
- SentencePiece:一个语言无关的分词工具框架,而非单一算法,它将文本视为原始字符流,可集成BPE或Unigram算法,并将空格当作特殊字符处理。
- 词汇表 (Vocabulary):模型最终使用的token集合。子词分词的目标是在固定词汇表大小(如3万)下,覆盖所有可能的文本组合。
- OOV (Out-of-Vocabulary):未登录词,即不在训练词汇表中的词。子词分词通过将OOV拆解为已知子词来解决此问题。
- 预分词器 (Pre-tokenizer):BPE算法的第一步,基于空格或规则将原始文本初步切分为单词或更大的块。
- 合并规则 (Merge Rules):BPE算法在训练阶段学习到的字符对合并序列,用于推理时将文本切分为子词。
历史背景 / 来源
- BPE:最初是一种通用数据压缩算法(Gage, 1994),2016年由Sennrich等人引入神经机器翻译(NMT),用于解决罕见词问题,成为GPT系列的基础。
- WordPiece:由谷歌研究人员提出(Schuster & Nakajima, 2012),最初用于日文、韩文的语音搜索系统,后被BERT、DistilBERT等模型采用。
- Unigram:由Kudo(2018)提出,是一种基于概率的子词分词模型,其思想源于EM算法。
- SentencePiece:由谷歌在2018年开源,旨在提供一种与语言无关的端到端分词工具,特别适用于处理中文、日文等无空格分隔的语言。
工作原理 / 核心机制(详细讲解)
整体思路:BPE和WordPiece采用自底向上的合并策略,从字符开始构建词表;Unigram采用自顶向下的裁剪策略,从大词表开始精简;SentencePiece则是一个可搭载上述算法的预处理框架。
输入与输出:输入为原始文本字符串,输出为token序列(如['un', '##happy'])及对应的token ID序列。
BPE核心步骤详解:
- 第一步:预分词与统计:输入文本如“low lower newest”,预分词器(基于空格)将其分为[“low”, “lower”, “newest”]。统计每个词的出现频率,例如(“low”, 5), (“lower”, 2), (“newest”, 6)。
- 第二步:初始化基础词汇表:将所有单词拆成字符,并加上词尾标记。例如”low”变为”l o w
</w>”。基础词汇表为所有唯一字符,如[‘l’, ‘o’, ‘w’, ‘e’, ‘r’, ‘n’, ‘s’, ‘t’, ‘</w>’]。 - 第三步:迭代合并:计算所有相邻字符对的频率。首次合并频率最高的对,例如‘e’和‘s’(在“newest”中高频共现)。假设频率为15,则合并为‘es’,并更新所有词的表示(如”newest”变为”n e w es t
</w>”)。将‘es’加入词汇表。重复此过程,直到词汇表达到预定大小(如30000)。
WordPiece核心步骤详解:
- 前两步与BPE类似:初始化基础字符集和语言模型。
- 关键差异:合并依据不同:在每一步,不单纯看频率,而是计算合并特定字符对(如A和B)对整体语言模型概率(似然)的提升。公式核心是比较合并后的概率P(AB)与分开的概率P(A)P(B),选择比值P(AB)/(P(A)P(B))最大的对进行合并。这相当于选择在语料库中“共同出现概率远高于独立出现概率”的字符对,语义结合更紧密。
Unigram核心步骤详解:
- 第一步:初始化大词表:准备一个远大于目标大小的初始词汇表,包含所有字符、高频子串和常见词。
- 第二步:EM算法估计概率:为词表中每个子词赋予一个概率值,使用EM算法迭代优化,使得当前词表能以最高概率生成训练语料。
- 第三步:迭代裁剪:计算每个子词的“损失”,即如果删除它,整体语料似然会下降多少。按损失从小到大排序,删除损失最小的10%-20%的子词。重复步骤2和3,直至词表大小降至目标值。
SentencePiece处理流程:它接收原始句子字符串,将其中的空格(‘ ’)替换为特殊字符(如‘▁’),从而将空格信息编码进token。然后,内部调用BPE或Unigram算法进行子词切分。解码时,将‘▁’替换回空格,并拼接token还原句子。
关键知识点(15条 bullet)
- BPE合并基于字符对出现频率,简单高效,是GPT-2、GPT-3的基础。
- WordPiece合并基于语言模型似然提升,语义结合更准,是BERT、DistilBERT的基础。
- Unigram基于概率模型裁剪,从大词表开始做减法,是T5、XLNet的基础。
- SentencePiece是语言无关的框架,将空格字符化,完美处理无空格语言(如中文)。
- GPT-2词汇表大小为50,257,由256字节基础字符+50,000个合并规则构成。
- BERT-base-uncased英文词汇表大小为30,522,中文版为21,128。
- T5模型使用的SentencePiece词汇表大小为32,000。
- 子词切分常用‘##’标记非词首子词(BERT),或‘▁’标记词首(SentencePiece)。
- Byte-level BPE以单个字节为最小单位,基础字符集固定为256个,彻底解决Unicode编码问题。
- 高频词如“the”通常保持完整,生僻词如“tokenization”会被拆分为“token”和“ization”。
- 算法选择:多语言、无空格文本首选SentencePiece;追求语义精准选WordPiece;追求简单高效选BPE。
- 训练一个BPE分词器,通常需要数GB到数十GB的单语言语料。
- 分词粒度影响模型性能:太粗(词级)导致OOV,太细(字符级)导致序列过长、语义模糊。
- 子词切分本质上是数据压缩,目标是用最少的token表示最多的文本。
- 现代开源库如HuggingFace Tokenizers已集成了BPE、WordPiece、SentencePiece等多种算法。
应用场景(真实例子)
- 场景1:谷歌的BERT模型使用WordPiece进行分词。在英文维基百科和BooksCorpus上训练,词汇表约30,000,成功解决了如“transformers”等长词的OOV问题,同时将序列长度控制在合理范围(最大512 token),奠定了预训练模型的基础。
- 场景2:OpenAI的GPT-2/3模型使用Byte-level BPE。在40GB的互联网文本上训练,得到50,257的词汇表。其优势在于用256字节覆盖所有Unicode字符,包括多语言和特殊符号,使模型无需预分词器,泛化能力极强。
- 场景3:谷歌的T5、XLNet以及多语言模型MarianMT使用SentencePiece + Unigram。例如T5在混合了英语、德语、法语等多语言语料上训练,直接处理原始文本,词表大小32,000,在翻译任务中无需进行额外的分词预处理。
- 场景4:中文预训练模型如BERT-Chinese也使用WordPiece,但其预分词器基于中文单字,因此输出主要是单个汉字(如“你”,“的”),而非多字词。这简化了流程,但可能丢失部分词汇级语义。
常见误区 / 踩坑
- ❌ 误区1:以为BPE、WordPiece、Unigram是三种完全独立、互斥的算法。
✅ 正解:它们都是子词切分算法,核心目标相同(构建子词词表),但合并/裁剪策略不同。SentencePiece是一个工具框架,内部可以使用BPE或Unigram。 - ❌ 误区2:以为SentencePiece必须配合Unigram使用。
✅ 正解:SentencePiece支持两种算法。其训练命令中可通过--model_type='bpe'或--model_type='unigram'指定。实践中与Unigram联用更常见。 - ❌ 误区3:以为BPE在训练时直接处理原始字符串。
✅ 正解:BPE依赖一个预分词器先将句子切分为单词/词块(基于空格、标点等规则),然后才在这些词块内进行字符对合并。 - ❌ 误区4:以为WordPiece和BPE的合并目标完全相同。
✅ 正解:BPE目标是频率最大化,而WordPiece目标是语言模型似然提升最大化。后者理论上能找到语义结合更紧密的字符对(如“un”和“##happy”可能比“u”和“n##h”合并得分更高)。 - ❌ 误区5:认为子词切分后的token一定是有明确语言学意义的“词根”或“词缀”。
✅ 正解:子词是数据驱动的统计结果,可能包含无意义的字符组合(如“##ms”),也可能是完整的常用词。其意义在于压缩词表和覆盖OOV,而非严格的语言学分析。
性能 / 复杂度(数据驱动)
- 时间复杂度:BPE和WordPiece的训练复杂度大致为O(N * V^2),其中N为语料库token数,V为目标词表大小。推理分词复杂度为O(M * logV),M为句子长度。
- 空间复杂度:O(V) 用于存储词汇表和合并规则。在实践中,一个3万词表的分词器模型文件通常在1-10MB量级。
- 与替代方案对比:
- 方案A:全词分词:时间O(M),空间O(词表大小),词表极大(如26.7万词),导致Embedding矩阵巨大(超过10GB),且严重OOV。
- 方案B:BPE/WordPiece:时间O(M*logV),空间O(V),词表适中(3-5万),平衡性能与覆盖。
- 方案C:字符级分词:时间O(M),空间O(字符集大小,如256),序列长度倍增(5-10倍),模型训练困难。
- 临界点:当语料规模大且词汇多样性高时,子词分词优势明显。当任务极度依赖完整词义且计算资源充足时,全词分词可能更优(但实践中罕见)。
- 性能数字:在标准的英语语料上,使用HuggingFace Tokenizers库训练一个BPE分词器,处理10GB文本数据,在单个CPU核心上通常需要1-2小时。
与相关概念的区别(3对对比)
- vs 全词分词 (Word Tokenization):
- 维度1(词表大小):全词分词词表巨大(数十万),子词分词词表小而全(3-5万)。
- 维度2(OOV处理):全词分词遇生僻词用
<UNK>替代,信息损失;子词分词拆解生僻词,无信息损失。 - 维度3(适用场景):全词分词适合封闭领域、词表可控的任务;子词分词是开放域、多语言大模型的标配。
- 怎么选:除非在特定封闭场景,否则现代NLP任务几乎都首选子词分词。
- vs 字符级分词 (Character Tokenization):
- 维度1(序列长度):字符分词序列长(约为子词的2-5倍),增加计算负担;子词分词序列长度适中。
- 维度2(语义信息):字符分词每个token语义模糊;子词分词token携带部分语义。
- 维度3(模型学习):字符分词需要模型自行学习组合规则,难度大;子词分词通过分词器预置了高频组合,降低模型学习难度。
- 怎么选:研究字符级模型时可用字符分词;工程落地首选子词分词。
- vs BPE与WordPiece算法之间:
- 维度1(合并策略):BPE用频率,简单直接;WordPiece用似然,语义更准。
- 维度2(计算开销):BPE训练快;WordPiece每步需计算概率,稍慢。
- 维度3(主流采用):BPE被GPT家族、多数机器翻译模型采用;WordPiece被BERT家族采用。
- 怎么选:复现GPT类模型选BPE;复现BERT类模型选WordPiece。效果差异在实践中可能不大。
进阶 / 面试加分项
- 最新进展:谷歌2023年推出的RETVec(Resilient and Efficient Text Vectorizer)就借鉴了BPE思想,但直接在字符级进行高效编码,旨在提升抗拼写错误和对抗攻击的能力。这反映了子词思想在更基础层面的演化。
- 业界争议:是否需要在分词阶段进行更精细的语言学形态学分析(如英语的时态、词根)仍存争议。数据驱动的子词分词因其简单有效成为主流,但可能在处理形态丰富的语言(如土耳其语)时效率较低。
- 一句话送给候选人:“子词分词是大模型的‘口腔和牙齿’,决定了模型如何‘咀嚼’文本。理解BPE、WordPiece、SentencePiece的区别,不仅是记住算法,更是理解如何在词表大小、语义完整性和计算效率之间做出精妙的工程权衡。”
面试如何回答
🟢 什么是子词分词(Subword Tokenization)?它解决了传统分词的什么问题?
回答要点:
子词分词是一种介于字符和单词之间的文本切分粒度。它解决了传统全词分词面临的两大核心问题:OOV(未登录词)和词表过大。例如,对于生僻词‘tokenization’,全词分词会将其视为一个OOV并用<UNK>替代,导致信息损失;而子词分词会将其拆解为‘token’和‘##ization’这两个已知子词,既覆盖了生僻词,又保持了语义信息。同时,子词分词能将词表大小控制在3-5万的合理范围,使得模型的Embedding层参数可控(通常在100MB以内),而全词分词可能需要一个26.7万词的巨大词表,导致Embedding矩阵超过10GB,难以训练和部署。因此,子词分词是当今所有主流大语言模型(如BERT、GPT、T5)的文本处理基石。
🟡 请解释BPE分词算法的核心思想和主要步骤。
回答要点:
BPE(字节对编码)的核心思想是自底向上地构建词汇表,通过不断合并语料中出现最频繁的相邻字符对来形成新的子词单元。主要步骤包括:第一,预分词,将原始句子基于空格或标点切分为单词或词块。第二,初始化,将每个词拆分为字符序列,并建立一个包含所有唯一字符的基础词汇表。第三,迭代合并,统计所有相邻字符对的频率,将频率最高的字符对(如‘e’和‘s’)合并为一个新token(如‘es’),并将该新token加入词汇表。第四,重复第三步,直到词汇表大小达到预设值(如30,000)。训练完成后,得到一个合并规则列表,推理时按此规则对新文本进行切分。BPE的优势在于简单、高效,是GPT-2等模型的基础。
🟡 BPE和WordPiece在合并子词的策略上有什么根本区别?
回答要点:
根本区别在于选择合并哪一对子词的标准不同。BPE基于频率,它在每一步迭代中,纯粹选择语料库中共同出现次数最多的字符对进行合并,目标是最大化地压缩语料表示。而WordPiece基于似然,它在每一步迭代中,选择合并后能使得整个训练语料在语言模型下的概率(似然)提升最大的字符对,即计算P(AB) / (P(A) * P(B))的比值,选择比值最大的对进行合并。这实质上是在寻找那些共同出现概率远高于独立出现概率的字符对,因此WordPiece被认为在语义结合上可能更精准。例如,在‘unhappy’中,WordPiece可能会优先合并‘un’和‘##happy’,因为‘un’作为一个前缀与形容词的结合概率非常高,而BPE可能只看‘u’、‘n’、‘h’等字符对的局部频率。
🟡 为什么说SentencePiece不是一个具体的分词算法,而是一个框架?它在处理中文等语言时有什么独特优势?
回答要点:
SentencePiece是一个与语言无关的分词框架,因为它内部可以集成BPE或Unigram等具体算法。其核心创新在于处理流程:它首先将输入文本视为一个完整的字符序列,并将空格(‘ ’)也当做一个特殊字符(如‘▁’)进行编码,从而将分词过程从依赖语言特定的空格规则中解放出来。对于中文、日文这种本身没有空格分隔符的语言,传统分词需要先调用分词库(如Jieba)进行预分词,而SentencePiece可以直接处理原始汉字序列,通过其内部的子词算法学习出有意义的组合(如可能将高频共现的‘机器’‘学习’合并)。因此,其优势是真正的端到端、语言无关,避免了预分词错误传播,并能统一处理多语言文本。T5、XLNet等多语言模型均采用此方案。
🔴 在实际的预训练模型中,BPE、WordPiece和SentencePiece(通常与Unigram联用)分别是哪些代表性模型在使用?这种选择反映了模型设计上的什么考量?
回答要点:
这种选择体现了模型架构和设计哲学的不同。首先,BPE 是OpenAI GPT系列(GPT-1/2/3/4)的基础,甚至在其Byte-level版本中应用。GPT作为自回归语言模型,BPE的简单高效和优秀的文本压缩能力,非常适合其大规模语料的预训练和高效的文本生成。其次,WordPiece 是谷歌BERT、DistilBERT、ELECTRA等模型的基础。BERT作为掩码语言模型,更注重对上下文语义的双向理解,WordPiece基于似然的合并策略可能提供了更精细的语义单元,有助于模型学习更准确的上下文表示。最后,SentencePiece + Unigram 是谷歌T5、XLNet以及多语言模型MarianMT的选择。T5将一切任务统一为文本到文本,且处理多语言,SentencePiece的端到端、语言无关特性至关重要;Unigram的概率模型则可能提供了更稳定的切分结果。因此,这种选择并非优劣之分,而是由模型目标(自回归 vs 双向)、处理语言(单语 vs 多语)和工程传统共同决定的。
🔴 假设你要从零开始为一个全新的、包含大量专业术语和罕见字符的领域(如生物化学)训练一个分词器,你会如何选择和配置分词算法?需要考虑哪些关键参数?
回答要点:
我会优先选择 SentencePiece框架,并配置为Unigram或BPE算法。原因如下:第一,领域专业术语和罕见字符多,预分词(如基于空格)可能无效,SentencePiece直接处理原始文本的特性是关键。第二,Unigram算法基于概率裁剪,对于发现领域内有意义的子词组合可能更鲁棒;BPE作为备选,训练更快。关键配置参数包括:1. vocab_size:这是最重要的参数。我需要在模型性能和序列长度之间权衡。对于生物化学,可能需要一个比通用模型更大的词表(如40,000-50,000),以容纳更多专业子词,避免过多拆分。我会通过在不同词表大小下评估下游任务(如命名实体识别)的性能来选择最优值。2. character_coverage:对于罕见字符多的领域,应设为1.0或接近1.0,确保所有字符都能被编码,防止出现未知字符。3. input_sentence_size:由于专业语料可能稀缺,此参数可设置为语料库的全部大小,充分利用所有数据。4. 训练语料:必须使用大量该领域的专业文献作为训练数据,而非通用文本。我会先用Unigram训练一个模型,观察其切分出的子词是否包含领域内的有意义词根,再微调参数。
🟢 什么是Byte-level BPE?它解决了标准BPE的什么问题?
回答要点:
Byte-level BPE是对标准BPE的一个重要改进。标准BPE以Unicode字符为基本单位,当处理包含大量不同语言或特殊符号的文本时,其基础字符集可能会变得非常大(成千上万)。Byte-level BPE的做法是,不再以字符为最小单位,而是以单个字节(0-255)为最小单位。无论一个Unicode字符实际由几个字节组成,它都被视为一个或多个独立的字节序列。这样,基础词汇表的大小就被严格锁定在256个可能的字节值上,从而完美解决了Unicode字符集无限的问题。例如,GPT-2就采用了这种方法,其50,257的词汇表构成是:256个字节基础字符 + 1个句尾标记<EOS> + 50,000个通过合并规则学习的子词。这使得模型能够处理任何语言的文本、甚至二进制数据,泛化能力极强。
🟡 在模型推理时,分词器如何将一句新话转换为token ID序列?请以‘Unhappily’这个词为例,说明BPE分词器的处理过程。
回答要点:
在推理阶段,分词器使用训练阶段学到的合并规则列表,自左向右扫描输入文本。以‘Unhappily’为例,BPE分词器的处理过程如下:第一步,预分词(如果需要)将句子切分为单词。第二步,将单词‘Unhappily’拆分为初始字符序列:[‘U’, ‘n’, ‘h’, ‘a’, ‘p’, ‘p’, ‘i’, ‘l’, ‘y’]。第三步,按照合并规则列表,从前往后依次查找可以合并的字符对。假设规则列表中有‘p’ + ‘p’ -> ‘pp’、‘l’ + ‘y’ -> ‘ly’、‘happ’ + ‘ily’ -> ‘happily’等规则。分词器会先找到序列中第一个可以应用的规则,比如‘p’和‘p’相邻且规则存在,于是合并为‘pp’,序列变为[‘U’, ‘n’, ‘h’, ‘a’, ‘pp’, ‘i’, ‘l’, ‘y’]。第四步,继续扫描,可能找到‘l’和‘y’合并为‘ly’,序列变为[‘U’, ‘n’, ‘h’, ‘a’, ‘pp’, ‘i’, ‘ly’]。第五步,可能继续合并‘happ’和‘ily’(如果规则存在且序列相邻),最终得到[‘U’, ‘n’, ‘happily’]或进一步合并为[‘Un’, ‘happily’]。这个过程完全由静态的规则驱动,是确定性的,最终得到子词token列表。然后,分词器通过词汇表将这些子词映射为对应的整数ID序列,输入给模型。
