1. 程式人生 > >Convolutional Sequence to Sequence Learning 論文筆記

Convolutional Sequence to Sequence Learning 論文筆記

目錄

  • 簡介
  • Position Embeddings
  • GLU or GRU
  • Convolutional Block Structure
  • Multi-step Attention
  • Normalization Strategy
  • Initialization

簡介

寫這篇部落格主要是為了進一步瞭解如何將CNN當作Encoder結構來使用,同時這篇論文也是必看的論文之一。該論文證明了使用CNN作為特徵抽取結構實現Seq2Seq,可以達到與 RNN 相接近甚至更好的效果,並且CNN的高並行能力能夠大大減少我們的模型訓練時間(本文對原文中不清晰的部分做了梳理,建議與原文搭配服用)

原文連結:Convolutional Sequence to Sequence Learning

模型結構如下圖所示:

下面對模型的每個部分進行分塊介紹:

Position Embeddings

卷積網路和Transformer一樣,不是類似於RNN的時序模型,因此需要加入位置編碼來體現詞與詞之間的位置關係

  • 樣本輸入的詞向量:\(w = (w_1, w_2, ..., w_n)\)
  • 樣本位置編碼:\(p = (p_1, p_2, ..., p_n)\)
  • 最終詞向量表徵:\(e = (w_1 + p_1, w_2 + p_2, ..., w_n + p_n)\)

GLU or GRU

GLU和GTU是在同一篇論文中提出的,其中,GLU也是CNN Seq2Seq的主要結構。可以直接將其當作啟用函式來看待,其將某以卷積核的輸出輸入到兩個結構相同的卷積網路,令其中一個的輸出為\(A\),另一個為\(B\)。

GLU與GRU的區別就在於A輸出的啟用函式不同:
\[GLU:H_0=A \otimes \sigma (B)\]

\[GTU:H_0=tanh(A) \otimes \sigma (B)\]

而CNN Seq2Seq就採用了GLU作為模型的啟用函式

原文連結:Language Modeling with Gated Convolutional Networks

Convolutional Block Structure

編碼器與解碼器都是由多個卷積層構成的(原文中稱為block,實際上就是layer),每一層包含一個1維卷積核以及一個門控線性單元(Gated linear units, GLU)。假設單詞數即輸入長度為\(m\),kernel大小為\(k\),pad為\(p\),那麼計算輸出sequence長度的公式為\((m+2p-k)/stride+1\),只要適當的設定卷積核的kernel大小、pad以及步長引數,即可使得輸出序列與輸入序列的維度保持一致。在文中,輸入為25,kernel為5,則輸出序列長度為(25+2*2-5)/1+1=25。

另外,為了充分讓輸出節點跟整個sequence單詞有聯絡,必須使用多個卷積層,這樣才能使得最後一個卷積核有足夠大得感受野以感受整個句子的特徵,同時也能捕捉區域性句子的特徵。

來看一下整個編碼器的前向傳播方式:

  • 每次輸入到卷積核的句子的大小為\(X \in R^{k\times d}\),表明每次卷積核能夠讀取的序列長度為\(k\),也就是卷積核的寬度為\(k\),詞向量維度為$d
  • 卷積核的權重矩陣大小為\(W^{2d \times k \times d}\),偏置向量為\(b_W \in R^{2d}\),表明每一層有\(2d\)個卷積核,因此輸出序列的維度為\(2d\),而由於事先的設計,使得輸入序列與輸出序列的長度是相同的,因此經過卷積之後,得到的序列的矩陣大小為\(Y \in R^{k \times 2d}\)。
  • 我們將上面的\(2d\)個卷積核分為兩個部分,這兩個部分的卷積核尺寸與個數完全相同,輸出維度也完全相同,則可以將其當作\(GLU\)的兩個輸入,輸入到GLU整合過後,輸出的序列維度又變為了\(\hat{Y} \in R^{k \times d}\)
  • 為了能夠實現深層次的網路,在每一層的輸入和輸出之間採用了殘差結構
  • 對於解碼序列來說,我們需要提取解碼序列的隱藏表徵,但是解碼序列的解碼過程是時序遞迴的,即我們無法觀測到當前預測物件之後的序列,因此論文作者將輸入的decoder序列

這樣的卷積策略保證了每一層的輸入與輸出序列的一一對應,並且能夠將其看作簡單的編碼器單元,多層堆疊以實現更深層次的編碼。

Multi-step Attention

對於Attention的計算,關鍵就是找到 Query、Key 和 Value。下圖為計算Attention且解碼的示意圖

Attention的計算過程如下:

  • Query由decoder的最後一個卷積層的輸出\(h_i^l\)以及上一時刻decoder最終的生成的目標\(g_i\)共同決定,\(W^l_d\)與\(b_d^l\)為線性對映的引數。
    \[d_i^l = W^l_dh^l_i+b_d^l+g_i\]

  • Key 則採用 Encoder 的輸出\(z_j^u\),典型的二維匹配模型,將 Query 與 Key 一一對齊,計算 dot attention分數:
    \[a_{ij}^l = \frac{exp(d^l_i \cdot z^u_j)}{\sum_{t=1}^mexp(z_j^u+e_j)}\]

  • Value 的值則取編碼器的輸出\(z_j^u\)以及詞向量表徵\(e_j\)之和,目的是為編碼器的輸出加上位置表徵資訊。得到對應的 Value 值 \(c_i^l\) 之後,直接與當前時刻的 Decoder 輸出 \(h_i^l\) 相加,再輸入分類器進行分類。
    \[c_i^l = \sum_{j=1}^ma_{ij}^l(z_j^u + e_j)\]

Normalization Strategy

模型還通過歸一化策略來保證通過每一層模型的方差變化不會太大,這裡先簡單的記錄一下,具體的操作細節需要回去仔細琢磨程式碼。歸一化的主要策略如下:

  • 對殘差網路的輸入和輸出乘以 \(\sqrt{0.5}\) 來保證輸入和輸出的方差減半(這假設兩側的方差是相等的,雖然這不是總是正確的,但是實驗證明這樣做是有效的)
  • 由於注意力模組的輸出向量為 m 個向量的加權和,因此將其乘以 \(m \sqrt{m}\) 來抵消方差的變化,其中,乘以 \(m\) 是為了將向量放大到原始的大小(實際中通常不會這麼做,但是這麼做的效果良好)
  • 由於採用了多重注意力機制的卷積解碼器,作者根據注意力機制的數量來對反向傳播到編碼器的梯度進行壓縮,這可以避免編碼器接收過多的梯度資訊,使得訓練變得更加平穩。

Initialization

初始化的目的與歸一化是一致的,即都是為了保證前向與後項傳播的資料方差能夠保持在一個較穩定的水準,模型初始化的策略如下:

  • 此前如層都由平均值為0以及標準差為0.1的正太分佈進行初始化。
  • 對於其輸出未直接輸入門控線性單元的層,我們以正態分佈 \(N(0, \sqrt{1/n_l})\) 來初始化權重,其中 \(n_l\) 是每個神經元的輸入連線個數。 這樣可以確保正太分佈的輸入的方差得以保留
  • 對於輸出與GLU相連的層,我們採取不同的策略。如果GLU的輸入的均值為0且方差足夠小,則輸出方差可以近似等於輸入方差的1/4。 因此,需要初始化權重使得GLU啟用的輸入具有該層輸入方差的4倍,即該層的初始化分佈為 \(N(0, \sqrt{4/n_l})\)。
  • 此外,每一層的偏置 \(b\) 統一設定為0
  • 另外,考慮到 dropout 也會影響資料的方差分佈,假設dropout的保留概率為p,則方差將放大為 \(1/p\) 倍,因此上述提到的初始化策略需要修正為: \(N(0, \sqrt{p/n_l})\) 以及 \(N(0, \sqrt{4p/n_l})\)

最後的實驗部分就不記錄了,有興趣的同學可以去原文裡看看。

https://zhuanlan.zhihu.com/p/26918935
https://zhuanlan.zhihu.com/p/27464080
https://www.zhihu.com/question/59645329/answer/17001