NLP預訓練模型綜述:從word2vec, ELMo到BERT

目錄

 

前言

word2vec

模型

負採樣

char-level與上下文

ELMo

BERT

深層雙向的encoding

學習句子與句對關係表示

簡潔到過分的下游任務接口


前言

還記得不久之前的機器閱讀理解領域,微軟和阿里在SQuAD上分別以R-Net+和SLQA超過人類,百度在MS MARCO上憑藉V-Net霸榜並在BLEU上超過人類。這些網絡可以說一個比一個複雜,似乎「如何設計出一個更work的task-specific的網絡"變成了NLP領域政治正確的研究方向。而在這種風向下,不管word2vec也好,glove也好,fasttext也好,都只能充當一個錦上添花的作用。說好的遷移學習、預訓練呢?在NLP似乎始終沒成主角。
小夕寫這篇文章時也有點慚愧,搞了好一段時間的表示與遷移,雖然早在直覺上感覺這應該是NLP的核心問題,但是也沒做出一些令自己滿意的實驗結果,直到幾天前的BERT出來,才感覺是貧窮限制了我的想象力╮( ̄▽ ̄」」)╭(劃掉),才感覺自己着眼的點還是太窄了。每個人對於BERT的理解都不一樣,本文就試着從word2vec和ELMo的角度說說BERT。下面先簡單回顧一下word2vec和ELMo中的精華,已經理解很透徹的小夥伴可以快速下拉到BERT章節啦。

word2vec

說來也都是些俗套而樂此不疲一遍遍寫的句子,2013年Google的word2vec一出,讓NLP各個領域遍地開花,一時間好像不用上預訓練的詞向量都不好意思寫論文了。而word2vec是什麼呢?

模型

顯然就是一個「線性」語言模型。既然我們的目標是學習詞向量,而且詞向量在語義上要支持一些」線性的語義運算「,如」皇帝-皇后=男-女「(忽略武則天),那麼使用一個線性模型自然足夠了,跑的又快又能完成任務,非常優雅。

另外word2vec的一個精髓是把語言模型的那一套softmax加速方法也給順便優化了,用一個看似開腦洞的「負採樣」方法來代替傳統的層級softmax和NCE做法。而這個名字高大上的「負採樣」到底是什麼呢?

負採樣

我們知道對於訓練語言模型來說,softmax層非常難算,畢竟你要預測的是當前位置是哪個詞,那麼這個類別數就等同於詞典規模,因此動輒幾萬幾十萬的類別數,算softmax函數當然很費力啦。但是,如果我們的目標不在於訓練一個精準的語言模型,而只是爲了訓練得到語言模型的副產物-詞向量,那麼其實只需要用這裏隱含的一個計算代價更小的「子任務」就好啦。想一想,給你10000張寫有數字的卡片,讓你找出其中的最大值,是不是特別費力?但是如果把裏面的最大值事先抽出來,跟五張隨機抽取的卡片混到一起,讓你選出其中的最大值,是不是就容易多啦?負採樣就是這個思想,即不直接讓模型從整個詞表找最可能的詞了,而是直接給定這個詞(即正例)和幾個隨機採樣的噪聲詞(即採樣出來的負例),只要模型能從這裏面找出正確的詞就認爲完成目標啦。所以這個想法對應的目標函數即:這裏是正例,是隨機採樣出來的負例(採樣k個),是sigmoid函數。然後即最大化正例的似然,最小化負例的似然。這種負採樣的思想被成功的應用在了BERT模型中,只不過粒度從詞變成了句子。不要急,慢慢往後看~

char-level與上下文

雖然2015年到2017年也有不少工作試圖從char-level入手,另闢蹊徑,擺脫預訓練詞向量的遊戲規則,然而實測只是曇花一現,很快被懟了[8][9]。不過,人們同時也意識到了char-level的文本中也蘊含了一些word-level的文本所難以描述的模式,因此一方面出現了可以學習到char-level特徵的詞向量FastText[5],另一方面在有監督任務中開始通過淺層CNN、HIghwayNet、RNN等網絡引入char-level文本的表示。不過,至此爲止,詞向量都是上下文無關的。也就是說,同一個詞在不同的語境中總是相同的詞向量,很明顯這就導致詞向量模型缺乏詞義消歧(WSD)的能力。於是,**人們爲了讓詞向量變得上下文相關,開始在具體的下游任務中基於詞向量sequence來做encoding。**最常見的encoding方法當然就是用RNN系的網絡,除此之外還有成功的用深層CNN來encoding的工作(如文本分類[6],機器翻譯[7],機器閱讀理解[4]),然!而!Google說了,CNN也太俗了,我們要用全連接網絡!(劃掉)self-attention!於是就有了爲NLP深度定製的Transformer模型[11],Transformer的提出是在機器翻譯任務上,但是其在其他領域如檢索式對話[3]上也發揮了巨大的威力。不過,既然發現在各個NLP任務中基本都有encoding的需要,那麼爲啥不在最開始就讓詞向量擁有上下文相關的能力呢?於是有了ELMo[2]。

ELMo

當然,實際上ELMo不是第一個試圖產生上下文相關的詞向量的模型,不過確是一個讓你有充分理由放棄word2vec的模型(手動微笑),畢竟犧牲點推理速度換來辣麼多的性能提升,大部分情況下超值呀~ELMo在模型層上就是一個stacked bi-lstm(嚴格來說是訓練了兩個單向的stacked lstm),所以當然有不錯的encoding能力。同時其源碼實現上也支持用Highway Net或者CNN來額外引入char-level encoding。訓練它的話自然也是語言模型標準的最大化似然函數,即不過這個ELMo的亮點當然不在於模型層,而是其通過實驗間接說明了在多層的RNN中,不同層學到的特徵其實是有差異的,因此ELMo提出在預訓練完成並遷移到下游NLP任務中時,要爲原始詞向量層和每一層RNN的隱層都設置一個可訓練參數,這些參數通過softmax層歸一化後乘到其相應的層上並求和便起到了weighting的作用,然後對「加權和」得到的詞向量再通過一個參數來進行詞向量整體的scaling以更好的適應下游任務。

ps:其實最後這個參數還是非常重要的,比如word2vec中,一般來說cbow和sg學出來的詞向量方差差異比較大,這時那個方差跟適合下游任務後續層方差匹配的詞向量就收斂更快,更容易有更好的表現

數學表達式如下

其中L=2就是ELMo論文中的設定,j=0時代表原始詞向量層,j=1是lstm的第一隱層,j=2是第二隱層。是參數被softmax歸一化之後的結果(也就是說)。通過這樣的遷移策略,那些對詞義消歧有需求的任務就更容易通過訓練給第二隱層一個很大的權重,而對詞性、句法有明顯需求的任務則可能對第一隱層的參數學習到比較大的值(實驗結論)。總之,這樣便得到了一份」可以被下游任務定製「的特徵更爲豐富的詞向量,效果比word2vec好得多也就不足爲奇了。不過話說回來,ELMo的目標也僅僅是學習到上下文相關的、更強大的詞向量,其目的依然是爲下游任務提供一個紮實的根基,還沒有想要弒君稱王的意思。而我們知道,僅僅是對文本進行充分而強大的encoding(即得到每個詞位非常精準豐富的特徵)是遠不夠覆蓋所有NLP任務的。在QA、機器閱讀理解(MRC)、自然語言推理(NLI)、對話等任務中,還有很多更復雜的模式需要捕捉,比如句間關係。爲此,下游任務中的網絡會加入各種花式attention(參考NLI、MRC、Chatbot中的SOTA們)。而隨着捕捉更多神奇模式的需要,研究者們爲每個下游任務定製出各種各樣的網絡結構,導致同一個模型,稍微一換任務就掛掉了,甚至在同一個任務的情況下換另一種分佈的數據集都會出現顯著的性能損失,這顯然不符合人類的語言行爲呀~要知道人類的generalization能力是非常強的,這就說明,或許現在整個NLP的發展軌跡就是錯的,尤其是在SQuAD的帶領下,窮盡各種trick和花式結構去刷榜,真正之於NLP的意義多大呢?好像扯遠了,不過所幸,這條越走越偏的道路終於被一個模型shutdown了,那就是幾天前Google發佈的Bidirectional Encoder Representations from Transformers (BERT)[1].

BERT

這篇paper的最重要意義不在於用了什麼模型,也不在於怎麼訓練的,而是它提出一種全新的遊戲規則。開始遊戲之前,先幫小夕點一下小廣告好不好呀\(//∇//)\

像之前說的,爲每個NLP任務去深度定製泛化能力極差的複雜模型結構其實是非常不明智的,走偏了方向的。既然ELMo相比word2vec會有這麼大的提升,這就說明預訓練模型的潛力遠不止爲下游任務提供一份精準的詞向量,所以我們可不可以直接預訓練一個龍骨級的模型呢?如果它裏面已經充分的描述了字符級、詞級、句子級甚至句間關係的特徵,那麼在不同的NLP任務中,只需要去爲任務定製一個非常輕量級的輸出層(比如一個單層MLP)就好了,畢竟模型骨架都已經做好了嘛。而BERT正是做了這件事情,或者說,它真的把這件事情做成了,它作爲一個general的龍骨級模型輕鬆的挑戰了11個任務上的深度定製的模型。。。所以它怎麼完成的呢?

深層雙向的encoding

首先,它指出,對上下文相關的詞向量的學習上,先前的預訓練模型還不夠!雖然在下游有監督任務中,encoding的方式已經是花裏胡哨非常充分了,深度雙向encoding基本成了許多複雜下游任務的標配(比如MRC, dialogue)。但是在預訓練模型上,先前的最先進模型也只是基於傳統的語言模型來做,而傳統的語言模型是單向的(數學上已經定義了),即而且往往都很淺(想象一下LSTM堆三層就train不動了,就要上各種trick了),比如ELMo。另外,雖然ELMo有用雙向RNN來做encoding,但是這兩個方向的RNN其實是分開訓練的,只是在最後在loss層做了個簡單相加。這樣就導致對於每個方向上的單詞來說,在被encoding的時候始終是看不到它另一側的單詞的。而顯然句子中有的單詞的語義會同時依賴於它左右兩側的某些詞,僅僅從單方向做encoding是不能描述清楚的。**那麼爲什麼不像下游監督任務中那樣做真正的雙向encoding呢?**原因一想就很清楚了,畢竟傳統的語言模型是以預測下一個詞爲訓練目標的,然而如果做了雙向encoding的話,那不就表示要預測的詞已經看到了嘛╮( ̄▽ ̄」」)╭這樣的預測當然沒有意義了。所以,在BERT中,提出了使用一種新的任務來訓練監督任務中的那種真正可以雙向encoding的模型,這個任務稱爲Masked Language Model (Masked LM)。

Masked LM

顧名思義,Masked LM就是說,我們不是像傳統LM那樣給定已經出現過的詞,去預測下一個詞,而是直接把整個句子的一部分詞(隨機選擇)蓋住(make it masked),這樣模型不就可以放心的去做雙向encoding了嘛,然後就可以放心的讓模型去預測這些蓋住的詞是啥。這個任務其實最開始叫做cloze test(大概翻譯成「完形填空測試」)。這樣顯然會導致一些小問題。這樣雖然可以放心的雙向encoding了,但是這樣在encoding時把這些蓋住的標記也給encoding進去了╮( ̄▽ ̄」」)╭而這些mask標記在下游任務中是不存在的呀。。。那怎麼辦呢?對此,爲了儘可能的把模型調教的忽略這些標記的影響,作者通過如下方式來告訴模型「這些是噪聲是噪聲!靠不住的!忽略它們吧!」,對於一個被蓋住的單詞:

  • 有80%的概率用「[mask]」標記來替換

  • 有10%的概率用隨機採樣的一個單詞來替換

  • 有10%的概率不做替換(雖然不做替換,但是還是要預測哈)

Encoder

在encoder的選擇上,作者並沒有用爛大街的bi-lstm,而是使用了可以做的更深、具有更好並行性的Transformer encoder來做。這樣每個詞位的詞都可以無視方向和距離的直接把句子中的每個詞都有機會encoding進來。另一方面我主觀的感覺Transformer相比lstm更容易免受mask標記的影響,畢竟self-attention的過程完全可以把mask標記針對性的削弱匹配權重,但是lstm中的輸入門是如何看待mask標記的那就不得而知了。等下,小夕在之前的文章中也說過了,直接用Transformer encoder顯然不就丟失位置信息了嘛?難道作者這裏也像Transformer原論文中那樣搞了個讓人怕怕的sin、cos函數編碼位置?並木有,作者這裏很簡單粗暴的直接去訓練了一個position embedding ╮( ̄▽ ̄」」)╭ 這裏就是說,比如我把句子截斷到50的長度,那麼我們就有50個位置嘛,所以就有50個表徵位置的單詞,即從位置0一直到位置49。。。然後給每個位置詞一個隨機初始化的詞向量,再隨他們訓練去吧(很想說這特喵的也能work?太簡單粗暴了吧。。。)。另外,position embedding和word embedding的結合方式上,BERT裏選擇了直接相加。最後,在深度方面,最終BERT完全版的encoder喪心病狂的疊加了24層的multi-head attention block(要知道對話裏的SOTA模型DAM也才用了5層…)。。。而且每個block包含16抽頭、1024隱單元╮( ̄▽ ̄」」)╭此處打出標語:money is all you need (劃掉)

學習句子與句對關係表示

像之前說的,在很多任務中,僅僅靠encoding是不足以完成任務的(這個只是學到了一堆token級的特徵),還需要捕捉一些句子級的模式,來完成SLI、QA、dialogue等需要句子表示、句間交互與匹配的任務。對此,BERT又引入了另一個極其重要卻又極其輕量級的任務,來試圖把這種模式也學習到。

句子級負採樣

還記得小夕在前面word2vec章節說過的,word2vec的一個精髓是引入了一個優雅的負採樣任務來學習詞向量(word-level representation)嘛。那麼如果我們把這個負採樣的過程給generalize到sentence-level呢?這便是BERT學習sentence-level representation的關鍵啦。BERT這裏跟word2vec做法類似,不過構造的是一個句子級的分類任務。即首先給定的一個句子(相當於word2vec中給定context),它下一個句子即爲正例(相當於word2vec中的正確詞),隨機採樣一個句子作爲負例(相當於word2vec中隨機採樣的詞),然後在該sentence-level上來做二分類(即判斷句子是當前句子的下一句還是噪聲)。通過這個簡單的句子級負採樣任務,BERT就可以像word2vec學習詞表示那樣輕鬆學到句子表示啦。

句子級表示

等等,前面說了這麼半天,還沒有說句子該怎麼表示呢。。。BERT這裏並沒有像下游監督任務中的普遍做法一樣,在encoding的基礎上再搞個全局池化之類的,它首先在每個sequence(對於句子對任務來說是兩個拼起來的句子,對於其他任務來說是一個句子)前面加了一個特殊的token,記爲[CLS],如圖

ps:這裏的[sep]是句子之間的分隔符,BERT同時支持學習句對的表示,這裏是[SEP]便是爲了區分句對的切割點。

然後讓encoder對[CLS]進行深度encoding,深度encoding的最高隱層即爲整個句子/句對的表示啦。這個做法乍一看有點費解,不過別忘了,Transformer是可以無視空間和距離的把全局信息encoding進每個位置的,而[CLS]作爲句子/句對的表示是直接跟分類器的輸出層連接的,因此其作爲梯度反傳路徑上的「關卡」,當然會想辦法學習到分類相關的上層特徵啦。另外,爲了讓模型能夠區分裏面的每個詞是屬於「左句子」還是「右句子」,作者這裏引入了「segment embedding」的概念來區分句子。對於句對來說,就用embedding A和embedding B來分別代表左句子和右句子;而對於句子來說,就只有embedding A啦。這個embedding A和B也是隨模型訓練出來的。

ps: 這做法跟position embedding一樣感覺簡單粗暴,實在很費解爲什麼BERT用在「quora question pairs」這種理論上需要網絡保持對稱的任務上依然能work,心情複雜

所以最終BERT每個token的表示由token原始的詞向量token embedding、前文提到的position embedding和這裏的segment embedding三部分相加而成,如圖:

簡潔到過分的下游任務接口

真正體現出BERT這個模型是龍骨級模型而不再是詞向量的,就是其到各個下游任務的接口設計了,或者換個更洋氣的詞叫遷移策略。首先,既然句子和句子對的上層表示都得到了,那麼當然對於文本分類任務和文本匹配任務(文本匹配其實也是一種文本分類任務,只不過輸入是文本對)來說,只需要用得到的表示(即encoder在[CLS]詞位的頂層輸出)加上一層MLP就好了呀~既然文本都被深度雙向encoding了,那麼做序列標註任務就只需要加softmax輸出層就好了呀,連CRF都不用了呀~讓小夕更木有想到的是,在span抽取式任務如SQuAD上,把深度encoding和深度attention這倆大禮包省掉就算了,甚至都敢直接把輸出層的pointer net給丟掉了?直接像DrQA那樣傲嬌的用兩個線性分類器分別輸出span的起點和終點?不多說了,已跪m(_ _)m最後來看一下實驗效果

嗯,這很Google。此論文一出,小夕非常開心,因爲很多之前的想法都不用去做實驗驗證了,因爲已經被BERT摁死了(。 ́︿ ̀。)分類、標註和遷移任務都可以從頭開始了,SQuAD的造樓計劃也可以停了,感謝BERT沒有跑生成任務,這給人帶來了一點想象空間。嗯,手動微笑流淚。

參考文獻

[1] 2018 | BERT- Pre-training of Deep Bidirectional Transformers for Language Understanding [2] 2018NAACL | Deep contextualized word representations [3] 2018 ACL | Multi-Turn Response Selection for Chatbots with Deep Attention Matching Network [4] 2018ICLR | Fast and Accurate Reading Comprehension by Combining Self-Attention and Convolution [5] 2017TACL | Enriching Word Vectors with Subword Information [6] 2017ACL | Deep Pyramid Convolutional Neural Networks for Text Categorization [7] 2017 | Convolutional Sequence to Sequence Learning [8] 2017 | Do Convolutional Networks need to be Deep for Text Classification ? [9] 2016 | Convolutional Neural Networks for Text Categorization/ Shallow Word-level vs. Deep Character-level [10] 2013NIPS | Distributed-representations-of-words-and-phrases-and-their-compositionality