Byte-Pair-Encoding是用于解决未登录词的一种方法。首先简单提一句什么是未登录词,未登录词可以理解为训练语料库中没有出现的,但是在测试语料库中出现的词。我们在处理NLP任务时,通常会根据语料生成一个词典,把语料中词频大于某个阈值的词放入词典中,而低于该阈值的词统统编码成"#UNK"。这种处理方法的好处是简单,但是问题也很大,在测试语料库中如果出现了未登录词,那么我们的模型很难处理这种词。由于本文并不是为了解释NLP中如何处理未登录词的,因此其他的废话不多说,我们只说BPE算法是怎么解决未登录词的。
通常我们的词典都是word-level的,也就是说词典是以单词或者短语为基本单位的,但这就无可避免的会遇到未登录词的问题,因为不可能设计一个非常大的能涵盖所有单词的词典。此外另一种词典是character-lever,即以单个字母或汉字(中文)为基本单词设计词典,这种方法理论上可以解决未登录词的问题,因为所有的词都是由字母组成的,但是这样做的缺点是模型粒度太细,缺少语义信息,实际也有人做过实验证明这种方法不好。

后来2016年rich等人提出了基于subword来生成词典的方法,这种方法综合了word-level和charater-level的优势,从语料中学习所有单词里频次高的字符子串,然后把这些频次高的字符子串合并为一个词典。在这个词典里,既存在word-level级别的子串,也存在charater-level的子串。其中,用于寻找高频子串的方法,就是本文即将解释的BPE算法。

BEP算法很简单,它主要是用来寻找字符串中的高频子串的方法。具体来说,我们把语料库中的每个单词结尾添加一个stop token “”。然后我们将每个单词拆分成字母的形式。例如,起初我们有如下的words:

{'low': 5, 'lower': 2, 'newest': 6, 'widest': 3}

添加stop token并拆分后,变成了下面的形式:

{'l o w </w>': 5, 'l o w e r </w>': 2, 'n e w e s t </w>': 6, 'w i d e s t </w>': 3}

接下来我们计算相邻两字母出现的频率,选择频率最高的一对进行合并,在上面的例子中,'e’与’s’共出现了9次,频率最高,我们将其合并:

{'l o w </w>': 5, 'l o w e r </w>': 2, 'n e w es t </w>': 6, 'w i d es t </w>': 3}

继续重复刚刚的方法,发现’es’与’t’共出现了9次,频率最高,将其合并:

{'l o w </w>': 5, 'l o w e r </w>': 2, 'n e w est </w>': 6, 'w i d est </w>': 3}

以此类推,迭代n次,直到达到预设的subwords词表大小或下一个最高频的字节对出现频率为1。