← 返回首页

Tokenization 算法详解

BPE、WordPiece、SentencePiece 分词算法的实现与对比

什么是 Tokenization?

Tokenization(分词)是将原始文本转换为模型可处理的token序列的过程。在深度学习中,模型无法直接处理原始文本,需要将文本分解为更小的单元(tokens),并将其映射为数值表示。

输入文本: "机器学习很有趣"
字符级: ["机", "器", "学", "习", "很", "有", "趣"]
词级: ["机器学习", "很", "有趣"]
子词级: ["机器", "学习", "很", "有趣"]

Tokenization 的重要性

  • 词汇表大小控制:平衡表达能力和计算效率
  • 未知词处理:处理训练时未见过的词汇
  • 语义保持:保留词汇的语义信息
  • 多语言支持:统一处理不同语言的文本

传统分词方法的局限性

基于空格的分词

优势

  • 简单直观,易于实现
  • 保留完整词汇语义
  • 适用于英语等语言

劣势

  • 词汇表过大,内存占用高
  • 无法处理未知词(OOV)
  • 不适用于中文等语言
  • 无法处理形态变化

字符级分词

优势

  • 词汇表小,无OOV问题
  • 适用于所有语言
  • 能处理拼写错误

劣势

  • 序列长度大大增加
  • 丢失词汇级别的语义
  • 计算成本高

BPE (Byte Pair Encoding) 算法

BPE 是一种数据压缩技术,后来被应用于自然语言处理。它通过迭代地合并最频繁出现的字符对来构建词汇表。

BPE 算法步骤

训练阶段:

  1. 将训练语料分解为字符序列
  2. 统计所有相邻字符对的频率
  3. 合并频率最高的字符对
  4. 重复步骤2-3,直到达到预设的词汇表大小

BPE 实例演示

初始词汇: ["low", "lower", "newest", "widest"]
字符序列: ["l o w ", "l o w e r ", "n e w e s t ", "w i d e s t "]

迭代1: 最频繁对 "e s" → "es"
["l o w ", "l o w e r ", "n e w es t ", "w i d es t "]

迭代2: 最频繁对 "es t" → "est"
["l o w ", "l o w e r ", "n e w est ", "w i d est "]

迭代3: 最频繁对 "l o" → "lo"
["lo w ", "lo w e r ", "n e w est ", "w i d est "]
BPE 算法训练实现

def train_bpe(corpus, num_merges):
    # 初始化词汇表为字符级别
    vocab = get_character_vocab(corpus)
    
    for i in range(num_merges):
        # 统计字符对频率
        pairs = get_pair_frequencies(corpus)
        if not pairs:
            break
            
        # 找到频率最高的字符对
        best_pair = max(pairs, key=pairs.get)
        
        # 合并字符对
        corpus = merge_pair(corpus, best_pair)
        vocab.add(''.join(best_pair))
    
    return vocab
                    

WordPiece 算法

WordPiece 是Google开发的子词算法,被用于BERT等模型。与BPE类似,但使用不同的合并策略。

WordPiece 与 BPE 的区别

特性 BPE WordPiece
合并策略 基于频率 基于似然度提升
评分函数 count(A,B) count(A,B) / (count(A) × count(B))
子词标记 @@标记 ##标记
应用模型 GPT系列 BERT系列

WordPiece 合并准则

似然度提升公式:

对于字符对 (A, B),合并后的得分为:

$$\text{Score}(A, B) = \frac{\text{freq}(AB)}{\text{freq}(A) \times \text{freq}(B)}$$

WordPiece 示例:
输入:playing
输出:play ##ing

输入:unaffable
输出:un ##aff ##able

SentencePiece 算法

SentencePiece 是Google开发的无监督文本分词器,它将文本视为Unicode字符序列,不依赖于语言特定的预处理。

SentencePiece 的核心特点

  • 语言无关:统一处理所有语言,包括没有明显词边界的语言
  • 可逆性:分词结果可以无损地还原为原始文本
  • 空格处理:将空格视为特殊字符 ▁ 进行处理
  • 端到端:从原始文本直接到子词,无需预分词

SentencePiece 处理流程

原始文本: "Hello world"
Unicode normalization: "Hello world"
空格替换: "Hello▁world"
子词分割: ["Hell", "o", "▁wor", "ld"]
还原: "Hello world"

训练步骤:

  1. 将文本标准化为Unicode NFC格式
  2. 将空格替换为特殊符号 ▁
  3. 应用BPE或Unigram算法学习子词
  4. 生成词汇表和分词模型

Unigram Language Model

Unigram语言模型是另一种子词分割算法,与BPE采用自底向上的方法不同,它采用自顶向下的方法。

Unigram 算法原理

目标函数:最大化语料库的对数似然

$$\mathcal{L} = \sum_{i=1}^{|D|} \log P(X_i)$$

其中 $P(X_i) = \sum_{x \in S(X_i)} \prod_{j=1}^{|x|} p(x_j)$

算法步骤:

  1. 初始化一个足够大的候选词汇表
  2. 使用EM算法优化Unigram语言模型
  3. 计算每个子词的损失值
  4. 删除损失最小的子词(保留一定比例)
  5. 重复步骤2-4直到达到目标词汇表大小

算法对比与选择

算法 训练复杂度 分词速度 语言支持 代表模型
BPE 需要预处理 GPT, GPT-2
WordPiece 中等 需要预处理 BERT, DistilBERT
SentencePiece 中等 语言无关 T5, XLNet
Unigram 中等 语言无关 ALBERT, T5

选择建议

  • 英语为主:BPE 或 WordPiece
  • 多语言:SentencePiece + Unigram
  • 计算资源有限:BPE
  • 追求最佳性能:SentencePiece + Unigram

实际应用中的考虑因素

词汇表大小设计

  • 小词汇表 (8K-16K):计算高效,但可能增加序列长度
  • 中等词汇表 (32K-64K):平衡性能和效率的常见选择
  • 大词汇表 (100K+):更好的语言覆盖,但内存开销大

特殊token处理

常见特殊token:
[CLS] - 分类任务的开始标记
[SEP] - 句子分隔符
[PAD] - 填充标记
[UNK] - 未知词标记
[MASK] - 掩码语言模型的掩码标记

性能优化技巧

  • 预计算:缓存常见词的分词结果
  • 并行处理:批量处理多个文本
  • 内存优化:使用trie树存储词汇表
  • 增量训练:支持词汇表的动态更新

🔧 交互式演示

点击按钮体验不同的分词算法: