BPE (字节对编码)

一种基于高频字节 (字符) 组合把文本拆分为子词单元的算法。作为 GPT 系列等大语言模型的分词器被广泛采用。

BPE (Byte Pair Encoding,字节对编码) 最初是菲利普·盖奇于 1994 年作为数据压缩算法提出的方法。自 2015 年塞内里希等人将其应用于机器翻译的子词切分之后,它成为自然语言处理中标准的令牌化方法。GPT 系列和 LLaMA 的分词器属于 BPE 系,但 BERT 的分词器是 WordPiece 这一另外的方式。WordPiece 也是把文本拆分为比词更小的单位的同一系统的方法,不同之处在于选择要合并的对时依据的并不是出现频率本身。若归纳为"大语言模型的分词器全都是 BPE"就会出错。

BPE 的训练算法很直观。首先,把训练文本拆分为字符 (或字节) 单位。接着,找出最频繁相邻的对,把这个对合并为一个新的令牌。重复这一合并,直到词表大小达到目标值。例如从"low""lower""lowest"这样的文本中,会按"l"+"o"→"lo"、"lo"+"w"→"low"的方式依次合并高频对。

BPE 的强项在于能把未登录词 (out-of-vocabulary) 的问题缩小。基于词的令牌化无法处理训练数据中未包含的词,而用 BPE 则可以把任何词分解为子词的组合。"unhappiness"会被切分为"un"+"happiness"或"un"+"happ"+"iness",各个子词都包含在词表中。

不过,这并不意味着"绝对不会出现未登录词"。如果词表是从字符单位构建的,那么输入了词表中没有的字符时就无法表示,会被替换为表示未登录词的专用令牌 (BERT 中为 [UNK])。拥有约 3 万词词表的 BERT 就是这种形式。避免这一点的方式是字节级 BPE,它先把文本转换为 UTF-8 的字节序列再学习合并,因此任何字符串都必定能够表示。GPT-2 系和 RoBERTa 等采用这种方式,表情符号和罕见汉字虽然会被切得很细,但不会缺失。

日语的 BPE 令牌化有其特有的课题。日语的词与词之间不用空格分隔,因此存在两种做法:事先用形态素分析做词语切分再应用 BPE,以及直接从字符级别学习 BPE。GPT-4 的分词器 (cl100k_base) 采用后一种做法,日语的一个汉字有时会成为一个令牌,连续的平假名有时也会汇总为一个令牌。cl100k_base 的切分规则中有一项作用,是把位于词正前方的空格并入该词的令牌,因此在英语中即使是同一个词,也会因正前方是否为空格而切分不同。日语的词之间不放空格,所以没有这项作用。

令牌数与字符数的关系因语言而异。英语大致是每个令牌 4 个字符左右,日语大致是每个令牌 1〜2 个字符左右。可以认为:字符数相同的文章,日语的令牌数更容易变多,这样想不会偏离太多。不过这个大致标准会随内容和写法而摇摆。估算输入上限或费用时,用该模型的分词器实际去数才是可靠的。上限的令牌数因模型而异,分词器不同时同一篇文章数出来的结果也会变化。

在实务上,应把字符数与令牌数当作两回事来处理。输入框的限制和显示的折行由字符数决定,而能否放进模型、费用是多少则由令牌数决定。BPE 是通过合并高频对来构建词表的机制,所以常用的写法会汇总为较少的令牌,而罕见的写法、符号的堆砌、自造的专有名词则会被切得很细、令牌数增加。想把长提示词缩短时,可以由此判断:与其削减字符数,不如把重复和奇特的写法改成普通的写法更容易见效。

分享这篇文章