WordPiece、BPE详解及代码
1.BPE是干什么用的?
WordPiece字面理解是把word拆成piece一片一片,其實就是這個意思。
 WordPiece的一種主要的實現(xiàn)方式叫做BPE(Byte-Pair Encoding)雙字節(jié)編碼。
 “l(fā)oved”,“l(fā)oving”,“l(fā)oves"這三個單詞。其實本身的語義都是“愛”的意思,但是如果我們以單詞為單位,那它們就算不一樣的詞,在英語中不同后綴的詞非常的多,就會使得詞表變的很大,訓練速度變慢,訓練的效果也不是太好。
 BPE算法通過訓練,能夠把上面的3個單詞拆分成"lov”,“ed”,“ing”,"es"幾部分,這樣可以把詞的本身的意思和時態(tài)分開,有效的減少了詞表的數(shù)量。
BPE的作用如下:
1.傳統(tǒng)詞表示方法無法很好的處理未知或罕見的詞匯(OOV問題:out of vocabulary)
2.傳統(tǒng)詞tokenization方法不利于模型學習詞綴之前的關(guān)系
3.Character embedding作為OOV的解決方法粒度太細
4.Subword粒度在詞與字符之間,能夠較好的平衡OOV問題
2.BPE算法
1.準備足夠大的訓練語料
2.確定期望的subword詞表大小
3.將單詞拆分為字符序列并在末尾添加后綴“ </ w>”,統(tǒng)計單詞頻率。本階段的subword的粒度是字符。例如,“ low”的頻率為5,那么我們將其改寫為“ l o w </ w>”:5
 (備注:為什么加入"< /w >"在解碼階段有說明)
4.統(tǒng)計每一個連續(xù)字節(jié)對的出現(xiàn)頻率,選擇最高頻者合并成新的subword
5.重復(fù)第4步直到達到第2步設(shè)定的subword詞表大小或下一個最高頻的字節(jié)對出現(xiàn)頻率為1
例子
{'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, 最高頻連續(xù)字節(jié)對"e"和"s"出現(xiàn)了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, 最高頻連續(xù)字節(jié)對"es"和"t"出現(xiàn)了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, 以此類推,最高頻連續(xù)字節(jié)對為"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, 繼續(xù)迭代直到達到預(yù)設(shè)的subword詞表大小或下一個最高頻的字節(jié)對出現(xiàn)頻率為1。說明
 每次合并后詞表可能出現(xiàn)3種變化:
+1,表明加入合并后的新字詞,同時原來在2個子詞還保留(2個字詞不是完全同時連續(xù)出現(xiàn))
+0,表明加入合并后的新字詞,同時原來2個子詞中一個保留,一個被消解(一個字詞完全隨著另一個字詞的出現(xiàn)而緊跟著出現(xiàn))
-1,表明加入合并后的新字詞,同時原來2個子詞都被消解(2個字詞同時連續(xù)出現(xiàn))
實際上,隨著合并的次數(shù)增加,詞表大小通常先增加后減小。
3.BPE代碼實現(xiàn)
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 = 1000 for 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>')編碼:構(gòu)建完詞表之后,對詞表按照長度進行排序。對于要預(yù)訓練的text,先將其按照詞表的順序進行分解(即編碼)。
 如下例子:
解碼:
# 編碼序列 [“the</w>”, “high”, “est</w>”, “moun”, “tain</w>”]# 解碼序列 “the</w> highest</w> mountain</w>”直接拼接起來,"< /w >"就可以隔離開不同的單詞。所以,加入"< /w >"是為了在解碼階段隔離開不同的單詞。
4.適用范圍
BPE一般適用在歐美語言,因為歐美語言大多是字符形式,涉及前綴、后綴的單詞比較多。而中文的漢字一般不用BPE進行編碼,因為中文是字無法進行拆分。對中文的處理通常只有分詞和分字兩種。理論上分詞效果更好,更好的區(qū)別語義。分字效率高、簡潔,因為常用的字不過3000字,詞表更加簡短。
 參考鏈接:
 一文讀懂BERT中的WordPiece
 NLP Subword三大算法原理:BPE、WordPiece、ULM
總結(jié)
以上是生活随笔為你收集整理的WordPiece、BPE详解及代码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 传统僵尸网络家族
 - 下一篇: SpringBoot基础-Environ