語言模型(五)—— Seq2Seq、Attention、Transformer學習筆記
按:三個月前的一篇筆記,先發出來,後面還會有第二次學習的筆記,兩者結合起來看,更加爽口。
本篇筆記5000餘字,可細嚼,亦可跳閱。
機器翻譯
本篇筆記中要開始介紹的Encoder-Decoder模型最初是由機器翻譯這一任務中脫產而來,所以先從此入手。
機器翻譯的通俗解釋就是由機器把一種語言翻譯成另外一種語言,它的發展大概經歷了三大階段:基於規則的方法、統計機器翻譯和目前流行的神經網路機器翻譯。
翻譯方法(階段) | 特點 | 劣勢 |
---|---|---|
基於規則的翻譯 | 翻譯知識來自於人類專家;準確率較高 | 成本較高;週期較長;規則易衝突; |
統計機器翻譯 | 基於語料庫的方法; | 需要大量語料訓練,否則易出現資料稀疏的問題;沒有專家規則,準確率不高; |
神經網路機器翻譯 | 基於Encoder-Decoder框架;準確率比較高; | 人工訓練成本相對比較高 |
那麼神經網路訓練出來的機器翻譯模型為何就能夠大大地提高翻譯的準確性呢?
讓我們一步步往下看:
Encoder-Decoder框架
上圖給我們簡單的展示了Encoder-Decoder框架的基本形態,其實不難理解,類似於無線訊號的調製與解調,編碼-解碼的模型也是將一個輸入進行編碼-解碼之後得到一個輸出,只不過應用在機器翻譯領域的話,輸入可能是一種語言,輸出又是另外一種語言。這樣也就完成了一次翻譯的過程。
Seq2Seq
Seq2Seq的全稱是sequence to sequence, 基礎的seq2seq = Encoder + Decoder + 語義編碼c (連線兩者的中間狀態向量,可以理解成兩種語言之間的聯絡規律)。Encoder 中將可變長度的訊號序列變為固定長度的向量表達,其實本質也就是進行了特徵壓縮;Decoder 將這個固定長度的向量變成可變長度的目標訊號序列;Encoder、Decoder可以是CNN、RNN、Transformer三種結構,Encoder和Decoder可以是相同的結構,也可以是不同的結構。
相同結構,即都是RNN,或者CNN,或者都是Transformer;不同結構,比如一個是RNN,另一個CNN(例如:Image Caption)。
seq2seq中Encoder-Decoder框架如下:
我們以一個簡單的中英文翻譯來舉例:在Encoder中,待翻譯的原文“歡迎來北京
”先是被分詞(tokenization)成“歡迎
/來
/北京
”,然後我們還需要將這些詞轉換為詞向量v(i)(即Embedding),然後與上一時刻的隱狀態h(i-1)按照時間順序進行輸入,每一時刻輸出一個隱狀態h(i),這裡用函式f表達RNN隱藏層的變換h(i)=f(v(i),h(i-1))。假設有t個詞,最終通過Encoder自定義函式q將各時刻的隱狀態變換為向量c=q(h(0),…,h(t)),我們認為c已經提取了輸入句子的含義,並將其傳入給Decoder部分進行解碼。在Decoder部分,每一時刻的輸入都是之前輸出的c和前一時刻解碼輸出的s(i-1),以及前一時刻預測出的詞向量E(i-1),那麼我們是如何定義開始和結束的呢,當預測第一個詞的時候,我們的輸入詞向量是_SOS,解碼一直往前,直到解析出 _EOS,表示解碼結束。這裡用函式來表示解碼部分的變換:s(i) = g(c,s(i-1),E(i-1))。
整個過程如下圖所示:
**有一點是需要特別說明的:**準確來說,上圖反映的是預測階段的Encoder-Decoder過程,真正模型訓練過程中,在Decoder階段,每一步解碼過程的輸入並不是上一步的輸出,而是我們知道的那個標準答案,我們只在最開始的時候輸入一個開始字元SOS,後面每一步的輸入都是上一步的樣本真實值y,而不是預測值y’,整個過程以輸出結束字元EOS為結束標誌,如下圖所示:
這種訓練中傳入標準答案進行監督糾正、加快收斂的方式我們稱之為“Teacher Forcing”。與之對應的是之前我們展示的方式:下一時刻的輸入是上一時刻的輸出,這種我們也可以叫它“Free Running”,那麼我們為何要用Teacher Forcing來進行訓練呢?
因為在Free Running中,本質上每一步的輸出有一種盲猜的感覺,如果不加以糾正反饋,就可能出現一步錯步步錯的結果,這顯然不是我們想要看見的。雖然Free Running將每一步的最優解輸出作為了下一步的輸入,但可能存在一個問題,那就是每一步的區域性最優並不一定引發最終結果上的全域性最優。小小的誤差可能導致最後的“誤差爆炸”。
如果在預測階段,我們不得不面對這種“誤差爆炸”的情況,我們可以採用一種叫“Beam Search”的方法從一定程度上緩解這種問題,Beam Search簡單來說就是設定一個n值,往後每計算一步都會取最優解排序的top-n,然後繼續在這n條分支上繼續前進,直到最後得出最終的top-n。這一塊我們另外單獨來學習。
Teacher Forcing其實也並不是完美的,它也可能造成模型的泛化能力不強,於是我們可以採取一種折中的方法來訓練模型——計劃取樣。一句話來說就是以一定概率p使用Teacher Forcing,有點dropout的意思了。
上面我們已經瞭解了seq2seq模型的基本結構及原理,由於RNN的結構和中間語義向量的難解釋性,它可以做到支援多輸入多輸出且輸入輸出長度不要求一致。但同時我們也應該看到:Encoder和Decoder之間的唯一聯絡就是一個固定長度的語義向量C,即Encoder要將整個序列的資訊壓縮排一個固定長度的向量中去。因為語義向量無法完全表示整個序列的資訊,而且之前先輸入的內容帶有的資訊會被後輸入的資訊稀釋掉,輸入的句子越長,輸入序列越長,這個現象就越嚴重。(這點上有點類似與LSTM當時要解決RNN的梯度消失的問題的感覺)這樣Decoder時,沒有獲得輸入序列足夠的資訊, 因此Deocder的準確度自然會降低。
基於這樣的不足,人們提出了基於Attention的Encoder-Decoder模型。在Decoder中,使用了Attention機制,不要求Encoder將所有輸入資訊都編碼進一個固定長度的向量中。
Attention 機制
Attention的核心就是加權重。
Encoder-Decoder中加入Attention機制:讓Encoder編碼出的c向量跟Decoder解碼過程中的每一個輸出進行加權運算,在Decoder的每一個過程中調整權重取到不一樣的 c 向量。
還是以之前翻譯“歡迎來北京”為例,當翻譯到第一個詞“welcome”的時候,網路需要著重去看“歡迎”這個詞。這就是所謂的Attention。但具體在計算時是怎麼體現的呢?
放兩張圖,原本在這寫了一大段,發現寫的沒人家好,直接把人家的搬過來了:
經典的Attention模型架構:
通過為每個輸出位置計算一個context vector,使得每個位置的輸出可以關注到輸入中最相關的部分,效果比傳統模型更好。
補充說明:其中a(ij)就是attention的權重,是j=1,2,3…,T時刻的一個概率分佈,其實是通過softmax函式進行計算得出的:
通俗地解釋一下這件事:
原先翻譯“北京歡迎你” 的時候,相當於每個詞給的權重一樣,比如都是0.33,現在加入attention之後,當我翻譯“北京”的時候,我會通過一種認定方式去認定我要輸出的“Beijing”與輸入序列的“北京”相關聯程度較大,這樣我就會給它給多的權重,可能權重就調整為:<北京,0.9>、<歡迎,0.05>、<你,0.05>,這樣我們就更加聚焦我們要翻譯的點,“北京”一詞到翻譯成“Beijing”時保留的資訊就更多了,翻譯的準確性也就提高了。同時在翻譯“北京”時,對應輸出的中間語義表徵向量是c1,以往是大家統一生成一個c,所有的語義資訊都被雜糅進了這一個向量中,特徵的個性得不到表達。
那麼剛剛我們提及的這個“認定方式”,又是什麼呢?網路是怎麼知道誰和誰關聯程度比較大的呢?其實我們的網路引數初始化都是隨機值,其實這個值還是通過一定規則前向傳播反向傳播學習出來的,那麼我們就要定一個規則(也可理解為目標函式)來作為我們的衡量指標,在這裡這個規則就是上面提及的相關性計算,比如點積,或者其他距離,我們稱之為e距離,通過計算Encoder的輸出h(j)與Decoder上一時刻的隱態s(i-1)之間的e距離,再通過softmax函式將其轉化為我們要的權重,這樣我們要Attention的依據就出來了。
感覺權重與殘差的思想一直就沒有離開過。
引申:Attention模型提出後,出現了許多Attention模型的變體,包括——
- Soft Attention、Global Attention、動態 Attention:
三者是同一種Attention,即上述結構,對輸入的每個位置都計算對齊概率- Hard Attention:
同樣對每個位置計算對齊概率,但只將最高的一個置為1,其餘置為0- local Attention:
只計算一個視窗內的位置的對齊概率,減少計算量
回顧整個Attention機制,不難發現它的內部還是用了大量的RNN模型,那麼我們就會想,都Attention了,不用RNN行不行呢,我就只用Attention。答案是可以的,它就是Transformer。
Transformer
Transformer利用Self Attention 來捕捉時序類的特徵,用Multi-head Attention 來增強資料處理的並行性,解決了RNN幾乎不可以並行處理的弊端。利用Feed-Forward前饋層,通過非線性變化來轉換資料特徵。Transformer用Attention機制代替了RNN搭建了整個模型框架。
說到對Transformer的理解,就不得不提到一篇文章:The Illustrated Transformer,這篇文章寫的很好,國內不少人將其翻譯轉發,以下內容部分也來自於該文章。
全域性視角
在Transformer中,我們仍然能夠看見他其實也是由傳統的Encoder-Decoder演化而來,還是以機器翻譯為例,大致的結構圖還是與之前一樣:
其中Encoders和Decoders 部分都是由6層Encoder或Decoder堆疊而成:
單看每一層Encoder和Decoder:
Encoder部分,輸入首先流進一個Self-Attention層(後面單獨討論),該層可以幫助編碼器在對特定單詞進行編碼時檢視輸入句子中的其他單詞(其實也就是相當於原先網路中的RNN,捕獲了時序類的特徵),該層的輸出被饋送到前饋神經網路(Feed Forward Neural Network),通過一些非線性的變換來轉換特徵(捕獲非線性特徵)。
注意,其實這裡有兩層全連線層:W2(Relu(W1x+b1))+b2,給模型提供非線效能力
Decoder部分,首先它具有和Encoder部分同樣的Self-Attention層和Feed Forward層,不同的是它在兩層之間加了一層Attention,這是一層普通的Attention層,和之前我們討論的原始Attention一樣,可以幫助解碼器將注意力集中在輸入語句的相關部分。
Self-Attention
對於機器翻譯中的指代問題,例如翻譯以下句子時“it”到底指的是什麼?
” The animal didn't cross the street because it was too tired
“
對機器來說怎麼讓它知道後面的“it”指代的是啥?這是一件不容易的事,Self-Attention機制就可以做到這件事,接下來我們就討論Self-Attention是怎麼工作的。
Attention的目的是要算出一個context vector,原始的Attention模型使用①輸出當前位置的隱狀態與②輸入所有位置的隱狀態計算匹配程度,並根據匹配程度對③輸入所有位置的隱狀態進行加權求和得到context vector。
在Self-Attention中,輸入輸出都是句子本身,對原始Attention做一個轉化——
把當前位置看成輸出,其對映後的隱狀態記為query(上面的①)
把當前位置看成輸入,其對映後的隱狀態記為key(上面的②)
把當前位置看成輸入,其用於加權求和的隱狀態記為value(上面的③)
藉助上面的理解,我們再來看Self-Attention的基本模型圖:
上面的模型是這樣運作的:
第一步,我們需要計算出三個向量(query/key/value-vec,對應q、k、v)出來。假設輸入的單詞是Thinking和Machines,先通過Embedding將輸入單詞轉化為詞向量x1和x2,再乘上模型引數來計算q、k、v:
如圖:
在這一步我們可以理解q、k、v是我們的三個特徵表達代理。
第二步,MatMul。即計算對應Attention的權重值,對“Thinking Machines”這句話,對“Thinking”(pos#1)計算attention 分值。我們需要計算每個詞與“Thinking”的評估分(Score),這個分決定著編碼“Thinking”時(某個固定位置時),每個輸入詞需要集中多少關注度。這個分,通過“Thinking”對應query-vector與所有詞的key-vec依次做點積得到。所以當我們處理位置#1時,第一個分值是q1和k1的點積,第二個分值是q1和k2的點積。
這一步類似於之前我們用e距離函式計算相似度的感覺,最後經過softmax變成對應的權重。
第三步:對上一步的乘積做一個除法,(1/sqrt(d(k))),這樣梯度會更穩定。除根號d(k)是為了把資料分佈拉回到正常的正態分佈,使分佈更平滑。縮放是為了使梯度更加穩定。
第四步:處理後的Score通過一個Softmax函式計算對應的權重。Softmax對Score進行歸一化,因此所有Score均為正,且加起來為1。如下圖:
第五步,將softmax分值與value-vec按位相乘。保留關注詞的value值,削弱非相關詞的value值。
第六步,將所有加權向量加和,產生該位置的self-attention的輸出結果。(如z1=0.88v1+0.12v2)
整個過程就是:
矩陣運算時,整個過程可以用公式表達(上述求和過程被內化到矩陣運算中了):
或者你可以看著這個圖來理解:
如果你細心對照你會發現,對比之前的模型結構圖,上述過程並沒有體現結構圖中Mask操作。在Scaled Dot-Product Attention中,Mask是可選的(實際工程實現是必須的,因為效果還是明顯的),在Decoder的時候,我們要獲取所有時刻的輸入(K, V),即不使用Mask,就像我們只會在Decoder的時候使用Attention機制去重點關注某一些輸入一樣。
到這裡我們就可以看出一件事,Encoder的每一個位置都能被下一層注意到,這其實就起到了類似RNN的處理序列資訊的作用。接下來我們是怎麼解決並行的問題的呢,那就是多頭注意力機制。
Multi-Head Attention
Multi-Head Attention進一步完善了Self-Attention層,增強了模型輸入處理的並行性,同時它對輸入的 Q,K,V 進行多次不同的對映,相當於把句子投影到不同的子空間中,提高其表達能力。其結構如下:
具體的過程如下:
Transformer整體回顧
對照上圖所示整個Transform的網路結構圖,結合之前我們已經詳細展示過的Scaled Dot-Product Attention和Multi-Head Attention,進行一些個人理解的說明和未涉及知識點的補充說明:
- 輸入文字的預處理包括兩個:Input Embedding和Positional Encoding,Input Embedding將文字詞語向量化,Positional Encoding使用正弦函式和餘弦函式來構造每個位置的值,使得最終輸入的向量包含每個詞在源文字中的位置資訊。這一步合成的輸入向量送入N層(一般6層)的Encoders中,每一層Encoder包含一個Self-Attention層和一個Feed Forward層。
- Self-Attention層可以理解成是我們所說的Multi-Head Attention,這裡邊包含了很多和Scaled Dot-Product Attention,增加了並行能力及模型表達能力。Scaled Dot-Product Attention之所以實現的是Self-Attention機制,是因為它關注的是自己,即來源可以說同源不同枝的q、k、v。通過一系列計算得出了我們需要的輸出z。
- 從上圖中可以看到Multi-Head Attention和Feed Forward之後都跟著一個Add & Norm,這是什麼呢,我們沒有詳細介紹,可以參見The Illustrated Transformer中詳細的說明,它其實是加入了一個網路輸入的殘差,殘差網路能讓每一層都能獲取一些輸入的原始資訊,不至於梯度消失,有助於提高模型的表達能力。簡單說明如下圖:
- Encoder中利用基本單元疊加,key, query, value來自前一層Encoder的輸出,即Encoder的每個位置都能注意到前一層Encoder的所有位置。這樣也是有助於提升模型的表達能力的。
- Decoder中有兩個與Encoder不同的地方,一個是第一級的Masked Multi-head(使用Mask是因為在預測句子的時候,當前時刻是無法獲取到未來時刻的資訊),另一個是第二級的Multi-Head Attention不僅接受來自前一級的輸出,還要接收Encoder的輸出。
- 第一級Decoder的key, query, value來自前一層Decoder的輸出,但加入了Mask操作,即只能Attend到前面已經翻譯過的輸出的詞語。
- 第二級Decoder也稱為Encoder-Decoder attention layer,它的query來自於之前一級的Decoder層的輸出,但key和value來自於Encoder的輸出,這樣Decoder的每一個位置都可以attend到輸入序列的每一個位置(k和v的來源總是相同的,q在Encoder及第一級Decoder中與k,v來源相同,在encoder-decoder attention layer中與k,v來源不同)。
還是建議多去讀一讀Attention Is All You Need和The Illustrated Transformer,對於我們理解Transform會很有幫助。這篇文章太長了,先到這,還有一些細枝末節需要另外開文講述,包括但不限於:
介紹position encoding機制。
attention機制的細節探索
transformer機制的一些細節探索
參考文章:
Attention機制詳解(一)——Seq2Seq中的Attention
相關文章
- 大模型學習筆記:attention 機制大模型筆記
- 深度學習中的序列模型演變及學習筆記(含RNN/LSTM/GRU/Seq2Seq/Attention機制)深度學習模型筆記RNN
- C 語言學習筆記筆記
- C語言學習筆記C語言筆記
- Go語言核心36講(Go語言基礎知識五)--學習筆記Go筆記
- Go語言核心36講(Go語言進階技術五)--學習筆記Go筆記
- Go語言核心36講(Go語言實戰與應用五)--學習筆記Go筆記
- 學習筆記CB014:TensorFlow seq2seq模型步步進階筆記模型
- 模型微調-書生浦語大模型實戰營學習筆記&大語言模型5大模型筆記
- 【論文閱讀筆記】Transformer——《Attention Is All You Need》筆記ORM
- Solidity語言學習筆記————1、初識Solidity語言Solid筆記
- Solidity語言學習筆記————36、 庫Solid筆記
- Solidity語言學習筆記————37、Using forSolid筆記
- Solidity語言學習筆記————4、常量Solid筆記
- 《JavaScript語言精粹》學習筆記一JavaScript筆記
- 《JavaScript語言精粹》學習筆記二JavaScript筆記
- 熱更新語言--lua學習筆記筆記
- c語言學習筆記===函式C語言筆記函式
- Go語言學習筆記(七)之方法Go筆記
- Solidity語言學習筆記————33、事件(Events)Solid筆記事件
- Solidity語言學習筆記————12、陣列Solid筆記陣列
- Solidity語言學習筆記————34、繼承Solid筆記繼承
- 初識C語言(01)—學習筆記C語言筆記
- C語言學習筆記——位運算C語言筆記
- C語言學習筆記--C運算子C語言筆記
- go 學習筆記之初識 go 語言Go筆記
- c語言程式基礎學習筆記C語言筆記
- C語言學習筆記之變數C語言筆記變數
- RealFormer: 殘差式 Attention 層的Transformer 模型ORM模型
- GO語言學習筆記之mac環境go語言配置Go筆記Mac
- 深度學習的seq2seq模型深度學習模型
- 【Go】Go語言學習筆記-3-包Go筆記
- Solidity語言學習筆記————43、安全考量Solid筆記
- Solidity語言學習筆記————38、Solidity彙編Solid筆記
- Solidity語言學習筆記————42、提示和技巧Solid筆記
- Dart語言學習筆記(一) —— Dart簡介Dart筆記
- Solidity語言學習筆記————28、純函式Solid筆記函式
- Solidity語言學習筆記————26、回退函式Solid筆記函式