BERT和transformer

前言

BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding(/arxiv.org/abs/1810.04805)。BERT解決方案刷新了各大NLP任務(wù)的榜單,在各種NLP任務(wù)上都做到state of the art。這里我把BERT說成是解決方案,而不是一個算法,因為這篇文章并沒有提出新的算法模型,還是沿用了之前已有的算法模型。BERT最大的創(chuàng)新點,在于提出了一套完整的方案,利用之前最新的算法模型,去解決各種各樣的NLP任務(wù),因此BERT這篇論文對于算法模型完全不做介紹,以至于在我直接看這篇文章的時候感覺云里霧里。但是本文中,我會從算法模型到解決方案,進行完整的詮釋。本文中我會分3個部分進行介紹,第一部分我會大概介紹一下NLP的發(fā)展,第二部分主要講BERT用到的算法,最后一部分講BERT具體是怎么操作的。

NLP發(fā)展

要處理NLP問題,首先要解決文本的表示問題。雖然我們?nèi)巳タ次谋荆軌蚯宄靼孜谋局械姆柋磉_什么含義,但是計算機只能做數(shù)學計算,需要將文本表示成計算機可以處理的形式。最開始的方法是采用one hot,比如,我們假設(shè)英文中常用的單詞有3萬個,那么我們就用一個3萬維的向量表示這個詞,所有位置都置0,當我們想表示apple這個詞時,就在對應位置設(shè)置1,如圖1.1所示。這種表示方式存在的問題就是,高維稀疏,高維是指有多少個詞,就需要多少個維度的向量,稀疏是指,每個向量中大部分值都是0。另外一個不足是這個向量沒有任何含義。

后來出現(xiàn)了詞向量,word embedding,用一個低維稠密的向量去表示一個詞,如圖1.2所示。通常這個向量的維度在幾百到上千之間,相比one hot幾千幾萬的維度就低了很多。詞與詞之間可以通過相似度或者距離來表示關(guān)系,相關(guān)的詞向量相似度比較高,或者距離比較近,不相關(guān)的詞向量相似度低,或者距離比較遠,這樣詞向量本身就有了含義。文本的表示問題就得到了解決。詞向量可以通過一些無監(jiān)督的方法學習得到,比如CBOW或者Skip-Gram等,可以預先在語料庫上訓練出詞向量,以供后續(xù)的使用。順便提一句,在圖像中就不存在表示方法的困擾,因為圖像本身就是數(shù)值矩陣,計算機可以直接處理。

NLP中有各種各樣的任務(wù),比如分類(Classification),問答(QA),實體命名識別(NER)等。對于這些不同的任務(wù),最早的做法是根據(jù)每類任務(wù)定制不同的模型,輸入預訓練好的embedding,然后利用特定任務(wù)的數(shù)據(jù)集對模型進行訓練,如圖1.3所示。這里存在的問題就是,不是每個特定任務(wù)都有大量的標簽數(shù)據(jù)可供訓練,對于那些數(shù)據(jù)集非常小的任務(wù),恐怕就難以得到一個理想的模型。

看一下圖像領(lǐng)域是如何解決這個問題的。圖像分類是計算機視覺中最基本的任務(wù),當我要解決一個小數(shù)據(jù)集的圖像分類任務(wù)時,該怎么做?CV領(lǐng)域已經(jīng)有了一套成熟的解決方案。我會用一個通用的網(wǎng)絡(luò)模型,比如VGG,ResNet或者GoogleNet,在ImageNet上做預訓練(pre-training)。ImageNet有1400萬張有標注的圖片,包含1000個類別,這樣的數(shù)據(jù)規(guī)模足以訓練出一個規(guī)模龐大的模型。在訓練過程中,模型會不斷的學習如何提取特征,底層的CNN網(wǎng)絡(luò)結(jié)構(gòu)會提取邊緣,角,點等通用特征,模型越往上走,提取的特征也越抽象,與特定的任務(wù)更加相關(guān)。當完成預訓練之后,根據(jù)我自己的分類任務(wù),調(diào)整最上層的網(wǎng)絡(luò)結(jié)構(gòu),然后在小數(shù)據(jù)集里對模型進行訓練。在訓練時,可以固定住底層的模型參數(shù)只訓練頂層的參數(shù),也可以對整個模型進行訓練,這個過程叫做微調(diào)(fine-tuning),最終得到一個可用的模型。總結(jié)一下,整個過程包括兩步,拿一個通用模型在ImageNet上做預訓練(pre-training),然后針對特定任務(wù)進行微調(diào)(fine-tuning),完美解決了特定任務(wù)數(shù)據(jù)不足的問題。還有一個好處是,對于各種各樣的任務(wù)都不再需要從頭開始訓練網(wǎng)絡(luò),可以直接拿預訓練好的結(jié)果進行微調(diào),既減少了訓練計算量的負擔,也減少了人工標注數(shù)據(jù)的負擔。

NLP領(lǐng)域也引入了這種做法,用一個通用模型,在非常大的語料庫上進行預訓練,然后在特定任務(wù)上進行微調(diào),BERT就是這套方案的集大成者。BERT不是第一個,但目前為止,是效果最好的方案。BERT用了一個已有的模型結(jié)構(gòu),提出了一整套的預訓練方法和微調(diào)方法,我們在后文中再進行詳細的描述。

算法

BERT所采用的算法來自于2017年12月份的這篇文章,Attenion Is All You Need(/arxiv.org/abs/1706.03762),同樣來自于谷歌。這篇文章要解決的是翻譯問題,比如從中文翻譯成英文。這篇文章完全放棄了以往經(jīng)常采用的RNN和CNN,提出了一種新的網(wǎng)絡(luò)結(jié)構(gòu),即Transformer,其中包括encoder和decoder,我們只關(guān)注encoder。這篇英文博客(/jalammar.github.io/illus)對Transformer介紹得非常詳細,有興趣的讀者可以看一下,如果不想看英文博客也可以看本文,本文中的部分圖片也截取自這篇博客。

圖2.1是Transformer encoder的結(jié)構(gòu),后文中我們都簡稱為Transformer。首先是輸入word embedding,這里是直接輸入一整句話的所有embedding。如圖2.1所示,假設(shè)我們的輸入是Thinking Machines,每個詞對應一個embedding,就有2個embedding。輸入embedding需要加上位置編碼(Positional Encoding),為什么要加位置編碼,后文會做詳細介紹。然后經(jīng)過一個Multi-Head Attention結(jié)構(gòu),這個結(jié)構(gòu)是算法單元中最重要的部分,我們會在后邊詳細介紹。之后是做了一個shortcut的處理,就是把輸入和輸出按照對應位置加起來,如果了解殘差網(wǎng)絡(luò)(ResNet)的同學,會對這個結(jié)構(gòu)比較熟悉,這個操作有利于加速訓練。然后經(jīng)過一個歸一化normalization的操作。接著經(jīng)過一個兩層的全連接網(wǎng)絡(luò),最后同樣是shortcut和normalization的操作。可以看到,除了Multi-Head Attention,都是常規(guī)操作,沒有什么難理解的。這里需要注意的是,每個小模塊的輸入和輸出向量,維度都是相等的,比如,Multi-Head Attention的輸入和輸出向量維度是相等的,否則無法進行shortcut的操作;Feed Forward的輸入和輸出向量維度也是相等的;最終的輸出和輸入向量維度也是相等的。但是Multi-Head Attention和Feed Forward內(nèi)部,向量維度會發(fā)生變化。

來詳細看一下Multi-Head Attention的結(jié)構(gòu)。這個Multi-Head表示多頭的意思,先從最簡單的看起,看看單頭Attention是如何操作的。從圖2.1的橙色方塊可以看到,embedding在進入到Attention之前,有3個分叉,那表示說從1個向量,變成了3個向量。具體是怎么算的呢?我們看圖2.3,定義一個WQ矩陣(這個矩陣隨機初始化,通過訓練得到),將embedding和WQ矩陣做乘法,得到查詢向量q,假設(shè)輸入embedding是512維,在圖3中我們用4個小方格表示,輸出的查詢向量是64維,圖3中用3個小方格以示不同。然后類似地,定義WK和WV矩陣,將embedding和WK做矩陣乘法,得到鍵向量k;將embeding和WV做矩陣乘法,得到值向量v。對每一個embedding做同樣的操作,那么每個輸入就得到了3個向量,查詢向量,鍵向量和值向量。需要注意的是,查詢向量和鍵向量要有相同的維度,值向量的維度可以相同,也可以不同,但一般也是相同的。

接下來計算每一個embedding的輸出,以第一個詞Thinking為例,參看圖2.4。用查詢向量q1跟鍵向量k1和k2分別做點積,得到112和96兩個數(shù)值。這也是為什么前文提到查詢向量和鍵向量的維度必須要一致,否則無法做點積。然后除以常數(shù)8,得到14和12兩個數(shù)值。這個常數(shù)8是鍵向量的維度的開方,鍵向量和查詢向量的維度都是64,開方后是8。做這個尺度上的調(diào)整目的是為了易于訓練。然后把14和12丟到softmax函數(shù)中,得到一組加和為1的系數(shù)權(quán)重,算出來是大約是0.88和0.12。將0.88和0.12對兩個值向量v1和v2做加權(quán)求和,就得到了Thinking的輸出向量z1。類似的,可以算出Machines的輸出z2。如果一句話中包含更多的詞,也是相同的計算方法。

通過這樣一系列的計算,可以看到,現(xiàn)在每個詞的輸出向量z都包含了其他詞的信息,每個詞都不再是孤立的了。而且每個位置中,詞與詞的相關(guān)程度,可以通過softmax輸出的權(quán)重進行分析。如圖2.5所示,這是某一次計算的權(quán)重,其中線條顏色的深淺反映了權(quán)重的大小,可以看到it中權(quán)重最大的兩個詞是The和animal,表示it跟這兩個詞關(guān)聯(lián)最大。這就是attention的含義,輸出跟哪個詞關(guān)聯(lián)比較強,就放比較多的注意力在上面。

上面我們把每一步計算都拆開了看,實際計算的時候,可以通過矩陣來計算,如圖2.6所示。

講完了attention,再來講Multi-Head。對于同一組輸入embedding,我們可以并行做若干組上面的操作,例如,我們可以進行8組這樣的運算,每一組都有WQ,WK,WV矩陣,并且不同組的矩陣也不相同。這樣最終會計算出8組輸出,我們把8組的輸出連接起來,并且乘以矩陣WO做一次線性變換得到輸出,WO也是隨機初始化,通過訓練得到,計算過程如圖2.7所示。這樣的好處,一是多個組可以并行計算,二是不同的組可以捕獲不同的子空間的信息。

到這里就把Transformer的結(jié)構(gòu)講完了,同樣都是做NLP任務(wù),我們來和RNN做個對比。圖2.8是個最基本的RNN結(jié)構(gòu),還有計算公式。當計算隱向量h4時,用到了輸入x4,和上一步算出來的隱向量h3,h3包含了前面所有節(jié)點的信息。h4中包含最多的信息是當前的輸入x4,越往前的輸入,隨著距離的增加,信息衰減得越多。對于每一個輸出隱向量h都是如此,包含信息最多得是當前的輸入,隨著距離拉遠,包含前面輸入的信息越來越少。但是Transformer這個結(jié)構(gòu)就不存在這個問題,不管當前詞和其他詞的空間距離有多遠,包含其他詞的信息不取決于距離,而是取決于兩者的相關(guān)性,這是Transformer的第一個優(yōu)勢。第二個優(yōu)勢在于,對于Transformer來說,在對當前詞進行計算的時候,不僅可以用到前面的詞,也可以用到后面的詞。而RNN只能用到前面的詞,這并不是個嚴重的問題,因為這可以通過雙向RNN來解決。第三點,RNN是一個順序的結(jié)構(gòu),必須要一步一步地計算,只有計算出h1,才能計算h2,再計算h3,隱向量無法同時并行計算,導致RNN的計算效率不高,這是RNN的固有結(jié)構(gòu)所造成的,之前有一些工作就是在研究如何對RNN的計算并行化。通過前文的介紹,可以看到Transformer不存在這個問題。通過這里的比較,可以看到Transformer相對于RNN有巨大的優(yōu)勢。

RNN的結(jié)構(gòu)包含了序列的時序信息,而Transformer卻完全把時序信息給丟掉了。為了解決時序的問題,Transformer的作者用了一個絕妙的辦法,這就是我在前文提到的位置編碼(Positional Encoding)。位置編碼是和word embedding同樣維度的向量,將位置embedding和詞embedding加在一起,作為輸入embedding,如圖2.9所示。位置編碼可以通過學習得到,也可以通過設(shè)置一個跟位置或者時序相關(guān)的函數(shù)得到,比如設(shè)置一個正弦或者余弦函數(shù),這里不再多說。

把圖2.1的結(jié)構(gòu)作為一個基本單元,把N個這樣的基本單元順序連起來,就是BERT的算法模型,如圖2.10所示。從前面的描述中可以看到,當輸入有多少個embedding,那么輸出也就有相同數(shù)量的embedding,可以采用和RNN采用相同的叫法,把輸出叫做隱向量。在做具體NLP任務(wù)的時候,只需要從中取對應的隱向量作為輸出即可。

BERT

在介紹BERT之前,我們先看看另外一套方案。在第一部分說過,BERT并不是第一個提出預訓練加微調(diào)的方案,此前還有一套方案叫GPT,這也是BERT重點對比的方案,文章在這,Improving Language Understanding by Generative Pre-Training(hs3-us-west-2.amazonaws.com/)。GPT的模型結(jié)構(gòu)和BERT是相同的,都是圖2.10的結(jié)構(gòu),只是BERT的模型規(guī)模更加龐大。GPT是這么預訓練的,在一個8億單詞的語料庫上做訓練,給出前文,不斷地預測下一個單詞。比如這句話,Winter is coming,當給出第一個詞Winter之后,預測下一個詞is,之后再預測下一個詞coming。不需要標注數(shù)據(jù),通過這種無監(jiān)督訓練的方式,得到一個預訓練模型。

我們再來看看BERT有什么不同。BERT來自于Bidirectional Encoder Representations from Transformers首字母縮寫,這里提到了一個雙向(Bidirectional)的概念。BERT在一個33億單詞的語料庫上做預訓練,語料庫就要比GPT大了幾倍。預訓練包括了兩個任務(wù),第一個任務(wù)是隨機地扣掉15%的單詞,用一個掩碼MASK代替,讓模型去猜測這個單詞;第二個任務(wù)是,每個訓練樣本是一個上下句,有50%的樣本,下句和上句是真實的,另外50%的樣本,下句和上句是無關(guān)的,模型需要判斷兩句的關(guān)系。這兩個任務(wù)各有一個loss,將這兩個loss加起來作為總的loss進行優(yōu)化。下面兩行是一個小栗子,用括號標注的是扣掉的詞,用[MASK]來代替。

正樣本:我[MASK](是)個算法工程師,我服務(wù)于WiFi萬能鑰匙這家[MASK](公司)。

負樣本:我[MASK](是)個算法工程師,今天[MASK](股票)又跌了。

我們來對比下GPT和BERT兩種預訓練方式的優(yōu)劣。GPT在預測詞的時候,只預測下一個詞,因此只能用到上文的信息,無法利用到下文的信息。而BERT是預測文中扣掉的詞,可以充分利用到上下文的信息,這使得模型有更強的表達能力,這也是BERT中Bidirectional的含義。在一些NLP任務(wù)中需要判斷句子關(guān)系,比如判斷兩句話是否有相同的含義。BERT有了第二個任務(wù),就能夠很好的捕捉句子之間的關(guān)系。圖3.1是BERT原文中對另外兩種方法的預訓練對比,包括GPT和ELMo。ELMo采用的還是LSTM,這里我們不多講ELMo。這里會有讀者困惑,這里的結(jié)構(gòu)圖怎么跟圖2.10不一樣?如果熟悉LSTM的同學,看到最右邊的ELMo,就會知道那些水平相連的LSTM其實只是一個LSTM單元。左邊的BERT和GPT也是一樣,水平方向的Trm表示的是同一個單元,圖中那些復雜的連線表示的是詞與詞之間的依賴關(guān)系,BERT中的依賴關(guān)系既有前文又有后文,而GPT的依賴關(guān)系只有前文。

講完了這兩個任務(wù),我們再來看看,如何表達這么復雜的一個訓練樣本,讓計算機能夠明白。圖3.2表示“my dog is cute, he likes playing.”的輸入形式。每個符號的輸入由3部分構(gòu)成,一個是詞本身的embedding;第二個是表示上下句的embedding,如果是上句,就用A embedding,如果是下句,就用B embedding;最后,根據(jù)Transformer模型的特點,還要加上位置embedding,這里的位置embedding是通過學習的方式得到的,BERT設(shè)計一個樣本最多支持512個位置;將3個embedding相加,作為輸入。需要注意的是,在每個句子的開頭,需要加一個Classification(CLS)符號,后文中會進行介紹。

完成預訓練之后,就要針對特定任務(wù)就行微調(diào)了,這里描述一下論文中的4個例子,看圖3.4。首先說下分類任務(wù),分類任務(wù)包括對單句子的分類任務(wù),比如判斷電影評論是喜歡還是討厭;多句子分類,比如判斷兩句話是否表示相同的含義。圖3.4(a)(b)是對這類任務(wù)的一個示例,左邊表示兩個句子的分類,右邊是單句子分類。在輸出的隱向量中,取出CLS對應的向量C,加一層網(wǎng)絡(luò)W,并丟給softmax進行分類,得到預測結(jié)果P,計算過程如圖3.3中的計算公式。在特定任務(wù)數(shù)據(jù)集中對Transformer模型的所有參數(shù)和網(wǎng)絡(luò)W共同訓練,直到收斂。新增加的網(wǎng)絡(luò)W是HxK維,H表示隱向量的維度,K表示分類數(shù)量,W的參數(shù)數(shù)量相比預訓練模型的參數(shù)少得可憐。

image-20210428102806542
圖3.4

對于問答任務(wù),如圖3.4(c),以SQuAD v1.1為例,給出一個問題Question,并且給出一個段落Paragraph,然后從段落中標出答案的具體位置。需要學習一個開始向量S,維度和輸出隱向量維度相同,然后和所有的隱向量做點積,取值最大的詞作為開始位置;另外再學一個結(jié)束向量E,做同樣的運算,得到結(jié)束位置。附加一個條件,結(jié)束位置一定要大于開始位置。最后再看NER任務(wù),實體命名識別,比如給出一句話,對每個詞進行標注,判斷屬于人名,地名,機構(gòu)名,還是其他。如圖3.4(d)所示,加一層分類網(wǎng)絡(luò),對每個輸出隱向量都做一次判斷。可以看到,這些任務(wù),都只需要新增少量的參數(shù),然后在特定數(shù)據(jù)集上進行訓練即可。從實驗結(jié)果來看,即便是很小的數(shù)據(jù)集,也能取得不錯的效果。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容