Byte Pair Encoding
2. Byte Pair Encoding原理
在NLP模型中,输入通常是一个句子,例如 "I went to New York last week." ,一句话中包含很多单词(token)。传统的做法是将这些单词以空格进行分隔,例如['i', 'went', 'to', 'New', 'York', 'last', 'week']。然而这种做法存在很多问题,例如模型无法通过walked, walking,walker之间的关系学到talked,talking,talker之间的关系。如果我们能使用将一个token分成多个subtokens,上面的问题就能很好的解决。
现在性能比较流行的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
停止符</w>的意义在于表示subword是词后缀。举例来说:st不加</w>可以出现在词首,如st ar;加了</w>表明改字词位于词尾,如wide st</w>,二者意义截然不同。
举例来说:
原始词表
{'l o w e r </w>': 2, 'n e w e s t </w>': 6, 'w i d e s t </w>': 3, 'l o w </w>': 5}
Step1:
出现最频繁的序列
('e', 's') 9
合并最频繁的序列后的词表
{'n e w es t </w>': 6, 'l o w e r </w>': 2, 'w i d es t </w>': 3, 'l o w </w>': 5}
Step2:
出现最频繁的序列
('es', 't') 9
合并最频繁的序列后的词表
{{'n e w est </w>': 6, 'l o w e r </w>': 2, 'w i d est </w>': 3, 'l o w </w>': 5}
Step3:
出现最频繁的序列
('est', '</w>') 9
合并最频繁的序列后的词表
{'w i d est</w>': 3, 'l o w e r </w>': 2, 'n e w est</w>': 6, 'l o w </w>': 5}
Step4:
出现最频繁的序列
('l', 'o') 7
合并最频繁的序列后的词表
{'w i d est</w>': 3, 'lo w e r </w>': 2, 'n e w est</w>': 6, 'lo w </w>': 5}
Step5:
出现最频繁的序列
('lo', 'w') 7
合并最频繁的序列后的词表
{'w i d est</w>': 3, 'low e r </w>': 2, 'n e w est</w>': 6, 'low </w>': 5}
Step6:
出现最频繁的序列
('n', 'e') 6
合并最频繁的序列后的词表
{'w i d est</w>': 3, 'low e r </w>': 2, 'ne w est</w>': 6, 'low </w>': 5}
Step7:
出现最频繁的序列
('ne', 'w') 6
合并最频繁的序列后的词表
{'w i d est</w>': 3, 'low e r </w>': 2, 'new est</w>': 6, 'low </w>': 5}
Step8:
出现最频繁的序列
('new', 'est</w>') 6
合并最频繁的序列后的词表
{'w i d est</w>': 3, 'low e r </w>': 2, 'newest</w>': 6, 'low </w>': 5}
Step9:
出现最频繁的序列
('low', '</w>') 5
合并最频繁的序列后的词表
{'w i d est</w>': 3, 'low e r </w>': 2, 'newest</w>': 6, 'low</w>': 5}
Step10:
出现最频繁的序列
('w', 'i') 3
合并最频繁的序列后的词表
{'wi d est</w>': 3, 'newest</w>': 6, 'low</w>': 5, 'low e r </w>': 2}
Step11:
出现最频繁的序列
('wi', 'd') 3
合并最频繁的序列后的词表
{'wid est</w>': 3, 'newest</w>': 6, 'low</w>': 5, 'low e r </w>': 2}
Step12:
出现最频繁的序列
('wid', 'est</w>') 3
合并最频繁的序列后的词表
{'widest</w>': 3, 'newest</w>': 6, 'low</w>': 5, 'low e r </w>': 2}
Step13:
出现最频繁的序列
('low', 'e') 2
合并最频繁的序列后的词表
{'widest</w>': 3, 'newest</w>': 6, 'low</w>': 5, 'lowe r </w>': 2}
Step14:
出现最频繁的序列
('lowe', 'r') 2
合并最频繁的序列后的词表
{'widest</w>': 3, 'newest</w>': 6, 'low</w>': 5, 'lower </w>': 2}
Step15:
出现最频繁的序列
('lower', '</w>') 2
合并最频繁的序列后的词表
{'widest</w>': 3, 'newest</w>': 6, 'low</w>': 5, 'lower</w>': 2}
解码:
将所有的tokens拼在一起即可,
https://zhuanlan.zhihu.com/p/378323693
https://zhuanlan.zhihu.com/p/369625931