tft每日頭條

 > 生活

 > bert是用來幹嘛的

bert是用來幹嘛的

生活 更新时间:2024-09-27 12:09:27

bert是用來幹嘛的(BERT詳解)1

前言

還記得不久之前的機器閱讀理解領域,微軟和阿裡在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是什麼呢?

模型

bert是用來幹嘛的(BERT詳解)2

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

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

負采樣

我們知道對于訓練語言模型來說,softmax層非常難算,畢竟你要預測的是當前位置是哪個詞,那麼這個類别數就等同于詞典規模,因此動辄幾萬幾十萬的類别數,算softmax函數當然很費力啦。但是,如果我們的目标不在于訓練一個精準的語言模型,而隻是為了訓練得到語言模型的副産物-詞向量,那麼其實隻需要用這裡隐含的一個計算代價更小的“子任務”就好啦。

想一想,給你10000張寫有數字的卡片,讓你找出其中的最大值,是不是特别費力?但是如果把裡面的最大值事先抽出來,跟五張随機抽取的卡片混到一起,讓你選出其中的最大值,是不是就容易多啦?

負采樣就是這個思想,即不直接讓模型從整個詞表找最可能的詞了,而是直接給定這個詞(即正例)和幾個随機采樣的噪聲詞(即采樣出來的負例),隻要模型能從這裡面找出正确的詞就認為完成目标啦。所以這個想法對應的目标函數即:

bert是用來幹嘛的(BERT詳解)3

這裡

bert是用來幹嘛的(BERT詳解)4

是正例,

bert是用來幹嘛的(BERT詳解)5

是随機采樣出來的負例(采樣k個),

bert是用來幹嘛的(BERT詳解)6

是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。訓練它的話自然也是語言模型标準的最大化似然函數,即

bert是用來幹嘛的(BERT詳解)7

不過這個ELMo的亮點當然不在于模型層,而是其通過實驗間接說明了在多層的RNN中,不同層學到的特征其實是有差異的,因此ELMo提出在預訓練完成并遷移到下遊NLP任務中時,要為原始詞向量層和每一層RNN的隐層都設置一個可訓練參數,這些參數通過softmax層歸一化後乘到其相應的層上并求和便起到了weighting的作用,然後對“加權和”得到的詞向量再通過一個參數來進行詞向量整體的scaling以更好的适應下遊任務。

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

數學表達式如下

bert是用來幹嘛的(BERT詳解)8

其中L=2就是ELMo論文中的設定,j=0時代表原始詞向量層,j=1是lstm的第一隐層,j=2是第二隐層。

bert是用來幹嘛的(BERT詳解)9

是參數被softmax歸一化之後的結果(也就是說

bert是用來幹嘛的(BERT詳解)10

)。

通過這樣的遷移策略,那些對詞義消歧有需求的任務就更容易通過訓練給第二隐層一個很大的權重,而對詞性、句法有明顯需求的任務則可能對第一隐層的參數學習到比較大的值(實驗結論)。總之,這樣便得到了一份”可以被下遊任務定制“的特征更為豐富的詞向量,效果比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)。但是在預訓練模型上,先前的最先進模型也隻是基于傳統的語言模型來做,而傳統的語言模型是單向的(數學上已經定義了),即

bert是用來幹嘛的(BERT詳解)11

而且往往都很淺(想象一下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],如圖

bert是用來幹嘛的(BERT詳解)12

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是用來幹嘛的(BERT詳解)13

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

真正體現出BERT這個模型是龍骨級模型而不再是詞向量的,就是其到各個下遊任務的接口設計了,或者換個更洋氣的詞叫遷移策略。 首先,既然句子和句子對的上層表示都得到了,那麼當然對于文本分類任務和文本匹配任務(文本匹配其實也是一種文本分類任務,隻不過輸入是文本對)來說,隻需要用得到的表示(即encoder在[CLS]詞位的頂層輸出)加上一層MLP就好了呀~

bert是用來幹嘛的(BERT詳解)14

既然文本都被深度雙向encoding了,那麼做序列标注任務就隻需要加softmax輸出層就好了呀,連CRF都不用了呀~

bert是用來幹嘛的(BERT詳解)15

讓小夕更木有想到的是,在span抽取式任務如SQuAD上,把深度encoding和深度attention這倆大禮包省掉就算了,甚至都敢直接把輸出層的pointer net給丢掉了?直接像DrQA那樣傲嬌的用兩個線性分類器分别輸出span的起點和終點?不多說了,已跪m(_ _)m

bert是用來幹嘛的(BERT詳解)16

最後來看一下實驗效果

bert是用來幹嘛的(BERT詳解)17

bert是用來幹嘛的(BERT詳解)18

bert是用來幹嘛的(BERT詳解)19

嗯,這很Google。

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

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved