【學習筆記】Transformer (1)

在看Transformer之前,建議先學習一下Self-attention

同樣,這邊筆記是參考李宏毅老師的課程ppt,感興趣的可以去看原視頻~

補充了Transformer論文精讀筆記,建議結合本文食用: )

Sequence-to-Sequence

沒錯!Transformer是一個sequence-to-sequence (Seq2Seq) 的模型,也就是輸入一個sequence,模型會輸出一個sequence。

前面講self-attention提到模型有三種輸出:1. 每個向量都有一個label;2. 整個序列有一個label;3. 輸出sequence的長度由模型自己決定,也就是這邊的Seq2Seq。

經典的應用包括:機器翻譯、語義識別、問答機器人...幾乎什麼樣五花八門的任務,只要輸入和輸出是sequence,就都可以拿來用Seq2Seq硬做,並且效果居然也不錯。當然啦,針對不同的任務客製化model會比Seq2Seq效果更好,但足以看出Seq2Seq的應用之廣泛。

模型結構

簡單來說,Transformer就是經典的Encoder-Decoder結構:輸入序列進入編碼器,編碼器的輸出再進入解碼器,最終輸出一個序列。

下面來分別講一講Encoder和Decoder具體在做些什麼。

Encoder

下面這張圖的左邊是不是和上一講的Self-attention很像?每個輸入向量都會經過Encoder輸出一個向量,當然,RNN和CNN也可以辦得到這一點!

把Encoder放大,右邊就是Transformer編碼器的結構啦。可以看出,它的主體其實就是Self-attention,中間灰色的框框被視爲一個block,輸入向量要經過N個這樣的block。

可是,右邊的圖花花綠綠看起來好複雜!

我們來看下面這張圖:輸入向量經過一個block,得到的輸出再作爲下一個block的輸入...最終得到輸出向量。

每個block做的事情也很簡單:經過self-attention得到的各個向量分別餵給一個全連接層得到輸出。

簡單複習一下,self-attention做的事情就是整合序列信息,每個向量經過投影后得到query、key、value,計算每個query和所有key的相似度 (attention score) 作爲各個value的權值,而加權和就是最後的輸出。

 但是,Transformer編碼器做的事情要稍微複雜一點點,每個向量經過self-attention得到的輸出,還要加上原始的輸入(這就是ResNet裏的殘差連接)!如果b是輸入向量,對應self-attention的輸出向量爲a,那麼b + a纔是我們需要的。

這之後,還要再經過一個Norm層。注意,這裏不是常見的Batch Normalization,而是Layer Normalization。BN是對整個batch的樣本在特徵維上做normalization,而LN是每個樣本自己做normalization,不需要考慮整個batch。這是合理的,每個序列長度都不統一,自己做normalization效果自然會更好。

經過LN之後的輸出,纔是要進入全連接層的輸入。同樣,這邊也要用到殘差連接和LN:FC的輸出加上FC的輸入,經過LN後得到這一個block的最終輸出。

 聽起來很像繞口令對不對?但是仔細看懂上面的圖片在做什麼之後,再回過來看Transformer的Encoder會豁然開朗。

輸入向量經過embedding層,加上位置編碼(同樣在self-attention裏提到過),進入第一個block:先做multi-head attention,輸出+輸入做Layer norm,經過全連接層後再做一次殘差連接和LN,得到block的輸出。這樣的block會重複N次。

 block一定要這麼設計嗎?當然不一定。在Transformer之後,有不少論文做了相關的研究,比如下面這個就把Layer Norm放在了attention前面,效果更好了。

Decoder

講完編碼器,我們來看解碼器。解碼器有兩種,AT和NAT。

  • Autoregressive (AT)

解碼器通過某種方法把Encoder的輸出讀進來(後面會細說),輸入一個特殊的START向量來作爲序列的開始。

假設要處理翻譯任務,這個輸出向量的維數就和字典的長度一樣,每個字都會對應一個數值,分數最高的那一個字就是最後的輸出。

拿到第一個輸出之後,把它作爲下一個輸入進入Decoder,重複前面的步驟,依次得到新的輸出和新的輸入...這樣的過程就叫做自迴歸 (Autoregressive) 。

但是,難道就這麼無休止的輸出下去嗎?

當然不了!有始 (START) 有終 (END) ,在字典裏我們也要加入一個特殊的END,標誌着輸出序列的結束。

現在,我們來看看Decoder具體在做些什麼。

誒,怎麼這麼眼熟?沒錯,它和Encoder長得很像!把中間那一塊擋住,Decoder和Encoder的block簡直一模一樣嘛!

但是,這邊爲什麼是Masked Attention呢?

和前面的Encoder不一樣,Decoder是一個一個輸出的,在產生當前輸出的時候,只考慮它左邊的那些輸入,而不是一下子看到整個輸入序列。

  • Non-autoregressive (NAT)

和自迴歸解碼器不同,NAT解碼器一次性產生所有輸出——因此,也是一次性輸入BEGIN!

可是,我們並不知道輸出序列有多長啊?NAT是怎麼辦到的呢?

有兩個方法:

  1. 再加一個predictor,把編碼器的輸出作爲輸入,預測序列的長度
  2. 輸入一個很長的STRAT序列,輸出只取END之前的部分

Encoder - Decoder

前面挖的坑還沒填,Decoder和Encoder是怎麼聯動的呢?

這裏就要引入一個叫”cross-attention“的東西啦。不要被名字嚇到,就那麼回事兒——只不過key和value來自Encoder的最後一層輸出,query來自Decoder經過Masked Attention的輸出。當然,輸出都要先做投影再做attention。

現在看看Transformer整體架構,是不是就懂啦~

Training

我們觀察一下Decoder的輸入,其實這不就是Decoder的輸出嘛!

所以在訓練的時候,我們可以把Ground Truth(真實值)拿來做輸入,再拿輸出和GT算交叉熵,希望所有交叉熵的總和越小越好。

可是在做inference的時候,Decoder看不到正確答案啊!顯然和訓練的情況存在一個mismatch。

如果Decoder在訓練的時候只看過正確的東西,那麼inference時可能會出現“一步錯,步步錯”的情況。所以,在訓練的時候,我們不能只給Decoder看正確的答案,也要輸入一些錯誤的東西給它看。這一招叫Schedule Sampling。

比如,GT是“機器學習”,可我們會故意輸入“機氣學習”,這樣如果Decoder犯錯輸出了“機氣”,後面也不至於跟着全部錯下去。是不是很有意思?人生也是這樣,需要引入一些“隨機性”,不斷地踩坑、走彎路,看過更多不一樣的風景,好壞都參透,後面的路才能走得更穩。

 

到這裏,Transformer就全部講完啦!

歡迎大家評論區留言討論!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章