【NLP】機(jī)器如何認(rèn)識(shí)文本 ?NLP中的Tokenization方法總結(jié)
Tokenization
關(guān)于Tokenization,網(wǎng)上有翻譯成"分詞"的,但是我覺(jué)得不是很準(zhǔn)確,容易引起誤導(dǎo)。一直找不到合適的中文來(lái)恰當(dāng)表達(dá),所以下文采用原汁原味的英文表達(dá)。
在正式進(jìn)入主題之前,先來(lái)看看NLP任務(wù)中最基礎(chǔ)也最先需要進(jìn)行的一步:tokenization。簡(jiǎn)單說(shuō),該操作的目地是將輸入文本分割成一個(gè)個(gè)token,和詞典配合以讓機(jī)器認(rèn)識(shí)文本。Tokenization的難點(diǎn)在于如何獲得理想的切分,使文本中所有的token都具有正確的表義,并且不會(huì)存在遺漏(OOV問(wèn)題)。
接下來(lái),我們簡(jiǎn)單梳理下目前主流的tokenization方法,及其優(yōu)缺點(diǎn)。
詞粒度
詞粒度的切分就跟人類平時(shí)理解文本原理一樣,常常用一些工具來(lái)完成,例如英文的NLTK、SpaCy,中文的jieba、LTP等。舉個(gè)栗子:
英文:
live in New York ------> live / in / New York /
中文:
在紐約生活 -----> 在 / 紐約 / 生活
詞粒度的切分能夠非常好地保留完整語(yǔ)義信息,但是如果出現(xiàn)拼寫錯(cuò)誤、英文中的縮寫等情況,魯棒性一般。另一方面,詞切分會(huì)產(chǎn)生非常巨大的詞表,而且這都不能確保不會(huì)出現(xiàn)out of vocabulary問(wèn)題。
字粒度
字粒度最早應(yīng)該是2015年Karpathy[1]提出,簡(jiǎn)單說(shuō)英文就是以字母為單位(對(duì)于大小寫不敏感的任務(wù),甚至可以先轉(zhuǎn)小寫再切分),中文就是以字為單位,舉個(gè)栗子,
英文:
live in New York -----> l / i / v /e / i / n / N / e / w / Y / o / r /k
中文:
在紐約生活 -----> 在 / 紐 / 約 / 生 / 活
可以看出,字粒度的切分很好地解決了詞粒度的缺陷,魯棒性增強(qiáng)、詞表大大減小。但另一方面,也會(huì)帶來(lái)一些麻煩:
「毫無(wú)意義」:一個(gè)字母或一個(gè)單字本質(zhì)上并沒(méi)有任何語(yǔ)義意義; 「增加輸入計(jì)算壓力」:減小詞表的代價(jià)就是輸入長(zhǎng)度大大增加,從而輸入計(jì)算變得更耗時(shí)耗力;
如果詞粒度不理想,而且字粒度似乎也有自己的問(wèn)題,那么還有什么替代方法呢?
Here comes subword tokenization!
Subword粒度
我們理想中的tokenization需要滿足:
它能夠在不需要無(wú)限詞匯表的情況下處理缺失的標(biāo)記,即通過(guò)有限的已知單詞列表來(lái)處理無(wú)限的潛在詞匯; 此外,我們不希望將所有內(nèi)容分解為單個(gè)字符的額外復(fù)雜性,因?yàn)樽址?jí)別可能會(huì)丟失單詞級(jí)別的一些含義和語(yǔ)義細(xì)節(jié)。
為此,我們需要考慮如何重新利用『小』單詞來(lái)創(chuàng)建『大』單詞。subword tokenization不轉(zhuǎn)換最常見(jiàn)的單詞,而是將稀有單詞分解成有意義的子詞單元。如果unfriendly被標(biāo)記為一個(gè)稀有詞,它將被分解為un-friendly-ly,這些單位都是有意義的單位,un的意思是相反的,friend是一個(gè)名詞,ly則變成副詞。這里的挑戰(zhàn)是如何進(jìn)行細(xì)分,我們?nèi)绾潍@得un-friend-ly而不是unfr-ien-dly。
NLP最火的網(wǎng)紅 Transformer 和 BERT 就是Subword的帶鹽人,來(lái)看個(gè)它們做tokenization的栗子,
I have a new GPU ?----> [’i’, ’have’, ’a’, ’new’, ’gp’, ’##u’, ’.’]
subword粒度切分算法又有以下幾種:
BPE WordPiece ULM
BPE
BPE全稱Byte Pair Encoding,字節(jié)對(duì)編碼,首先在Neural Machine Translation of Rare Words with Subword Units[2] 中提出。BPE 迭代地合并最頻繁出現(xiàn)的字符或字符序列,具體步驟:
準(zhǔn)備足夠大的語(yǔ)料庫(kù) 定義好所需要的詞表大小 將單詞拆分為字符序列,在末尾添加后綴 w>,并統(tǒng)計(jì)單詞頻率。本階段的subword的粒度是字符。例如,“ low”的頻率為5,那么我們將其改寫為l o w w>:5統(tǒng)計(jì)每一個(gè)連續(xù)字節(jié)對(duì)的出現(xiàn)頻率,選擇最高頻者合并成新的subword 重復(fù)第4步直到達(dá)到第2步設(shè)定的subword詞表大小或下一個(gè)最高頻的字節(jié)對(duì)出現(xiàn)頻率為1
舉個(gè)栗子,我們輸入,
{'l?o?w?':?5,?'l?o?w?e?r?':?2,?'n?e?w?e?s?t?':?6,?'w?i?d?e?s?t?':?3}
第一輪迭代,統(tǒng)計(jì)連續(xù)的每?jī)蓚€(gè)字節(jié)出現(xiàn)的次數(shù),發(fā)現(xiàn) e 和s 共現(xiàn)次數(shù)最大,合并成es,有,
{'l?o?w?':?5,?'l?o?w?e?r?':?2,?'n?e?w?es?t?':?6,?'w?i?d?es?t?':?3}
第二輪迭代,統(tǒng)計(jì)連續(xù)的每?jī)蓚€(gè)字節(jié)出現(xiàn)的次數(shù),發(fā)現(xiàn) es 和t 共現(xiàn)次數(shù)最大,合并成est,有,
{'l?o?w?':?5,?'l?o?w?e?r?':?2,?'n?e?w?est?':?6,?'w?i?d?est?':?3}
依次繼續(xù)迭代直到達(dá)到預(yù)設(shè)的subword詞表大小或下一個(gè)最高頻的字節(jié)對(duì)出現(xiàn)頻率為1。
以上是BPE的整體流程,關(guān)于BPE更多細(xì)節(jié)可以參考:Byte Pair Encoding[3]
Unigram LM
Unigram語(yǔ)言建模首先在Subword Regularization: Improving Neural Network Translation Models with Multiple Subword Candidates[4]中提出,基于所有子詞出現(xiàn)是獨(dú)立的假設(shè),因此子詞序列由子詞出現(xiàn)概率的乘積生成。算法步驟如下:
準(zhǔn)備足夠大的語(yǔ)料庫(kù) 定義好所需要的詞表大小 給定詞序列優(yōu)化下一個(gè)詞出現(xiàn)的概率 計(jì)算每個(gè)subword的損失 基于損失對(duì)subword排序并保留前X%。為了避免OOV,保留字符級(jí)的單元 重復(fù)第3至第5步直到達(dá)到第2步設(shè)定的subword詞表大小或第5步的結(jié)果不再變化
unigram-LM模型比BPE更靈活,因?yàn)樗诟怕蔐M,并且可以輸出具有概率的多個(gè)分段。它不是從一組基本符號(hào)開始,更具某些規(guī)則進(jìn)行合并,如BPE或WordPiece,而是從一個(gè)龐大的詞匯量開始,例如所有預(yù)處理的單詞和最常見(jiàn)的子字符串,并逐步減少。
WordPiece
WordPiece首先在 JAPANESE AND KOREAN VOICE SEARCH[5] 中提出,最初用于解決日語(yǔ)和韓語(yǔ)語(yǔ)音問(wèn)題。它在許多方面類似于BPE,只是它基于可能性而不是下一個(gè)最高頻率對(duì)來(lái)形成一個(gè)新的子詞。算法步驟如下:
準(zhǔn)備足夠大的語(yǔ)料庫(kù) 定義好所需要的詞表大小 將單詞拆分成字符序列 基于第3步數(shù)據(jù)訓(xùn)練語(yǔ)言模型 從所有可能的subword單元中選擇加入語(yǔ)言模型后能最大程度地增加訓(xùn)練數(shù)據(jù)概率的單元作為新的單元 重復(fù)第5步直到達(dá)到第2步設(shè)定的subword詞表大小或概率增量低于某一閾值
WordPiece更像是BPE和Unigram LM的結(jié)合。
小結(jié)
簡(jiǎn)單幾句話總結(jié)下Subword的三種算法:
BPE:只需在每次迭代中使用「出現(xiàn)頻率」來(lái)確定最佳匹配,直到達(dá)到預(yù)定義的詞匯表大??; Unigram:使用概率模型訓(xùn)練LM,移除提高整體可能性最小的token;然后迭代進(jìn)行,直到達(dá)到預(yù)定義的詞匯表大?。?/section> WordPiece:結(jié)合BPE與Unigram,使用「出現(xiàn)頻率」來(lái)確定潛在匹配,但根據(jù)合并token的概率做出最終決定.
Sentencepiece
到目前為止,可以發(fā)現(xiàn)subword結(jié)合了詞粒度和字粒度方法的優(yōu)點(diǎn),并避免了其不足。但是,仔細(xì)想會(huì)發(fā)現(xiàn)上述三種subword算法都存在一些問(wèn)題:
「都需要提前切分(pretokenization)」 :這對(duì)于某些語(yǔ)言來(lái)說(shuō),可能是不合理的,因?yàn)椴豢梢杂每崭駚?lái)分隔單詞;
「無(wú)法逆轉(zhuǎn)」:原始輸入和切分后序列是不可逆的。舉個(gè)栗子,下面兩者的結(jié)果是相等的,即空格的信息經(jīng)過(guò)該操作被丟失
Tokenize(“World.”) == Tokenize(“World .”)
「不是End-to-End」:使用起來(lái)并沒(méi)有那么方便
ok,here comes SentencePiece!來(lái)看看是怎么解決上述問(wèn)題的
SentencePiece首先將所有輸入轉(zhuǎn)換為unicode字符。這意味著它不必?fù)?dān)心不同的語(yǔ)言、字符或符號(hào),可以以相同的方式處理所有輸入; 空白也被當(dāng)作普通符號(hào)來(lái)處理。Sentencepiece顯式地將空白作為基本標(biāo)記來(lái)處理,用一個(gè)元符號(hào) “▁”( U+2581 )轉(zhuǎn)義空白,這樣就可以實(shí)現(xiàn)簡(jiǎn)單地decoding Sentencepiece可以直接從raw text進(jìn)行訓(xùn)練,并且官方稱非???!
快結(jié)束了,我想說(shuō)一下,這真的不是Sentencepiece的軟文(谷歌,打錢?。?/p>
SentencePiece集成了兩種subword算法,BPE和UniLM, WordPiece 則是谷歌內(nèi)部的子詞包,沒(méi)對(duì)外公開。感興趣的可以去官方開源代碼庫(kù)玩玩:google/sentencepiece[6]
放個(gè)栗子:
>>>?import?sentencepiece?as?spm
>>>?s?=?spm.SentencePieceProcessor(model_file='spm.model')
>>>?for?n?in?range(5):
...?????s.encode('New?York',?out_type=str,?enable_sampling=True,?alpha=0.1,?nbest=-1)
...
['▁',?'N',?'e',?'w',?'▁York']
['▁',?'New',?'▁York']
['▁',?'New',?'▁Y',?'o',?'r',?'k']
['▁',?'New',?'▁York']
['▁',?'New',?'▁York']
最后,如果想嘗試WordPiece,大家也可以試試HuggingFace的Tokenization庫(kù)[7]
from?tokenizers?import?Tokenizer
from?tokenizers.models?import?BPE
from?tokenizers.pre_tokenizers?import?Whitespace
from?tokenizers.trainers?import?BpeTrainer
tokenizer?=?Tokenizer(BPE())
tokenizer.pre_tokenizer?=?Whitespace()
trainer?=?BpeTrainer(special_tokens=["[UNK]",?"[CLS]",?"[SEP]",?"[PAD]",?"[MASK]"])
tokenizer.train(trainer,?["wiki.train.raw",?"wiki.valid.raw",?"wiki.test.raw"])
output?=?tokenizer.encode("Hello,?y'all!?How?are?you????")
print(output.tokens)
#?["Hello",?",",?"y",?"'",?"all",?"!",?"How",?"are",?"you",?"[UNK]",?"?"]
本文參考資料
2015年Karpathy: https://github.com/karpathy/char-rnn
[2]Neural Machine Translation of Rare Words with Subword Units: https://arxiv.org/abs/1508.07909
[3]Byte Pair Encoding: https://leimao.github.io/blog/Byte-Pair-Encoding/
[4]Subword Regularization: Improving Neural Network Translation Models with Multiple Subword Candidates: https://arxiv.org/abs/1804.10959
[5]JAPANESE AND KOREAN VOICE SEARCH: https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/37842.pdf
[6]google/sentencepiece: https://github.com/google/sentencepiece
[7]HuggingFace的Tokenization庫(kù): https://github.com/huggingface/tokenizers
-?END?-
往期精彩回顧
獲取本站知識(shí)星球優(yōu)惠券,復(fù)制鏈接直接打開:
https://t.zsxq.com/qFiUFMV
本站qq群704220115。
加入微信群請(qǐng)掃碼:
