BPE,即字节对编码。其核心思想在于将最常出现的子词对合并,直到词汇表达到预定的大小时停止。
首先,它依赖于一种预分词器pretokenizer来完成初步的切分。pretokenizer可以是简单基于空格的,也可以是基于规则的;
分词之后,统计每个词出现的频次,供后续计算使用。例如,我们统计到了5个词的词频
("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5)
["b", "g", "h", "n", "p", "s", "u"]
["b", "g", "h", "n", "p", "s", "u", "ug", "un", "hug"]
实际使用中,如果遇到未知字符用
BPE的一个问题是,如果遇到了unicode,基本字符集可能会很大。一种处理方法是我们以一个字节为一种“字符”,不管实际字符集用了几个字节来表示一个字符。这样的话,基础字符集的大小就锁定在了256。
例如,像GPT-2的词汇表大小为50257 = 256 +
BPE、WordPiece和SentencePiece - 简书
简单的说BBPE比BPE有更多的粒度选择,BPE是char级别。
BPE 算法的主要思想是将输入的文本进行多轮迭代的分段和统计,每次迭代都会找到出现频率最高的相邻字符或子词序列,并将其合并成一个新的符号(或单词)。在整个过程中,所有出现过的字符和新合并出的子词都被保存在一个词汇表中。
下面,我们将从以下几个方面对 BPE 算法的原理进行详细阐述:
在 BPE 算法中,频率的定义非常重要。具体来说,频率需要考虑字符(单字母)和子词(多个字母组成的词)两个方面。
对于字符而言,我们可以使用它在输入文本中出现的次数作为其频率。例如,如果字符“a”在输入文本中出现了 10 次,那么我们就认为该字符的频率为 10。
对于子词而言,频率的定义则需要考虑其实际出现的次数和合并次数两个因素。具体来说,如果一个子词出现了一次,则它的频率为 1;如果一个子词被合并了 k 次,则它的频率需要乘以 2^k。这是因为 BPE 算法中每次合并时都会将原来出现的两个子词用新的合并后的子词替换,这样会导致原来的子词从输入中消失,而新的子词的频率则要加上原来的两个子词的频率之和。
BPE 算法的初始词汇表通常由输入文本中的所有字符组成。如果某个字符在输入文本中没有出现过,那么它不应该加入初始词汇表。在实际应用中,我们通常会额外添加一些特殊的字符,例如空格、句点、问号等,以便在后续操作中更方便地进行处理。
在 BPE 算法的每次迭代中,我们会选择出现频率最高的相邻字符或子词,将它们合并成一个新的符号(或单词),并将这个新的符号加入到词汇表中。这个过程一直持续到达到指定的词汇表大小为止。
具体来说,BPE 算法的迭代过程通常包括以下几步:
在 BPE 算法中,相邻字符或子词的选择是基于前缀和后缀的组合。例如,“app”和“le”可以组成“apple”,“p”和“i”可以组成“pi”,等等。在每一轮迭代中,我们按照从左到右、从上到下的顺序遍历输入文本,找到出现频率最高的相邻字符或子词,然后进行合并。由于更新后的文本中出现的新的相邻字符或子词可能也会成为下一轮迭代中的候选,因此我们需要反复迭代,直到达到指定的词汇表大小为止。
BPE 算法的最终目的是生成一个包含所有输入文本中出现的字符和子词的词汇表。在使用 BPE 对文本进行编码和解码时,我们通常会根据生成的词汇表将输入文本分割成最小的可处理单位,称为 subword(子词)。
在对文本进行编码时,我们可以将每个子词编码成它在词汇表中的索引。如果某个子词不在词汇表中,我们可以将它拆分成更小的子词,并将它们分别编码。编码后的结果通常是一个由整数构成的序列。
在对文本进行解码时,我们可以根据词汇表中的索引将每个子词解码成对应的字符串,并将它们拼接起来得到原始文本。如果某个子词无法解码,我们可以尝试将它拆分成更小的子词,并将它们分别解码。
ChatGpt都这么火了,它使用的 BPE 分词算法要不要了解一下?_bpe分词原理_大家都说我身材好的博客-CSDN博客
我最近在打机器翻译的一个比赛,主要使用基于BERT的模型。在这其中,一个小的知识点引起了我的好奇,就是在将英语训练语料输入到BERT模型之前,需要对其进行「BPE」(Byte Pair Encoding)的操作。作为致力于成为一名合格算法工程师的程序员,当然是要搞清楚其中的原理啦~本篇文章就带大家一起快速搞懂BPE分词算法。
本文主要分成两个部分,内容1500字,阅读耗时大约8分钟:
BPE算法[1],其目的是「使用一些子词来编码数据」。该方法已经成为了BERT等模型标准的数据预处理处理方式。
在机器翻译领域,模型训练之前一个很重要的步骤就是「构建词表」。对于英文语料,一个很自然的想法就是用训练语料中出现过的「所有英语单词」来构建词表,但是这样的方法存在两个问题:
另外一种方式是使用单个「字符」来构建词表。英文字符的个数是有限的,基于字符的方式可以有效缓解词表数目过大以及OOV的问题,但由于其粒度太细,丢失了很多单词本身所具有的语意信息。
为了解决上述问题,基于Subword(子词)的算法被提出,其中的代表就是BPE算法,「BPE算法的分词粒度处于单词级别和字符级别之间」。比如说单词"looked"和"looking"会被划分为"look","ed”,"ing",这样在降低词表大小的同时也能学到词的语意信息。
BPE算法的核心主要分成三个部分:
词表构建是BPE算法的核心,其是「根据训练语料」来构建BPE算法的词表。算法的整体步骤如下所示:
下面我们通过一个例子来搞懂BPE词表构建的过程。假设我们目前的训练语料中出现过的单词如下,我们构建初始词表:
值得注意的是,我们在每一个单词的后面都加入了一个新的字符<\w>
来表示这个单词的结束。初始的词表大小为7,其为训练语料中所有出现过的字符。
我们之后发现lo
这个字节对在训练语料中出现频率最高,为3次。我们更新词表,将lo
作为新的子词加入词表,并删除在当前训练语料中不单独出现的字符l
和o
。
之后我们发现low
这个字节对在训练语料中出现频率最高,为3次。我们继续组合,将low
加入词表中,并删去lo
。需要注意的是,由于字符w
在单词newer
中仍然存在,因此不予删除。
之后我们继续这个循环过程,在词表中加入er
,并删去字符r
我们一直循环这个过程,直到词表大小达到我们设定的期望或者剩下的字节对出现频率最高为1。
最终我们就得到了基于训练样本构建好的词表。
BPE算法详解 - mathor
词表构建好后,我们需要给训练语料中的单词进行编码。编码方式如下:
。具个例子,假设我们现在构建好的词表为
(“errrr”,
“tain”,
“moun”,
“est”,
“high”,
“the”,
“a”)
对于给定的单词mountain
,其分词结果为:[moun
, tain
]
语料解码就是将所有的输出子词拼在一起,直到碰到结尾为<\w>
。举个例子,假设模型输出为:
["moun", "tain", "high", "the"]
那么其解码的结果为
["mountain", "highthe"]
在本文中,我们一起学习了BPE的分词算法,该算法是「利用子词来编码数据」,已经成为目前机器翻译领域标准的预处理方式。
[1]Sennrich, Rico, Barry Haddow, and Alexandra Birch. "Neural machine translation of rare words with subword units." ACL 2016.
[2]NLP三大Subword模型详解:BPE、WordPiece、ULM - 知乎
[3]深入理解NLP Subword算法:BPE、WordPiece、ULM - 知乎
[4]https://www.cnblogs.com/huangyc/p/1
一文搞懂BPE分词算法 - 知乎
简单的搞懂BPE分词算法 - 知乎
BPE、WordPiece和SentencePiece - 简书
Byte Pair Encoding - Lei Mao's Log Book
ChatGpt都这么火了,它使用的 BPE 分词算法要不要了解一下?_bpe分词原理_大家都说我身材好的博客-CSDN博客
BPE算法详解 - mathor
Byte Pair Encoding - Lei Mao's Log Book
Byte Pair Encoding and Data Structures | Rust NLP tales