首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >NLP基础(分词):BPE 算法

NLP基础(分词):BPE 算法

作者头像
三猫
发布2025-11-28 18:54:10
发布2025-11-28 18:54:10
160
举报

导读:在自然语言处理(NLP)领域,分词是文本预处理中的一个关键步骤。分词的目的是将文本分解成有意义的单元,以便模型能够更好地理解和处理。传统的分词方法通常基于固定词汇表,如基于单词的分词。然而,这种方法在处理未知单词和稀有单词时存在局限性。为了解决这一问题,BPE算法应运而生。BPE算法是一种基于子词(subword)的分词方法,能够将单词分解成更小的子词单元,从而提高模型的泛化能力和灵活性。

1

算法原理

BPE(Byte Pair Encoding) 算法是一种基于频率的子词分割方法,其核心思想是将单词分解成更小的子词单元,这些子词单元可以是完整的单词、单词的前缀、后缀或中间部分。这种方法在处理未知单词和稀有单词时特别有效,因为它可以将这些单词分解成已知的子词单元,从而提高模型的泛化能力。

2

实现步骤

假设我们有一个训练语料 D,其中每个单词 w 由字符序列 w=c1,c2,…,cn组成。BPE 算法的目标是构建一个子词词汇表 V,使得每个单词 w 可以被分割成子词单元 w=v1,v2,…,vm,其中 viV。

step 1 : 初始化词汇表

将所有字符(Unicode)作为初始词汇表的基本单元。

step 2 : 统计字符对频率

对训练语料中的每个单词,统计相邻字符对的出现频率。

step 3 : 合并最频繁字符对

将最频繁的字符对作为一个新单元加入词汇表,并更新训练语料中的分割方式。

其中,cici+1 是在 Vt 中最频繁的字符对。

step 4 : 更新训练语料

重复上述过程,直到词汇表大小达到预设值 ∣V ∣=K。

假设有一个简单的训练语料库,包含以下单词及其频率:

{'hug': 10, 'pug': 5, 'pun': 12, 'bun': 4, 'hugs': 5}

每次迭代的结果示例如下:

3

python实现

下面通过python代码实现上述示例:

代码语言:javascript
复制
from collections import defaultdict, Counter

def get_stats(vocab):
    """统计字符对的频率"""
    pairs = defaultdict(int)
    for word, freq in vocab.items():
        symbols = word.split()
        for i in range(len(symbols) - 1):
            pairs[symbols[i], symbols[i+1]] += freq
    return pairs

def merge_vocab(pair, vocab_in):
    """合并字符对并更新词汇表"""
    vocab_out = {}
    bigram = ' '.join(pair)
    replacement = ''.join(pair)
    for word in vocab_in:
        w_out = word.replace(bigram, replacement)
        vocab_out[w_out] = vocab_in[word]
    return vocab_out

def bpe(vocab, num_merges):
    """执行 BPE 迭代"""
    print("Initial vocab:")
    print(vocab)
    print("\n")

    for i in range(num_merges):
        pairs = get_stats(vocab)
        if not pairs:
            break

        # 找到最频繁的字符对
        best_pair = max(pairs, key=pairs.get)
        print(f"Iteration {i+1}: Merging {best_pair} with frequency {pairs[best_pair]}")

        # 合并字符对并更新词汇表
        vocab = merge_vocab(best_pair, vocab)
        print("Updated vocab:")
        print(vocab)
        print("\n")

    return vocab

# 初始词汇表
vocab = {
    'h u g': 10,
    'p u g': 5,
    'p u n': 12,
    'b u n': 4,
    'h u g s': 5
}

# 执行 BPE,假设进行 3 次合并
final_vocab = bpe(vocab, num_merges=3)

得到结果如下:

4

优缺点

优势:通过数据驱动的方式有效平衡词汇表大小与未登录词问题。它能够将罕见词拆解为高频子词组合(如将“hugs”分解为“hug”和“s”),既压缩了词表规模,又提升了模型对未知词汇的泛化能力,尤其适用于形态丰富的语言或需要处理复合词的场景。无需依赖语言学规则的特点,在多语言任务中表现灵活,例如机器翻译中可统一处理不同语言的子词单元。

局限性:由于完全依赖统计频率,合并顺序的敏感性可能导致结果不稳定(如优先合并“u-g”而非“h-u”会生成不同子词),且生成的子词可能缺乏明确的语义解释性(如“ug”单独无意义)。此外,低频字符对的覆盖不足可能导致长尾词汇仍需以原子形式存在,而合并次数的设定依赖人工经验,需反复调参才能达到理想效果。

另外,BPE可以用于中文,但需要针对中文的语言特性进行适配。中文以汉字为基本单位,每个汉字本身具有独立语义,BPE可通过统计高频共现的汉字组合(如“中国”“北京”)生成子词,既能压缩词表规模(如从数万汉字减少到数千子词),又能解决未登录词问题(如将新词“元宇宙”拆解为“元”+“宇宙”)。然而,中文没有天然的空格分隔,BPE需以单字为起点逐步合并,可能产生无意义子词(如“的的”合并为冗余单元)或割裂语义连贯的固定搭配(如“巧克力”被拆为“巧”+“克力”)。实际应用中,BPE常与预分词技术结合,或通过限制子词长度、调整合并优先级来平衡效率与语义完整性,在机器翻译、预训练模型(如中文BERT)等场景中已得到有效验证。


参考文献:

1、Zouhar, V., Meister, C., Gastaldi, J. L., Du, L., Vieira, T., Sachan, M., & Cotterell, R. (2024). A Formal Perspective on Byte-Pair Encoding. arXiv preprint arXiv:2306.16837.

2、Lian, H., et al. (2024). Scaffold-BPE: Enhancing Byte Pair Encoding with Simple and Effective Scaffold Token Removal. arXiv preprint arXiv:2404.17808.

3、Sennrich, R., Haddow, B., & Birch, A. (2015). Neural Machine Translation of Rare Words with Subword Units. arXiv preprint arXiv:1508.07909.

后台回复“BPE”可免费获得上述论文和代码

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-02-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器学习养成记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档