logo

BPE 算法

Byte Pair Encoder

wangzf / 2024-10-16


目录

BPE 算法简介

通常 NLP 的分词有两个最简单和直接的思路:

  1. 按照空格分开(在英文里就是按照单词分开),例如 "I have a cat" 可以分为 ['I', 'have', 'a', 'cat']
  2. 按字符进行分割,例如 "I have a cat" 可以分为 ['I', 'h', 'a', 'v', 'e', 'a', 'c', 'a' , 't']

但这两种都有各自的弊端。

因此,在单词和字符两个粒度之间取平衡,基于子词(subword) 的算法被提出了, 典型的就是 BPE 算法(BPE, Byte Pair Encoder, 字节对编码)

BPE 算法流程

BPE 构建词表

  1. 确定词表大小,即 subword 的最大个数 $V$
  2. 在每个单词最后添加一个 </w>,并且统计每个单词出现的频率;
  3. 将所有单词拆分为单个字符,构建出初始的词表,此时词表的 subword 其实就是字符;
  4. 挑出频次最高的字符对,比如说 th 组成的 th, 将新字符加入词表,然后将语料中所有该字符对融合(merge),即所有 th 都变为 th。 新字符依然可以参与后续的 merge,有点类似哈夫曼树,BPE 实际上就是一种贪心算法;
  5. 重复 3,4 的操作,直到词表中单词数量达到预设的阈值 $V$ 或者下一个字符对的频数为 1;

BPE 编码

词表构建完成后,需要对训练语料进行编码,编码流程如下:

  1. 将词表中的单词按长度大小,从长到短就行排序;
  2. 对于语料中的每个单词,遍历排序好的词表, 判断词表中的单词/子词(subword)是否是该字符串的子串,如果匹配上了, 则输出当前子词,并继续遍历单词剩下的字符串。
  3. 如果遍历完词表,单词中仍然有子字符串没有被匹配,那我们将其替换为一个特殊的子词,比如 <unk>

具个例子,假设我们现在构建好的词表为

(“errrr</w>”, 
“tain</w>”, 
“moun”, 
“est</w>”, 
“high”, 
“the</w>”, 
“a</w>”)

对于给定的单词 mountain</w>,其分词结果为:[moun, tain</w>]

BPE 解码

语料解码就是将所有的输出子词拼在一起,直到碰到结尾为 <\w>。举个例子,假设模型输出为:

["moun", "tain</w>", "high", "the</w>"]

那么其解码的结果为:

["mountain</w>", "highthe</w>"]

BPE算法优缺点

参考