点击上方,选择星标或置顶,每天给你送干货!
阅读大概需要11分钟
跟随小博主,每天进步一丢丢
编辑:夕小瑶的卖萌屋
正文作者:Luke
正文来源:https://zhuanlan.zhihu.com/p/86965595
BPE(字节对)编码或二元编码是一种简单的数据压缩形式,其中最常见的一对连续字节数据被替换为该数据中不存在的字节。后期使用时需要一个替换表来重建原始数据。OpenAI GPT-2 与Facebook RoBERTa均采用此方法构建subword vector.
优点
可以有效地平衡词汇表大小和步数(编码句子所需的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}
Iter 1, 最高频连续字节对"e"和"s"出现了6+3=9次,合并成"es"。输出:
{'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}
Iter 2, 最高频连续字节对"es"和"t"出现了6+3=9次, 合并成"est"。输出:
{'l o w </w>': 5, 'l o w e r </w>': 2, 'n e w est </w>': 6, 'w i d est </w>': 3}
Iter 3, 以此类推,最高频连续字节对为"est"和"</w>" 输出:
{'l o w </w>': 5, 'l o w e r </w>': 2, 'n e w est</w>': 6, 'w i d est</w>': 3}
Iter n, 继续迭代直到达到预设的subword词表大小或下一个最高频的字节对出现频率为1。
import re, collectionsdef get_stats(vocab):pairs = collections.defaultdict(int)for word, freq in vocab.items():symbols = word.split()for i in range(len(symbols)-1):pairs[symbols[i],symbols[i+1]] += freqreturn pairsdef merge_vocab(pair, v_in):v_out = {}bigram = re.escape(' '.join(pair))p = re.compile(r'(?<!\S)' + bigram + r'(?!\S)')for word in v_in:w_out = p.sub(''.join(pair), word)v_out[w_out] = v_in[word]return v_outvocab = {'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}num_merges = 1000for i in range(num_merges):pairs = get_stats(vocab)if not pairs:breakbest = max(pairs, key=pairs.get)vocab = merge_vocab(best, vocab)print(best)# print output# ('e', 's')# ('es', 't')# ('est', '</w>')# ('l', 'o')# ('lo', 'w')# ('n', 'e')# ('ne', 'w')# ('new', 'est</w>')# ('low', '</w>')# ('w', 'i')# ('wi', 'd')# ('wid', 'est</w>')# ('low', 'e')# ('lowe', 'r')# ('lower', '</w>')
在之前的算法中,我们已经得到了subword的词表,对该词表按照子词长度由大到小排序。编码时,对于每个单词,遍历排好序的字词词表寻找是否有token是当前单词的子字符串,如果有,则该token是表示单词的tokens之一。
# 给定单词序列[“the</w>”, “highest</w>”, “mountain</w>”]# 假设已有排好序的subword词表[“errrr</w>”, “tain</w>”, “moun”, “est</w>”, “high”, “the</w>”, “a</w>”]# 迭代结果"the</w>" -> ["the</w>"]"highest</w>" -> ["high", "est</w>"]"mountain</w>" -> ["moun", "tain</w>"]
解码
将所有的tokens拼在一起,示例如下:
# 编码序列[“the</w>”, “high”, “est</w>”, “moun”, “tain</w>”]# 解码序列“the</w> highest</w> mountain</w>”
[1] https://en.wikipedia.org/wiki/Byte_pair_encoding
[2] https://leimao.github.io/blog/Byte-Pair-Encoding/
[3] https://medium.com/@makcedward/how-subword-helps-on-your-nlp-model-83dd1b836f46
[4] Subword Regularization: Improving Neural Network Translation Models with Multiple Subword Candidates