大模型Tokenizer原理:深入理解BPE与WordPiece子词编码技术
大模型Tokenizer原理深入理解BPE与WordPiece子词编码技术在大型语言模型的技术架构中Tokenizer分词器是连接原始文本与模型输入的关键桥梁。不同于简单的按空格或标点分割一个优秀的分词器需要将文本切分为模型能够高效处理的Token序列同时尽可能保留语义信息。本文深入剖析当前大模型中最常用的两种子词分词算法——Byte Pair EncodingBPE和WordPiece从底层原理到代码实现进行全面讲解。BPE算法原理与训练过程BPE最初由Philip Gage在1994年提出用于数据压缩领域。其核心思想是通过迭代合并高频出现的字节对来构建符号表。这一思想被迁移到NLP领域后成为构建子词词汇表的标准方法。BPE训练的核心流程如下。首先将训练语料中的每个单词拆分为字符序列并在每个单词末尾添加特殊分隔符。同时统计每个单词出现的频率。例如单词higher会变为h i g h e r“单词low变为l o w ”。初始词汇表包含所有单个字符和特殊分隔符。接下来进入迭代合并阶段。在每次迭代中算法遍历所有相邻字符对统计它们在语料库中共同出现的总频率。选择频率最高的字符对作为合并规则加入词汇表并将语料库中所有该字符对合并为一个新符号。这个过程重复进行直到词汇表达到预设大小。假设语料库中有单词low出现5次“lower出现2次“new出现3次。在初始状态下字符序列分别为l o w”、“l o w e r和n e w”。经过若干次迭代后可能形成lo”、wer等子词单元这些子词能够组合表示原单词同时在统计意义上具有更高的出现频率。BPE的最终分词过程是确定性的。对于任意输入单词首先拆分为字符序列然后从左到右遍历贪心地应用已学到的合并规则。每次检查当前位置是否存在可合并的字符对如果存在则合并否则保持原样并移动到下一个位置。这种方法保证每个单词都能被分解为词汇表中的子词组合。WordPiece算法深度解析WordPiece是Google为语音搜索系统开发的分词技术后被BERT采用并广为人知。与BPE基于频率的贪心合并不同WordPiece采用基于概率的训练目标这导致了本质性的差异。WordPiece的训练目标是最大化训练语料的语言模型概率。给定一个单词序列完整的分词方案是将其切分为若干子词单元。设分词结果为(t1, t2, …, tn)则该分词方案的语言模型概率为各个子词条件概率的乘积P(分词) P(|t1) × P(t1|t2) × P(t2|t3) × … × P(tn-1|tn)每个条件概率P(ti|ti1)可以通过统计训练语料中子词对的出现频率计算得到P(ti|ti1) Count(ti, ti1) / Count(ti1)。在训练过程中WordPiece需要决定哪两个子词应该合并。不同于BPE直接选择最高频的字符对WordPiece评估的是合并后对语言模型概率的提升。具体来说对于候选合并对(A, B)计算合并前的联合概率贡献与合并后的联合概率贡献之差选择使整体似然提升最大的对。这个差异在实际应用中产生了明显区别。考虑单词unsupervisedBPE可能优先合并出现频率最高的字符对而WordPiece会考虑合并后对整体句子概率的影响。如果un和super在语料中有明确且独立的语义作用WordPiece可能选择保留它们而非强行合并。分词阶段也存在差异。BPE采用确定性的贪心匹配而WordPiece通常采用动态规划或类似Viterbi算法来寻找最优分词路径。具体而言对于输入单词从右到左或从左到右遍历所有可能的分词位置计算每种分词方案的概率选择概率最高的方案。BPE代码实现详解理解算法原理后通过代码实现可以更深入地掌握细节。以下是一个完整的BPE训练和分词实现。fromcollectionsimportCounter,defaultdictimportreclassBPE:def__init__(self,vocab_size10000):self.vocab_sizevocab_size self.vocab{}self.merges{}defget_stats(self,vocab):统计所有字符对的频率pairsCounter()forword,freqinvocab.items():symbolsword.split()foriinrange(len(symbols)-1):pairs[(symbols[i],symbols[i1])]freqreturnpairsdefmerge_vocab(self,pair,vocab):合并所有词汇中的指定字符对v_out{}bigramre.escape(pair[0] pair[1])patternre.compile(r(?!\S)bigramr(?!\S))forwordinvocab:w_outpattern.sub(.join(pair),word)v_out[w_out]vocab[word]returnv_outdeftrain(self,corpus): 训练BPE模型 corpus: 单词列表 # 初始化词汇表每个单词拆分为单字符vocabCounter()forwordincorpus:word_tokenslist(word)[/w]vocab[ .join(word_tokens)]1# 迭代合并whilelen(vocab)self.vocab_size:pairsself.get_stats(vocab)ifnotpairs:breakbest_pairmax(pairs,keypairs.get)vocabself.merge_vocab(best_pair,vocab)self.merges[best_pair]Trueself.vocab[best_pair]len(self.vocab)print(f合并{best_pair}词汇表大小:{len(vocab)})# 添加单字符到词汇表forcharinset(.join(corpus))):ifcharnotinself.vocab:self.vocab[char]len(self.vocab)deftokenize(self,text):对输入文本进行分词tokenslist(text)[/w]whilelen(tokens)1:# 寻找第一个可合并的位置pairs[(tokens[i],tokens[i1])foriinrange(len(tokens)-1)]# 找优先级最高的合并min_rankNonemin_pairNoneforpairinpairs:ifpairinself.merges:rankself.merges[pair]ifmin_rankisNoneorrankmin_rank:min_rankrank min_pairpairifmin_pairisNone:break# 执行合并new_tokens[]i0whileilen(tokens):ifilen(tokens)-1and(tokens[i],tokens[i1])min_pair:new_tokens.append(.join(min_pair))i2else:new_tokens.append(tokens[i])i1tokensnew_tokensreturn[tfortintokensift!/w] 这段实现展示了BPE的核心机制词汇表构建阶段的迭代合并和分词阶段的贪心应用。关键点在于使用空格分隔符来标记字符边界以及通过re.escape处理可能包含特殊字符的合并对。### WordPiece代码实现WordPiece的实现更加复杂因为它需要维护完整的词汇表并使用动态规划进行最优分词。 pythonclassWordPiece:def__init__(self,vocabNone):self.vocabvocabor{}self.unk_token[UNK]self.unk_id0deftokenize(self,text):对文本进行分词返回子词序列output_tokens[]fortokeninself._basic_tokenize(text):charslist(token)iftokeninself.vocab:output_tokens.append(token)continue# 尝试将单词切分为子词tokens[]start0whilestartlen(chars):endlen(chars)cur_substrNone# 从后向前寻找最长匹配whilestartend:substr.join(chars[start:end])ifstart0:substr##substrifsubstrinself.vocab:cur_substrsubstrbreakend-1ifcur_substrisNone:# 没有找到匹配返回UNKoutput_tokens.append(self.unk_token)breaktokens.append(cur_substr)startend output_tokens.extend(tokens)returnoutput_tokensdef_basic_tokenize(self,text):基础分词处理标点和空格importre# 简单实现按空格分词保留标点tokensre.findall(r\w|[^\s\w],text)return[t.lower()fortintokens] 实际应用中WordPiece词汇表通常由专门的工具如Google的sentencepiece或BERT的tokenization工具生成。词汇表中的子词带有特定前缀标记##表示这是词内延续。### 大模型中的Tokenizer选择不同大模型选择了不同的Tokenizer策略这些选择深刻影响了模型的能力边界。 GPT系列采用BPE的变体——ByteLevelBPE。关键改进是使用UTF-8字节而非Unicode字符作为初始单位。UTF-8中任何字符都可以表示为1-4个字节这意味着词汇表可以从256个基础字节开始训练。这种方法有两个优势理论上有无限的字符词汇表以及能够处理任意Unicode字符串而不会出现未知字符问题。GPT-4的词汇表包含超过10万个Token反映了其处理多语言和特殊符号的能力。 BERT采用WordPiece这与其预训练任务设计密切相关。BERT使用Masked Language Modeling需要将输入的一部分Token替换为[MASK]WordPiece的概率优化目标与此高度一致。此外BERT的词汇表中包含丰富的词根和词缀这有助于模型学习形态学特征。 SentencePiece是另一个值得了解的框架由Google开发并被T5等模型采用。SentencePiece将输入视为原始字节流可以直接训练BPE或Unigram模型无需预分词步骤。这种端到端的处理方式避免了不同语言的分词规则差异更适合多语言模型。### 分词对模型的影响理解Tokenizer的选择对实际应用至关重要。相同的文本经过不同Tokenizer会产生显著差异的Token序列长度。以神经网络Transformer大模型为例 使用较小词汇表的Tokenizer可能产生15-20个Token而使用更大词汇表的Tokenizer可能只需要8-12个Token。Token数量的差异直接影响计算成本与Token数的平方成正比、显存占用和推理延迟。 此外分词粒度影响模型对语义的理解能力。过粗的分词如按空格分词会导致严重的OOV问题过细的分词如纯字符级会显著增加序列长度削弱模型捕捉长距离依赖的能力。子词分词在两者之间取得了平衡通过数据驱动的方式学习适合目标语料的词汇表。---标签大模型、Tokenization、BPE、WordPiece、NLP
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2568827.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!