恒源云 gpushare.com_Byte-Pair Encoding 算法超详细讲解
文章来源 | 恒源云社区
原文地址 | BPE 算法详解
原文作者 | Mathor
Byte Pair Encoding
在 NLP 模型中,输入通常是一个句子,例如"I went to New York last week."
,一句话中包含很多单词(token)。传统的做法是将这些单词以空格进行分隔,例如['i', 'went', 'to', 'New', 'York', 'last', 'week']
。然而这种做法存在很多问题,例如模型无法通过old, older, oldest
之间的关系学到smart, smarter, smartest
之间的关系。如果我们能使用将一个 token 分成多个 subtokens,上面的问题就能很好的解决。本文将详述目前比较常用的 subtokens 算法——BPE(Byte-Pair Encoding)
现在性能比较好一些的 NLP 模型,例如 GPT、BERT、RoBERTa 等,在数据预处理的时候都会有 WordPiece 的过程,其主要的实现方式就是 BPE(Byte-Pair Encoding)。具体来说,例如['loved', 'loving', 'loves']
这三个单词。其实本身的语义都是"爱"的意思,但是如果我们以词为单位,那它们就算不一样的词,在英语中不同后缀的词非常的多,就会使得词表变的很大,训练速度变慢,训练的效果也不是太好。BPE 算法通过训练,能够把上面的 3 个单词拆分成["lov","ed","ing","es"]
几部分,这样可以把词的本身的意思和时态分开,有效的减少了词表的数量。算法流程如下:
设定最大 subwords 个数
将所有单词拆分为单个字符,并在最后添加一个停止符
</w>
,同时标记出该单词出现的次数。例如,"low"
这个单词出现了 5 次,那么它将会被处理为{'l o w </w>': 5}
统计每一个连续字节对的出现频率,选择最高频者合并成新的 subword
重复第 3 步直到达到第 1 步设定的 subwords 词表大小或下一个最高频的字节对出现频率为 1
例如
出现最频繁的字节对是** e
和s
**,共出现了 6+3=9 次,因此将它们合并
出现最频繁的字节对是** es
和t
**,共出现了 6+3=9 次,因此将它们合并
出现最频繁的字节对是** est
和</w>
**,共出现了 6+3=9 次,因此将它们合并
出现最频繁的字节对是** l
和o
**,共出现了 5+2=7 次,因此将它们合并
出现最频繁的字节对是** lo
和w
**,共出现了 5+2=7 次,因此将它们合并
…继续迭代直到达到预设的 subwords 词表大小或下一个最高频的字节对出现频率为 1。这样我们就得到了更加合适的词表,这个词表可能会出现一些不是单词的组合,但是其本身有意义的一种形式
停止符</w>
的意义在于表示 subword 是词后缀。举例来说:st
不加</w>
可以出现在词首,如st ar
;加了</w>
表明改字词位于词尾,如wide st</w>
,二者意义截然不同
BPE 实现
输出如下
编码和解码
编码在之前的算法中,我们已经得到了 subword 的词表,对该词表按照字符个数由多到少排序。编码时,对于每个单词,遍历排好序的子词词表寻找是否有 token 是当前单词的子字符串,如果有,则该 token 是表示单词的 tokens 之一
我们从最长的 token 迭代到最短的 token,尝试将每个单词中的子字符串替换为 token。 最终,我们将迭代所有 tokens,并将所有子字符串替换为 tokens。 如果仍然有子字符串没被替换但所有 token 都已迭代完毕,则将剩余的子词替换为特殊 token,如<unk>
例如
解码将所有的 tokens 拼在一起即可,例如
编码和解码实现
输出如下
评论