NLP 新紀元?如何看待轟炸閱讀理解頂級測試的BERT模型?
Google AI最近又掀起了瓜界旋風。這次是BERT模型刷爆了閱讀理解的各項測試,一夜間大家似乎走進了NLP的"新時代"。
在11項NLP任務中,BERT模型奪得SOTA結果,在自然語言處理學界以及工業界都引起了不小的熱議,瓜界也是驚呼變天了。那天晚上10點,當我帶著澎湃的心情,跑上13樓求教我司實力與顏值兼具的演算法大拿鋒哥的時候,鋒哥還神遊在密密麻麻的程式碼世界裡。過了半晌,才悠悠地回了一句,“你們啊,太不關心我們研發了。”
鋒哥說BERT模型“吃下”了33億文字的語料資料,堪稱大塊頭,然後又在不同的下游任務中“微調”,就像駱駝穿過針眼一樣,很精細,最終在不同任務中取得了目前最好的效果。
“遠在天邊,近在眼前,不知道我們今年就在搞這個東西嗎?每天就知道在前端APP、微信上跟機器人撩來撩去,底層演算法關心有木有?BERT也絕非平地驚雷,模型也是有兄弟姐妹,高矮胖瘦的好伐。”明天我給你碼一篇,好好解讀下BERT的來龍去脈。
BERT的“前任”們
早在2015年的時候,微軟研究院的何凱明和他的同事們發表了殘差網路的論文,第一次通過殘差的方式將卷積神經網路推進到了100層以上,並在影象識別的任務上重新整理了當時的最高紀錄。
自那以後起, 隨著網路不斷地加深,效果也在不斷提升。 然而大量的資料訓練出來的大型網路雖然效果更好,但隨著網路的加深以及資料集的不斷擴大,完全重新訓練一個模型所需要的成本也在不斷地增加。
因此在計算機視覺處理中,人們越來越多地採用預訓練好的大型網路來提取特徵,然後再進行後續任務。目前這種處理方式已經是影象處理中很常見的做法了。
相比之下,自然語言處理目前通常會使用預訓練的詞向量來進行後續任務。但詞向量是通過淺層網路進行無監督訓練,雖然在詞的級別上有著不錯的特性,但卻缺少對連續文字的內在聯絡和語言結構的表達能力。
因此大家也 希望能像影象領域那樣,通過大量資料來預訓練一個大型的神經網路,然後用它來對文字提取特徵去做後續的任務,以期望能得到更好的效果。 其實這一方向的研究一直在持續,直到今年的早些時候AllenAI提出的ELMo由於其在後續任務上的優異表現獲得了不小的關注。
在CMRC2018閱讀理解比賽中,追一科技的參賽方案就運用了ELMo模型的預訓練方式,並做了相應的改進, ofollow,noindex">並拿下了測試的第一名 。因為原本的ELMo當中對英文進行了字元級別的編碼,但這對中文並不適用。我們在此基礎上改進為筆畫級別的編碼,同時結合原有的詞級別編碼一起通過雙層LSTM變換來進行語言模型預訓練。經過實驗驗證,最後選擇了512維的詞級別ELMo向量進行後續任務。
在ELMo獲得成功以後不久FastAI就推出了ULMFiT,其大體思路是在微調時對每一層設定不同的學習率。此後OpenAI又提出了GPT。 追一科技在文字蘊含、觀點型閱讀理解等任務中,就採用了GPT模型作為預訓練方案。 預訓練的語言模型是在百度15億詞文字的語料上進行的,模型引數選擇了12層,12head的Transformer結構。然後採用此模型直接在子任務上微調來進行後續任務。
從上面提及的這些論文的結果以及學界和工業界的反饋來看, 這種使用大量的語料進行預訓練,然後再在預訓練好的模型上進行後續任務訓練,雖然訓練方式各有不同,但在後續任務都有不同程度的提高。
而谷歌提出的BERT就是在OpenAI的GPT的基礎上對預訓練的目標進行了修改,並用更大的模型以及更多的資料去進行預訓練,從而得到了目前為止最好的效果。

Trransformer的編碼器結構
BERT主體結構和創新點
BERT模型沿襲了GPT模型的結構,採用Transfomer的編碼器作為主體模型結構。Transformer捨棄了RNN的迴圈式網路結構,完全基於注意力機制來對一段文字進行建模。
Transformer所使用的注意力機制的核心思想是去計算一句話中的每個詞對於這句話中所有詞的相互關係,然後認為這些詞與詞之間的相互關係在一定程度上反應了這句話中不同詞之間的關聯性以及重要程度。因此再利用這些相互關係來調整每個詞的重要性(權重)就可以獲得每個詞新的表達。這個新的表徵不但蘊含了該詞本身,還蘊含了其他詞與這個詞的關係,因此和單純的詞向量相比是一個更加全域性的表達。
Transformer通過對輸入的文字不斷進行這樣的注意力機制層和普通的非線性層交疊來得到最終的文字表達。
Transformer的注意力層得到的詞-詞之間關係
GPT則利用了Transformer的結構來進行單向語言模型的訓練。所謂的語言模型其實是自然語言處理中的一種基礎任務,其目標是給定一個序列文字,預測下一個位置上會出現的詞。
模型學習這樣的任務過程和我們人學習一門語言的過程有些類似。我們學習語言的時候會不斷地練習怎麼選用合適的詞來造句,對於模型來說也這樣。例如:
> 今天 天氣 不錯, 我們 去 公園 玩 吧。
這句話,單向語言模型在學習的時候是從左向右進行學習的,先給模型看到“今天 天氣”兩個詞,然後告訴模型下一個要填的詞是“不錯”。然而單向語言模型有一個欠缺,就是模型學習的時候總是按照句子的一個方向去學的,因此模型學習每個詞的時候只看到了上文,並沒有看到下文。
更加合理的方式應該是讓模型同時通過上下文去學習,這個過程有點類似於完形填空題。例如:
>今天 天氣 { }, 我們 去 公園 玩 吧。
通過這樣的學習,模型能夠更好地把握“不錯”這個詞所出現的上下文語境。
而BERT對GPT的第一個改進就是引入了雙向的語言模型任務。
此前其實也有一些研究在語言模型這個任務上使用了雙向的方法,例如在ELMo中是通過雙向的兩層RNN結構對兩個方向進行建模,但兩個方向的loss計算相互獨立。追一科技在文字意圖模型中,也加入了通過上下文預測某個詞的輔助任務,通過 實驗發現在做意圖分類的同時加入這個輔助任務能夠讓編碼器儘可能的包含輸入文字的全域性資訊,從而提高意圖判斷的準確率。
而BERT的作者指出這種兩個方向相互獨立或只有單層的雙向編碼可能沒有發揮最好的效果,我們可能不僅需要雙向編碼,還應該要加深網路的層數。但加深雙向編碼網路卻會引入一個問題,導致模型最終可以間接地“窺探”到需要預測的詞。這個“窺探”的過程可以用下面的圖來表示:
從圖中可以看到經過兩層的雙向操作,每個位置上的輸出就已經帶有了原本這個位置上的詞的資訊了。這樣的“窺探”會導致模型預測詞的任務變得失去意義,因為模型已經看到每個位置上是什麼詞了。
為了解決這個問題,我們可以從預訓練的目標入手。我們想要的其實是讓模型學會某個詞適合出現在怎樣的上下文語境當中;反過來說,如果給定了某個上下文語境,我們希望模型能夠知道這個地方適合填入怎樣的詞。
從這一點出發,其實我們可以直接去掉這個詞,只讓模型看上下文,然後來預測這個詞。但這樣做會丟掉這個詞在文字中的位置資訊,那麼還有一種方式是在這個詞的位置上隨機地輸入某一個詞,但如果每次都隨機輸入可能會讓模型難以收斂。
BERT的作者提出了採用MaskLM的方式來訓練語言模型。
通俗地說就是在輸入一句話的時候,隨機地選一些要預測的詞,然後用一個特殊的符號來代替它們。儘管模型最終還是會看到所有位置上的輸入資訊,但由於需要預測的詞已經被特殊符號代替,所以模型無法事先知道這些位置上是什麼詞,這樣就可以讓模型根據所給的標籤去學習這些地方該填的詞了。
然而這裡還有一個問題,就是我們在預訓練過程中所使用的這個特殊符號,在後續的任務中是不會出現的。
因此,為了和後續任務保持一致,作者按一定的比例在需要預測的詞位置上輸入原詞或者輸入某個隨機的詞。當然,由於一次輸入的文字序列中只有部分的詞被用來進行訓練,因此BERT在效率上會低於普通的語言模型,作者也指出BERT的收斂需要更多的訓練步數。
BERT另外一個創新是在雙向語言模型的基礎上額外增加了一個句子級別的連續性預測任務。這個任務的目標也很簡單,就是預測輸入BERT的兩端文字是否為連續的文字,作者指出引入這個任務可以更好地讓模型學到連續的文字片段之間的關係。在訓練的時候,輸入模型的第二個片段會以50%的概率從全部文字中隨機選取,剩下50%的概率選取第一個片段的後續的文字。
模型大小和資料量都很重要
以上的描述涵蓋了BERT在模型結構和訓練目標上的主要創新點,而BERT的成功還有一個很大的原因來自於模型的體量以及訓練的資料量。
BERT訓練資料採用了英文的開源語料BooksCropus 以及英文維基百科資料,一共有33億個詞。同時 BERT模型的標準版本有1億的引數量,與GPT持平,而BERT的大號版本有3億多引數量,這應該是目前自然語言處理中最大的預訓練模型了 。
當然,這麼大的模型和這麼多的資料,訓練的代價也是不菲的。谷歌用了16個自己的TPU叢集(一共64塊TPU)來訓練大號版本的BERT,一共花了4天的時間。對於是否可以復現預訓練,作者在Reddit上有一個大致的回覆,指出OpenAI當時訓練GPT用了將近1個月的時間,而如果用同等的硬體條件來訓練BERT估計需要1年的時間。不過他們會將已經訓練好的模型和程式碼開源,方便大家訓練好的模型上進行後續任務。
雖然訓練的代價很大,但是這個研究還是帶來了一些思考和啟發。例如 雙向語言模型的運用,多工對預訓練的幫助以及模型深度帶來的收益。 相信在未來的一段時間,自然語言處理中預訓練的神經網路語言模型會得到更多的關注和運用。