【NLP】机器如何认识文本 ?NLP中的Tokenization方法总结
Tokenization
關于Tokenization,網上有翻譯成"分詞"的,但是我覺得不是很準確,容易引起誤導。一直找不到合適的中文來恰當表達,所以下文采用原汁原味的英文表達。
在正式進入主題之前,先來看看NLP任務中最基礎也最先需要進行的一步:tokenization。簡單說,該操作的目地是將輸入文本分割成一個個token,和詞典配合以讓機器認識文本。Tokenization的難點在于如何獲得理想的切分,使文本中所有的token都具有正確的表義,并且不會存在遺漏(OOV問題)。
接下來,我們簡單梳理下目前主流的tokenization方法,及其優缺點。
詞粒度
詞粒度的切分就跟人類平時理解文本原理一樣,常常用一些工具來完成,例如英文的NLTK、SpaCy,中文的jieba、LTP等。舉個栗子:
英文:
live in New York ------> live / in / New York /
中文:
在紐約生活 -----> 在 / 紐約 / 生活
詞粒度的切分能夠非常好地保留完整語義信息,但是如果出現拼寫錯誤、英文中的縮寫等情況,魯棒性一般。另一方面,詞切分會產生非常巨大的詞表,而且這都不能確保不會出現out of vocabulary問題。
字粒度
字粒度最早應該是2015年Karpathy[1]提出,簡單說英文就是以字母為單位(對于大小寫不敏感的任務,甚至可以先轉小寫再切分),中文就是以字為單位,舉個栗子,
英文:
live in New York -----> l / i / v /e / i / n / N / e / w / Y / o / r /k
中文:
在紐約生活 -----> 在 / 紐 / 約 / 生 / 活
可以看出,字粒度的切分很好地解決了詞粒度的缺陷,魯棒性增強、詞表大大減小。但另一方面,也會帶來一些麻煩:
「毫無意義」:一個字母或一個單字本質上并沒有任何語義意義;
「增加輸入計算壓力」:減小詞表的代價就是輸入長度大大增加,從而輸入計算變得更耗時耗力;
如果詞粒度不理想,而且字粒度似乎也有自己的問題,那么還有什么替代方法呢?
Here comes subword tokenization!
Subword粒度
我們理想中的tokenization需要滿足:
它能夠在不需要無限詞匯表的情況下處理缺失的標記,即通過有限的已知單詞列表來處理無限的潛在詞匯;
此外,我們不希望將所有內容分解為單個字符的額外復雜性,因為字符級別可能會丟失單詞級別的一些含義和語義細節。
為此,我們需要考慮如何重新利用『小』單詞來創建『大』單詞。subword tokenization不轉換最常見的單詞,而是將稀有單詞分解成有意義的子詞單元。如果unfriendly被標記為一個稀有詞,它將被分解為un-friendly-ly,這些單位都是有意義的單位,un的意思是相反的,friend是一個名詞,ly則變成副詞。這里的挑戰是如何進行細分,我們如何獲得un-friend-ly而不是unfr-ien-dly。
NLP最火的網紅 Transformer 和 BERT 就是Subword的帶鹽人,來看個它們做tokenization的栗子,
I have a new GPU ?----> [’i’, ’have’, ’a’, ’new’, ’gp’, ’##u’, ’.’]
subword粒度切分算法又有以下幾種:
BPE
WordPiece
ULM
BPE
BPE全稱Byte Pair Encoding,字節對編碼,首先在Neural Machine Translation of Rare Words with Subword Units[2] 中提出。BPE 迭代地合并最頻繁出現的字符或字符序列,具體步驟:
準備足夠大的語料庫
定義好所需要的詞表大小
將單詞拆分為字符序列,在末尾添加后綴 </ w>,并統計單詞頻率。本階段的subword的粒度是字符。例如,“ low”的頻率為5,那么我們將其改寫為l o w </ w>:5
統計每一個連續字節對的出現頻率,選擇最高頻者合并成新的subword
重復第4步直到達到第2步設定的subword詞表大小或下一個最高頻的字節對出現頻率為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}第一輪迭代,統計連續的每兩個字節出現的次數,發現 e 和s 共現次數最大,合并成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}第二輪迭代,統計連續的每兩個字節出現的次數,發現 es 和t 共現次數最大,合并成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}依次繼續迭代直到達到預設的subword詞表大小或下一個最高頻的字節對出現頻率為1。
以上是BPE的整體流程,關于BPE更多細節可以參考:Byte Pair Encoding[3]
Unigram LM
Unigram語言建模首先在Subword Regularization: Improving Neural Network Translation Models with Multiple Subword Candidates[4]中提出,基于所有子詞出現是獨立的假設,因此子詞序列由子詞出現概率的乘積生成。算法步驟如下:
準備足夠大的語料庫
定義好所需要的詞表大小
給定詞序列優化下一個詞出現的概率
計算每個subword的損失
基于損失對subword排序并保留前X%。為了避免OOV,保留字符級的單元
重復第3至第5步直到達到第2步設定的subword詞表大小或第5步的結果不再變化
unigram-LM模型比BPE更靈活,因為它基于概率LM,并且可以輸出具有概率的多個分段。它不是從一組基本符號開始,更具某些規則進行合并,如BPE或WordPiece,而是從一個龐大的詞匯量開始,例如所有預處理的單詞和最常見的子字符串,并逐步減少。
WordPiece
WordPiece首先在 JAPANESE AND KOREAN VOICE SEARCH[5] 中提出,最初用于解決日語和韓語語音問題。它在許多方面類似于BPE,只是它基于可能性而不是下一個最高頻率對來形成一個新的子詞。算法步驟如下:
準備足夠大的語料庫
定義好所需要的詞表大小
將單詞拆分成字符序列
基于第3步數據訓練語言模型
從所有可能的subword單元中選擇加入語言模型后能最大程度地增加訓練數據概率的單元作為新的單元
重復第5步直到達到第2步設定的subword詞表大小或概率增量低于某一閾值
WordPiece更像是BPE和Unigram LM的結合。
小結
簡單幾句話總結下Subword的三種算法:
BPE:只需在每次迭代中使用「出現頻率」來確定最佳匹配,直到達到預定義的詞匯表大小;
Unigram:使用概率模型訓練LM,移除提高整體可能性最小的token;然后迭代進行,直到達到預定義的詞匯表大小;
WordPiece:結合BPE與Unigram,使用「出現頻率」來確定潛在匹配,但根據合并token的概率做出最終決定.
Sentencepiece
到目前為止,可以發現subword結合了詞粒度和字粒度方法的優點,并避免了其不足。但是,仔細想會發現上述三種subword算法都存在一些問題:
「都需要提前切分(pretokenization)」 :這對于某些語言來說,可能是不合理的,因為不可以用空格來分隔單詞;
「無法逆轉」:原始輸入和切分后序列是不可逆的。舉個栗子,下面兩者的結果是相等的,即空格的信息經過該操作被丟失
Tokenize(“World.”) == Tokenize(“World .”)
「不是End-to-End」:使用起來并沒有那么方便
ok,here comes SentencePiece!來看看是怎么解決上述問題的
SentencePiece首先將所有輸入轉換為unicode字符。這意味著它不必擔心不同的語言、字符或符號,可以以相同的方式處理所有輸入;
空白也被當作普通符號來處理。Sentencepiece顯式地將空白作為基本標記來處理,用一個元符號 “▁”( U+2581 )轉義空白,這樣就可以實現簡單地decoding
Sentencepiece可以直接從raw text進行訓練,并且官方稱非常快!
快結束了,我想說一下,這真的不是Sentencepiece的軟文(谷歌,打錢!)
SentencePiece集成了兩種subword算法,BPE和UniLM, WordPiece 則是谷歌內部的子詞包,沒對外公開。感興趣的可以去官方開源代碼庫玩玩:google/sentencepiece[6]
放個栗子:
>>>?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庫[7]
from?tokenizers?import?Tokenizer from?tokenizers.models?import?BPE from?tokenizers.pre_tokenizers?import?Whitespace from?tokenizers.trainers?import?BpeTrainertokenizer?=?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]",?"?"]本文參考資料
[1]
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庫: https://github.com/huggingface/tokenizers
-?END?-
往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習及深度學習筆記等資料打印機器學習在線手冊深度學習筆記專輯《統計學習方法》的代碼復現專輯 AI基礎下載機器學習的數學基礎專輯 獲取本站知識星球優惠券,復制鏈接直接打開: https://t.zsxq.com/qFiUFMV 本站qq群704220115。加入微信群請掃碼:總結
以上是生活随笔為你收集整理的【NLP】机器如何认识文本 ?NLP中的Tokenization方法总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【经验】新人学习写程序的第一道坎
- 下一篇: 为什么机器学习工程师用PyTorch的多