三大特徵提取器(RNN/CNN/Transformer)
目錄
- 三大特徵提取器 - RNN、CNN和Transformer
- 簡介
- 迴圈神經網路RNN
- 傳統RNN
- 長短期記憶網路(LSTM)
- 卷積神經網路CNN
- NLP界CNN模型的進化史
- Transformer
- 3.1 多頭注意力機制(Multi-Head Attention)
- 位置編碼(Positional Encoding)
- 殘差模組(Residual Block)
- Transformer小結
三大特徵提取器 - RNN、CNN和Transformer
簡介
近年來,深度學習在各個NLP任務中都取得了SOTA結果。這一節,我們先了解一下現階段在自然語言處理領域最常用的特徵抽取結構。
本文部分參考張俊林老師的文章《放棄幻想,全面擁抱Transformer:自然語言處理三大特徵抽取器(CNN/RNN/TF)比較》(寫的非常好,學NLP必看博文),這裡一方面對博文進行一定程度上的總結,並加上一些個人理解。
在深度學習流行起來之後,隨著我們的網路越做越深,我們的神經網路模型越來越像一個黑箱,我們只要餵給它資料,我們的模型就能夠根據我們的給予的目標,自動學習抽取對於該任務最有利的特徵(這點在CV中更為明顯,比如在卷積神經網路的不同層能夠輸出影象中不同層面上的細節特徵),從而實現了著名的“端到端”模型。在這裡,我們可以把我們的CNN、RNN以及Transformer看作抽取資料特徵的特徵抽取器。下面,本文將為大家簡單介紹RNN、CNN及NLP新寵Transformer的基本結構及其優缺點。
迴圈神經網路RNN
傳統RNN
在2018年以前,在NLP各個子領域的State of Art的結果都是RNN(此處包含LSTM、GRU等變種)得到的。為什麼RNN在NLP領域能夠有如此廣泛的應用?我們知道如果將全連線網路運用到NLP任務上,其會面臨三個主要問題:
- 對於不同的輸入樣本,輸入和輸出可能有不同的長度,因此輸入層和輸出層的神經元數量無法固定。
- 從輸入文字的不同位置學到的同一特徵無法共享。
- 模型中的引數太多,計算量太大。
為了解決上述問題,我們就有了熟悉的RNN網路結構。其通過掃描資料輸入的方式,使得每一個時間步的所有網路引數是共享的,且每個時間步不僅會接收當前時刻的輸入,同時會接收上一個時刻的輸出,從而使得其能夠成功利用過去輸入的資訊來輔助當前時刻的判斷。
但是,原始的RNN也存在問題,它採取線性序列結構不斷從前往後收集輸入資訊,但這種線性序列結構不擅長捕獲文字中的長期依賴關係,如下圖所示。這主要是因為反向傳播路徑太長,從而容易導致嚴重的梯度消失或梯度爆炸問題。
長短期記憶網路(LSTM)
傳統RNN的做法是將的所有知識全部提取出來,不作任何處理的輸入到下一個時間步進行迭代。就像參加考試一樣,如果希望事先把書本上的所有知識都記住,到了考試的時候,早期的知識恐怕已經被近期的知識完全覆蓋了,提取不到長遠時間步的資訊是很正常的。而人類是這樣做的嗎?顯然不是的,我們通常的做法是對知識有一個理性性判斷,重要的知識給予更高的權重,重點記憶,不那麼重要的可能沒多久就忘了,這樣,才能在面對考試的時候有較好的發揮。
在我看來,LSTM的結構更類似於人類對於知識的記憶方式。理解LSTM的關鍵就在於理解兩個狀態\(c^{t}\)和\(a^t\)和內部的三個門機制:
圖中我們可以看見,LSTM Cell在每個時間步接收上個時間步的輸入有兩個,傳給下一個時間步的輸出也有兩個。通常,我們將\(c(t)\)看作全域性資訊,\(a^t\)看作全域性資訊對下一個Cell影響的隱藏狀態。
遺忘門、輸入門(圖中的update gate)和輸出門分別都是一個啟用函式為sigmoid的小型單層神經網路。由於sigmoid在\((0, 1)\)範圍內的取值,有效的用於判斷是保留還是“遺忘”資訊(乘以接近1的值表示保留,乘以接近0的值表示遺忘),為我們提供了資訊選擇性傳輸的能力。這樣,我們就很好理解門在LSTM是怎樣工作的了:
- 遺忘門有兩個輸入:當前時間步的輸入\(x^t\)以及上一層輸出的隱藏狀態\(a^{t-1}\),遺忘門通過這兩個輸入訓練出一個門函式,注意這個門函式的輸出是在\((0, 1)\)之間的,將其與上一層輸出的全域性資訊\(c^{t-1}\)相乘,表示全域性資訊被選擇部分遺忘。
- 對於輸入門,我們那同樣訓練出一個門函式,與此同時,將接收到的\(a^{t-1}\)和\(x^t\)一起通過一個啟用函式為tanh的小型神經網路,這一部分與傳統RNN無異了,就是將上一時刻得到的資訊與該時刻得到的資訊進行整合。將整合資訊與門函式的輸出相乘,相當於同樣選擇有保留的提取新資訊,並將其直接加在全域性資訊中去。
- 對於輸出門,同樣的訓練出一個門函式,與此同時,將新的隱藏狀態\(c^t\)通過一個簡單的tanh函式(僅僅是啟用函式)後與門函式的輸出相乘,則可以得到該時刻全域性資訊對下一個Cell影響的隱藏狀態\(a^t\)
這樣看下來,是不是覺得LSTM已經十分"智慧"了呢?但實際上,LSTM還是有其侷限性:時序性的結構一方面使其很難具備高效的平行計算能力(當前狀態的計算不僅要依賴當前的輸入,還要依賴上一個狀態的輸出),另一方面使得整個LSTM模型(包括其他的RNN模型,如GRU)總體上更類似於一個馬爾可夫決策過程,較難以提取全域性資訊。
關於GRU的結構我這裡就不細講了,在參考文獻中有很多相關資料,大家想了解的可以去看看,簡單來說,GRU可以看作一個LSTM的簡化版本,其將\(a^t\)與\(c^t\)兩個變數整合在一起,且講遺忘門和輸入門整合為更新門,輸出門變更為重製門,大體思路沒有太大變化。兩者之間的效能往往差別不大,但GRU相對來說引數量更少。收斂速度更快。對於較少的資料集我建議使用GRU就已經足夠了,對於較大的資料集,可以試試有較多引數量的LSTM有沒有令人意外的效果。
卷積神經網路CNN
CNN是計算機視覺領域的重大突破,也是目前用於處理CV任務模型的核心。CNN同樣適用於NLP任務中的特徵提取,但其使用場景與RNN略有不同,這部分我會多寫一點,因為關於CNN在NLP任務中的應用大家相對來說應該都沒那麼瞭解。
關於二維卷積核的運算如下圖所示,我就不贅述了。
從資料結構上來看,CV任務中的輸入資料為影象畫素矩陣,其各個方向上的畫素點之間的相關性基本上是等同的。而NLP任務中的輸入資料通常為序列文字,假設句子長度為\(n\),我們詞向量的維度為\(d\),我們的輸入就成了一個\(n \times d\)的矩陣,顯然,該矩陣的行列“畫素”之間的相關性是不一樣的,矩陣的同一行為一個詞的向量表徵,而不同行表示不同詞。要讓卷積網路能夠正常的”讀“我們的文字,我們在NLP中就需要使用一維卷積。Kim在2014年首次將CNN用於NLP中的文字分類任務,其提出的網路結構如下圖所示:
可以看見,一維卷積與二維卷積不同的是,每一個卷積核的寬度與詞向量的維度\(d\)是相同的,以保證卷積核每次處理n個詞的完整詞向量,從上往下依次滑動卷積,這個過程中的輸出就成了我們需要的特徵向量。這就是CNN抽取特徵的過程。在卷積層之後通常接上Max Pooling層(用於抽取最顯著的特徵),用於對輸出的特徵向量進行降維提取操作,最後再接一層全連線層實現文字分類。
雖然傳統CNN經過簡單的改變之後可以成功的應用於NLP任務,且效果還不錯,但效果也僅僅是“不錯“而已,很多工還是處於完全被壓制的情況。這表明傳統的CNN在NLP領域中還是存在一些問題。
NLP界CNN模型的進化史
談到CNN在NLP界的進化,我們首先來看看Kim版CNN存在哪些問題。
- Kim版CNN實際上類似於一個k-gram模型(k即卷積核的window,表示每次卷積的時候覆蓋多少單詞),對於一個單層的k-gram模型是難以捕捉到距離\(d \ge k\)的特徵的;
- 卷積層輸出的特徵向量是包含了位置資訊的(與卷積核的卷積順序有關),在卷積層之後接Max Pooling層(僅僅保留提取特徵中最大值)將導致特徵資訊中及其重要的位置編碼資訊丟失。
為了解決上述問題,研究者們採取了一系列方法對Kim版的CNN進行改進。
- 解決長遠距離的資訊提取的一個主要方法就是可以把網路做的更深一些,越深的卷積核將會有更大的感受野,從而捕獲更遠距離的特徵。
- 另外,我們也可以採用膨脹卷積(Dilated Convolution)的方式,也就是說我們的卷積視窗不再覆蓋連續區域,而是跳著覆蓋,這樣,同樣尺寸的卷積核我們就能提取到更遠距離的特徵了。當然這裡的空洞卷積與CV中的還是不一樣的,其僅僅在詞間存在空洞,在詞向量內部是不存在空洞的。在蘇神的部落格裡對比了同樣\(window=3\)的卷積核,膨脹卷積和普通卷積在三層網路時每個神經元的感受野大小,如下圖所示,可以看見膨脹卷積的神經元感受野的範圍是大大增加的。
- 為了防止文字中的位置資訊丟失,NLP領域裡的CNN的發展趨勢是拋棄Pooling層,靠全卷積層來疊加網路深度,並且在輸入部分加入位置編碼,人工將單詞的位置特徵加入到對應的詞向量中。位置編碼的方式可以採用《Attention is All You Need》中的方案,在下面介紹Transformer的時候再詳細介紹
- 我們知道在CV領域中,網路做深之後將存在一系列問題,因此有了殘差網路。在NLP中同樣可以使用殘差網路,解決梯度消失問題,解決梯度消失問題的本質是能夠加速資訊流動,使簡單的資訊傳輸可以有更簡單的路徑,從而使得網路做深的同時,能夠保證良好的效能。
- 啟用函式開始採用GLU(Gated Linear Unit),如下圖所示,左右兩個卷積核的尺寸完全一樣,但是權值引數不共享,然後其中一個通過一個sigmoid函式,另一個不通過,將兩者相乘。是不是感覺有點熟悉,這其實與LSTM中的門機制是相同的效果,該啟用函式可以自行控制輸出的特徵的強弱大小。
- 在蘇神的部落格中還學到另一個應用,就是可以用\(window=1\)的一維卷積對人工合成的詞嵌入表徵進行特徵壓縮,從而得到一個更有效的詞向量表徵方法。
在很多地方都看見CNN比較適用於文字分類的任務,事實上,從《Convolutional Sequence to Sequence Learning》、《Fast Reading Comprehension with ConvNets》等論文與實踐報告來看,CNN已經發展成為一種成熟的特徵提取器,並且,相比於RNN來說,CNN的視窗滑動完全沒有先後關係,不同卷積核之前也沒有相互影響,因此其具有非常高的並行自由度,這是其非常好的一個優點。
Transformer
Transformer是在論文《Attentnion is all you need》裡首次被提出的。
Transformer詳解推薦這篇文章:https://zhuanlan.zhihu.com/p/54356280
在介紹Transformer之前,我們先來看看Encoder-Decoder框架。現階段的深度學習模型,我們通常都將其看作黑箱,而Encoder-Decoder框架則是將這個黑箱分為兩個部分,一部分做編碼,另一部分做解碼。
在不同的NLP任務中,Encoder框架及Decoder框架均是由多個單獨的特徵提取器堆疊而成,比如說我們之前提到的LSTM結構或CNN結構。由最初的one-hot向量通過Encoder框架,我們將得到一個矩陣(或是一個向量),這就可以看作其對輸入序列的一個編碼。而對於Decoder結構就比較靈活餓了,我們可以根據任務的不同,對我們得到的“特徵”矩陣或“特徵”向量進行解碼,輸出為我們任務需要的輸出結果。因此,對於不同的任務,如果我們堆疊的特徵抽取器能夠提取到更好的特徵,那麼理論上來說,在所有的NLP任務中我們都能夠得到更好的表現。
在2018年穀歌推出BERT,重新整理各項記錄,引爆了整個NLP界,其取得成功的一個關鍵因素是新的特徵提取結構:Transformer的強大作用。
Transformer結構是在論文《Attention is All You Need》中提出的的模型,如上圖所示。圖中紅框內為Encoder框架,黃框內為Decoder框架,其均是由多個Transformer Block堆疊而成的。這裡的Transformer Block就代替了我們之前提到的LSTM和CNN結構作為了我們的特徵提取器,也是其最關鍵的部分。更詳細的示意圖如下圖所示。我們可以發現,編碼器中的Transformer與解碼器中的Transformer是有略微區別的,但我們通常使用的特徵提取結構(包括Bert)主要是Encoder中的Transformer,那麼我們這裡主要理解一下Transformer在Encoder中是怎麼工作的。
由上圖可知,單個的Transformer Block主要由兩部分組成:多頭注意力機制(Multi-Head Attention)和前饋神經網路(Feed Forward)。
3.1 多頭注意力機制(Multi-Head Attention)
Multi-Head Attention模組結構如下圖所示:
這裡,我們就可以明白為什麼這一部分被稱為Multi-Head了,因為其本身就是由\(h\)個子模組Scaled Dot-Product Attention堆疊而成的,該模組也被稱為Self-Attention模組。關於整個Multi-Head Attention,主要有一下幾個關鍵點需要理解:
- Linear可以看作一個沒有啟用函式的全連線層,其各自維護了一個線性對映矩陣(神經網路的本質就是矩陣相乘)
- 對於每一個Self-Attention,均有獨立維護的三個線性對映矩陣\(W^V_i\)、\(W^K_i\)及\(W^Q_i\)(不同Self-Attention模組之間的權值不共享),通過將輸入的矩陣\(X\)與三個對映矩陣相乘,得到Self-Attetnion的三個輸入Queries、Keys和Values。這V, Q, K三個矩陣的輸入\(X\)是完全一樣的(均為輸入句子的Input Embedding + Positional Encoding或是上一層Transformer的輸出),這一點從整個的Encoder模型中也可以看出來。
- 在論文中,作者對於8個Self-Attention的輸出,進行簡單的拼接,並通過與一個對映矩陣\(W^O\)與其相乘(目的是對輸出矩陣進行壓縮),從而得到整個Multi-Head Attention的輸出
在Multi-Head Attention中,最關鍵的部分就是Self-Attention部分了,這也是整個模型的核心配方,我們將其展開,如下圖所示。
我們之前已經提到過,Self-Attention的輸入僅僅是矩陣\(X\)的三個線性對映。那麼Self-Attention內部的運算具有什麼樣的含義呢?我們從單個詞編碼的過程慢慢理解:
- 首先,我們對於輸入單詞向量\(X\)生成三個對應的向量: Query, Key 和 Value。注意這三個向量相比於向量\(X\)要小的多(論文中\(X\)的長度是512,三個向量的長度為64,這只是一種基於架構上的選擇,因為論文中的Multi-Head Attention有8個Self-Attention模組,8個Self-Attention的輸出要拼接,將其恢復成長度為512的向量),這一個部分是對每個單詞獨立操作的
- 用Queries和Keys的點積計算所有單詞相對於當前詞(圖中為Thinking)的得分Score,該分數決定在編碼單詞“Thinking”時其他單詞給予了多少貢獻
- 將Score除以向量維度(64)的平方根(保證Score在一個較小的範圍,否則softmax的結果非零即1了),再對其進行Softmax(將所有單詞的分數進行歸一化,使得所有單詞為正值且和為1)。這樣對於每個單詞都會獲得所有單詞對該單詞編碼的貢獻分數,當然當前單詞將獲得最大分數,但也將會關注其他單詞的貢獻大小
- 對於得到的Softmax分數,我們將其乘以每一個對應的Value向量(弱化了softmax分數較低單詞的影響,有點類似於之前的sigmoid門函式的思想)
- 對所得的所有加權向量求和,即得到Self-Attention對於當前詞”Thinking“的輸出
其實仔細思考一下就可以發現,Self-Attention與CNN是十分相似的。CNN通過簡單的卷積運算提取特徵,雖然有Dilated Convolution以及增加深度等方式來增大感受野,但是其本質上是一個n-gram模型。而在Self-Attention中,\(W^Q\), \(W^K\), \(W^V\)不也能看作三個卷積核嗎,但是其通過一種更加巧妙的方式將卷積運算的結果進行整合,實現了直觀上所謂的”注意力“,從而使得每一個詞的編碼結果均是句子中所有詞的共同作用結果,其本質上是一個超大的詞袋模型(包括句子中所有的詞)。顯然,上述過程可以用以下的矩陣形式進行平行計算:
\[Attention(Q, K, V) = softmax(\frac{QK^T}{\sqrt{d_k}})V\]
其中,Q, V, K分別表示輸入句子的Queries, Keys, Values矩陣,矩陣的每一行為每一個詞對應的向量Query, Key, Value向量,\(d_k\)表示向量長度。因此,Transformer同樣也具有十分高效的平行計算能力。
我們再回到Multi-Head Attention,我們將獨立維護的8個Self-Attention的輸出進行簡單的拼接,通過一個先行對映層,就得到了單個多頭注意力的輸出。其整個過程可以總結為下面這個示意圖:
位置編碼(Positional Encoding)
我們之前提到過,由於RNN的時序性結構,所以天然就具備位置編碼資訊。CNN本身其實也能提取一定位置資訊,但多層疊加之後,位置資訊將減弱,位置編碼可以看作是一種輔助手段。Transformer的每一個詞的編碼過程使得其基本不具備任何的位置資訊(將詞序打亂之後並不會改變Self-Attention的計算結果),因此位置向量在這裡是必須的,使其能夠更好的表達詞與詞之間的距離。構造位置編碼的公式如下所示:
\[\begin{cases} PE_{2i}(p)=sin(p/10000^{2i/d_{pos}}) \\ PE_{2i+1}(p)=cos(p/10000^{2i/d_{pos}}) \end{cases}\]
如果詞嵌入的長度\(d_{pos}\),則我們需要構造一個長度同樣為\(d_{pos}\)的位置編碼向量\(PE\)。其中\(p\)表示詞的位置,\(PE_i(p)\)表示第p個詞位置向量中的第i個元素的值,然後將詞向量與位置向量直接相加。該位置編碼不僅僅包含了絕對位置資訊,由\(sin(\alpha + \beta) = sin \alpha cos \beta + cos \alpha sin \beta\)以及\(cos(\alpha + \beta) = cos \alpha cos \beta - sin \alpha sin \beta\),這意味著我們可以\(p+k\)的位置向量可表示為位置\(p\)位置向量的線性變換,使得相對位置資訊也得到了表達。Transformer論文中提到過他們用該方式得到的位置編碼向量與訓練得到的位置編碼向量效果是十分接近的。
殘差模組(Residual Block)
我們之前說到Self-Attention與CNN的相似性。這裡的殘差運算同樣是借鑑了CNN中的思想,其原理基本是一樣的,我就不贅述了。在殘差連線之後,還需要進行層歸一化操作,其具體過程與Layer Normalization一致。
Transformer小結
到這裡,整個Transformer的結構基本講述完畢了。關於其相與RNN和CNN的效能比較,張俊林老師的文章裡有詳細的資料說明,我僅附上簡單的總結:
- 從語義特徵提取能力:Transformer顯著超過RNN和CNN,RNN和CNN兩者能力差不太多。
- 長距離特徵捕獲能力:CNN極為顯著地弱於RNN和Transformer,Transformer微弱優於RNN模型,但在比較遠的距離上(主語謂語距離大於13),RNN微弱優於Transformer,所以綜合看,可以認為Transformer和RNN在這方面能力差不太多,而CNN則顯著弱於前兩者。這部分我們之前也提到過,CNN提取長距離特徵的能力收到其卷積核感受野的限制,實驗證明,增大卷積核的尺寸,增加網路深度,可以增加CNN的長距離特徵捕獲能力。而對於Transformer來說,其長距離特徵捕獲能力主要受到Multi-Head數量的影響,Multi-Head的數量越多,Transformer的長距離特徵捕獲能力越強
- 任務綜合特徵抽取能力:通常,機器翻譯任務是對NLP各項處理能力綜合要求最高的任務之一,要想獲得高質量的翻譯結果,對於兩種語言的詞法,句法,語義,上下文處理能力,長距離特徵捕獲等方面的效能要求都是很高的。從綜合特徵抽取能力角度衡量,Transformer顯著強於RNN和CNN,而RNN和CNN的表現差不太多。
- 平行計算能力:對於平行計算能力,上文很多地方都提到過,平行計算是RNN的嚴重缺陷,而Transformer和CNN差不多。
由於平常科研任務也比較重,程式碼暫時沒有時間上傳,等釋出序列標註以及文字分類等文章的時候程式碼會同步上傳到Github,RNN/CNN/Transformer的程式碼也會包含在其中。
參考資料
https://zhuanlan.zhihu.com/p/54743941
http://www.ai-start.com/dl2017/html/lesson5-week1.html#header-n194
https://zhuanlan.zhihu.com/p/46327831
https://zhuanlan.zhihu.com/p/55386469
https://kexue.fm/archives/5409
https://zhuanlan.zhihu.com/p/54356280
http://jalammar.github.io/illustrated-transformer/
https://kexue.fm/archives/