在自然语言处理(NLP)领域,文本预处理一直是个基础但关键的环节。传统方法通常采用基于空格的分词或字符级处理,但这两种极端都存在明显缺陷:前者无法处理无空格语言(如中文),后者则丢失了有意义的语义单元。子词(subword)分割技术的出现,完美平衡了这两者,成为现代NLP系统的标配组件。
子词分割的核心价值在于:它将单词分解为更小的语义单元,同时保持处理效率。举个例子,英语单词"unhappiness"可以被分解为"un"、"happy"和"ness"三个有独立含义的子词。这种处理带来三个显著优势:
当前主流子词算法可分为两大阵营:
实际应用中,选择哪种算法取决于具体需求:如果追求处理速度和工程简便性,BPE是稳妥选择;如果需要更接近语言学的分割结果,Morfessor可能更合适;而像BERT这样的预训练模型则偏爱WordPiece的平衡性。
BPE算法由Philip Gage在1994年提出,后被Sennrich等人引入NLP领域。其核心是一个迭代的合并过程:
具体实现时,一个典型BPE训练过程如下(以Python伪代码示例):
python复制def train_bpe(corpus, vocab_size):
vocab = set("".join(word) for word in corpus) # 初始字符词表
while len(vocab) < vocab_size:
pairs = get_stats(corpus) # 统计符号对频率
best_pair = max(pairs, key=pairs.get)
corpus = merge_vocab(corpus, best_pair)
vocab.add(best_pair)
return vocab
BPE的优势在于:
但实际使用中需要注意:
WordPiece由Google团队提出,是BERT等模型的标准配置。与BPE的关键区别在于合并标准:
互信息(PMI)计算公式为:
code复制PMI(x,y) = log(p(x,y)/(p(x)*p(y)))
其中p(x)是x出现的概率,p(x,y)是x和y连续出现的联合概率。
这种选择标准使得WordPiece更倾向于合并那些:
在BERT的实现中,WordPiece还引入了两个特殊标记:
实践表明,WordPiece在中文处理中表现尤为出色。例如"人工智能"可能被合理地分割为"人工"+"智能",而BPE可能会产生更随机的分割。
Unigram方法采用完全不同的思路:先假设所有可能的子词都存在,然后通过概率模型筛选最优组合。其训练过程分为三步:
子词概率通过最大似然估计:
code复制p(t_i) = count(t_i) / sum(count(t_j)) for all t_j in vocab
句子分割概率则为各子词概率乘积:
code复制p(S) = ∏ p(t_i)
Unigram的特点包括:
实际应用中的一个技巧是:使用beam search(而非全局最优)来平衡分割质量和计算效率。
SentencePiece是Google开源的子词工具包,其核心价值在于:
一个典型的使用示例:
bash复制spm_train --input=corpus.txt --model_prefix=spm \
--vocab_size=8000 --character_coverage=1.0 \
--model_type=unigram
重要参数说明:
character_coverage:控制对罕见字符的覆盖(中文建议0.9995)user_defined_symbols:可以指定强制保留的tokensplit_by_whitespace:是否依赖空格(中文设为false)在跨语言任务中,SentencePiece表现尤为突出。例如,它可以自动学习到中英文共享的子词(如数字、专有名词等),这对机器翻译很有帮助。
Morfessor是专门为形态学分析设计的算法,其核心组件包括:
最新版的Morfessor 2.0采用递归分割策略:
与前面方法相比,Morfessor:
例如,对芬兰语单词"kirjoittaminen"(写作):
| 算法 | 训练速度 | 内存需求 | 分割质量 | 语言相关性 | 主要优势 |
|---|---|---|---|---|---|
| BPE | ★★★★★ | ★★☆☆☆ | ★★★☆☆ | ★☆☆☆☆ | 简单高效 |
| WordPiece | ★★★★☆ | ★★★☆☆ | ★★★★☆ | ★★☆☆☆ | 平衡性好 |
| Unigram | ★★☆☆☆ | ★★★★☆ | ★★★★★ | ★★★☆☆ | 概率解释 |
| Morfessor | ★☆☆☆☆ | ★★★★★ | ★★★★☆ | ★★★★★ | 语言学合理 |
| SentencePiece | ★★★★☆ | ★★★☆☆ | ★★★★☆ | ★★★★☆ | 工程友好 |
大规模预训练(如GPT类模型):
多语言任务(如机器翻译):
character_coverage=0.9995确保罕见字符覆盖语言学分析:
资源受限环境:
问题1:如何处理罕见字符?
--character_coverage参数问题2:词表大小如何选择?
问题3:分割不一致怎么办?
--num_threads=1确保确定性--user_defined_symbols固定关键术语在实践中,可以组合多种算法获得更好效果。例如:
这种混合方法在生物医学文本处理中表现优异。
最新研究如Dynamic Tokenization(ACL 2022)提出:
一些前沿工作尝试:
我在实际项目中发现,对于专业领域文本(如法律、医疗),先进行领域自适应训练子词模型,再接入下游任务,通常能提升3-5个百分点的性能。一个实用的技巧是:保留原始单词和其子词分割的映射关系,这对解释模型决策很有帮助。