公益AI-TASK04-機器翻譯及相關(guān)技術(shù);注意力機制與Seq2seq模型;Transformer

機器翻譯及相關(guān)技術(shù)
機器翻譯(MT):將一段文本從一種語言自動翻譯為另一種語言,用神經(jīng)網(wǎng)絡(luò)解決這個問題通常稱為神經(jīng)機器翻譯(NMT)。 主要特征:輸出是單詞序列而不是單個單詞。 輸出序列的長度可能與源序列的長度不同。

數(shù)據(jù)預(yù)處理
將數(shù)據(jù)集清洗、轉(zhuǎn)化為神經(jīng)網(wǎng)絡(luò)的輸入minbatch
字符在計算機里是以編碼的形式存在,我們通常所用的空格是 \x20 ,是在標準ASCII可見字符 0x20~0x7e 范圍內(nèi)。 而 \xa0 屬于 latin1 (ISO/IEC_8859-1)中的擴展字符集字符,代表不間斷空白符nbsp(non-breaking space),超出gbk編碼范圍,是需要去除的特殊字符。再數(shù)據(jù)預(yù)處理的過程中,我們首先需要對數(shù)據(jù)進行清洗。

分詞
字符串---單詞組成的列表

建立詞典
單詞組成的列表---單詞id組成的列表

載入數(shù)據(jù)集

Encoder-Decoder
encoder:輸入到隱藏狀態(tài)
decoder:隱藏狀態(tài)到輸出
可以應(yīng)用在對話系統(tǒng)、生成式任務(wù)中。

class Encoder(nn.Module):
    def __init__(self, **kwargs):
        super(Encoder, self).__init__(**kwargs)

    def forward(self, X, *args):
        raise NotImplementedError
class Decoder(nn.Module):
    def __init__(self, **kwargs):
        super(Decoder, self).__init__(**kwargs)

    def init_state(self, enc_outputs, *args):
        raise NotImplementedError

    def forward(self, X, state):
        raise NotImplementedError
class EncoderDecoder(nn.Module):
    def __init__(self, encoder, decoder, **kwargs):
        super(EncoderDecoder, self).__init__(**kwargs)
        self.encoder = encoder
        self.decoder = decoder

    def forward(self, enc_X, dec_X, *args):
        enc_outputs = self.encoder(enc_X, *args)
        dec_state = self.decoder.init_state(enc_outputs, *args)
        return self.decoder(dec_X, dec_state)

Seq2Seq

class Seq2SeqEncoder(d2l.Encoder):
    def __init__(self, vocab_size, embed_size, num_hiddens, num_layers,
                 dropout=0, **kwargs):
        super(Seq2SeqEncoder, self).__init__(**kwargs)
        self.num_hiddens=num_hiddens
        self.num_layers=num_layers
        self.embedding = nn.Embedding(vocab_size, embed_size)
        self.rnn = nn.LSTM(embed_size,num_hiddens, num_layers, dropout=dropout)
   
    def begin_state(self, batch_size, device):
        return [torch.zeros(size=(self.num_layers, batch_size, self.num_hiddens),  device=device),
                torch.zeros(size=(self.num_layers, batch_size, self.num_hiddens),  device=device)]
    def forward(self, X, *args):
        X = self.embedding(X) # X shape: (batch_size, seq_len, embed_size)
        X = X.transpose(0, 1)  # RNN needs first axes to be time
        # state = self.begin_state(X.shape[1], device=X.device)
        out, state = self.rnn(X)
        # The shape of out is (seq_len, batch_size, num_hiddens).
        # state contains the hidden state and the memory cell
        # of the last time step, the shape is (num_layers, batch_size, num_hiddens)
        return out, state
class Seq2SeqDecoder(d2l.Decoder):
    def __init__(self, vocab_size, embed_size, num_hiddens, num_layers,
                 dropout=0, **kwargs):
        super(Seq2SeqDecoder, self).__init__(**kwargs)
        self.embedding = nn.Embedding(vocab_size, embed_size)
        self.rnn = nn.LSTM(embed_size,num_hiddens, num_layers, dropout=dropout)
        self.dense = nn.Linear(num_hiddens,vocab_size)

    def init_state(self, enc_outputs, *args):
        return enc_outputs[1]

    def forward(self, X, state):
        X = self.embedding(X).transpose(0, 1)
        out, state = self.rnn(X, state)
        # Make the batch to be the first dimension to simplify loss computation.
        out = self.dense(out).transpose(0, 1)
        return out, state

然后是定義損失函數(shù)、train

Beam Search

注意力機制與Seq2seq模型
注意力機制
在“編碼器—解碼器(seq2seq)”?節(jié)?,解碼器在各個時間步依賴相同的背景變量(context vector)來獲取輸?序列信息。當編碼器為循環(huán)神經(jīng)?絡(luò)時,背景變量來?它最終時間步的隱藏狀態(tài)。將源序列輸入信息以循環(huán)單位狀態(tài)編碼,然后將其傳遞給解碼器以生成目標序列。然而這種結(jié)構(gòu)存在著問題,尤其是RNN機制實際中存在長程梯度消失的問題,對于較長的句子,我們很難寄希望于將輸入的序列轉(zhuǎn)化為定長的向量而保存所有的有效信息,所以隨著所需翻譯句子的長度的增加,這種結(jié)構(gòu)的效果會顯著下降。

與此同時,解碼的目標詞語可能只與原輸入的部分詞語有關(guān),而并不是與所有的輸入有關(guān)。例如,當把“Hello world”翻譯成“Bonjour le monde”時,“Hello”映射成“Bonjour”,“world”映射成“monde”。在seq2seq模型中,解碼器只能隱式地從編碼器的最終狀態(tài)中選擇相應(yīng)的信息。然而,注意力機制可以將這種選擇過程顯式地建模。

注意力機制框架
Attention 是一種通用的帶權(quán)池化方法,輸入由兩部分構(gòu)成:詢問(query)和鍵值對(key-value pairs)。 ki∈Rdk,vi∈Rdv . Query q∈Rdq , attention layer得到輸出與value的維度一致 o∈Rdv . 對于一個query來說,attention layer 會與每一個key計算注意力分數(shù)并進行權(quán)重的歸一化,輸出的向量 o 則是value的加權(quán)求和,而每個key計算的權(quán)重與value一一對應(yīng)。

為了計算輸出,我們首先假設(shè)有一個函數(shù) α 用于計算query和key的相似性,然后可以計算所有的 attention scores a1,…,an by

ai=α(q,ki).

我們使用 softmax函數(shù) 獲得注意力權(quán)重:

b1,…,bn=softmax(a1,…,an).

最終的輸出就是value的加權(quán)求和:

o=∑i=1nbivi.

不同的attetion layer的區(qū)別在于score函數(shù)的選擇,在本節(jié)的其余部分,我們將討論兩個常用的注意層 Dot-product Attention 和 Multilayer Perceptron Attention;隨后我們將實現(xiàn)一個引入attention的seq2seq模型并在英法翻譯語料上進行訓(xùn)練與測試。

Softmax 屏蔽
在深入研究實現(xiàn)之前,我們首先介紹softmax操作符的一個屏蔽操作。
超出2維矩陣的乘法

X 和 Y 是維度分別為 (b,n,m) 和 (b,m,k) 的張量,進行 b 次二維矩陣乘法后得到 Z , 維度為 (b,n,k) 。

Z[i,:,:]=dot(X[i,:,:],Y[i,:,:])for i=1,…,n .

點積注意力
The dot product 假設(shè)query和keys有相同的維度, 即 ?i,q,ki∈Rd . 通過計算query和key轉(zhuǎn)置的乘積來計算attention score,通常還會除去 d??√ 減少計算出來的score對維度??的依賴性,如下

α(q,k)=?q,k?/d??√

假設(shè) Q∈Rm×d 有 m 個query, K∈Rn×d 有 n 個keys. 我們可以通過矩陣運算的方式計算所有 mn 個score:

α(Q,K)=QKT/d??√

現(xiàn)在讓我們實現(xiàn)這個層,它支持一批查詢和鍵值對。此外,它支持作為正則化隨機刪除一些注意力權(quán)重.

測試
現(xiàn)在我們創(chuàng)建了兩個批,每個批有一個query和10個key-values對。我們通過valid_length指定,對于第一批,我們只關(guān)注前2個鍵-值對,而對于第二批,我們將檢查前6個鍵-值對。因此,盡管這兩個批處理具有相同的查詢和鍵值對,但我們獲得的輸出是不同的。

多層感知機注意力
在多層感知器中,我們首先將 query and keys 投影到 Rh .為了更具體,我們將可以學(xué)習(xí)的參數(shù)做如下映射 Wk∈Rh×dk , Wq∈Rh×dq , and v∈Rh . 將score函數(shù)定義
α(k,q)=vTtanh(Wkk+Wqq)

. 然后將key 和 value 在特征的維度上合并(concatenate),然后送至 a single hidden layer perceptron 這層中 hidden layer 為 ? and 輸出的size為 1 .隱層激活函數(shù)為tanh,無偏置.

測試
盡管MLPAttention包含一個額外的MLP模型,但如果給定相同的輸入和相同的鍵,我們將獲得與DotProductAttention相同的輸出

總結(jié)
注意力層顯式地選擇相關(guān)的信息。
注意層的內(nèi)存由鍵-值對組成,因此它的輸出接近于鍵類似于查詢的值。

引入注意力機制的Seq2seq模型
本節(jié)中將注意機制添加到sequence to sequence 模型中,以顯式地使用權(quán)重聚合states。下圖展示encoding 和decoding的模型結(jié)構(gòu),在時間步為t的時候。此刻attention layer保存著encodering看到的所有信息——即encoding的每一步輸出。在decoding階段,解碼器的 t 時刻的隱藏狀態(tài)被當作query,encoder的每個時間步的hidden states作為key和value進行attention聚合. Attetion model的輸出當作成上下文信息context vector,并與解碼器輸入 Dt 拼接起來一起送到解碼器:

解碼器
由于帶有注意機制的seq2seq的編碼器與之前章節(jié)中的Seq2SeqEncoder相同,所以在此處我們只關(guān)注解碼器。我們添加了一個MLP注意層(MLPAttention),它的隱藏大小與解碼器中的LSTM層相同。然后我們通過從編碼器傳遞三個參數(shù)來初始化解碼器的狀態(tài):

the encoder outputs of all timesteps:encoder輸出的各個狀態(tài),被用于attetion layer的memory部分,有相同的key和values
the hidden state of the encoder’s final timestep:編碼器最后一個時間步的隱藏狀態(tài),被用于初始化decoder 的hidden state
the encoder valid length: 編碼器的有效長度,借此,注意層不會考慮編碼器輸出中的填充標記(Paddings)
在解碼的每個時間步,我們使用解碼器的最后一個RNN層的輸出作為注意層的query。然后,將注意力模型的輸出與輸入嵌入向量連接起來,輸入到RNN層。雖然RNN層隱藏狀態(tài)也包含來自解碼器的歷史信息,但是attention model的輸出顯式地選擇了enc_valid_len以內(nèi)的編碼器輸出,這樣attention機制就會盡可能排除其他不相關(guān)的信息。
現(xiàn)在我們可以用注意力模型來測試seq2seq。為了與第9.7節(jié)中的模型保持一致,我們對vocab_size、embed_size、num_hiddens和num_layers使用相同的超參數(shù)。結(jié)果,我們得到了相同的解碼器輸出形狀,但是狀態(tài)結(jié)構(gòu)改變了。

訓(xùn)練
與第9.7.4節(jié)相似,通過應(yīng)用相同的訓(xùn)練超參數(shù)和相同的訓(xùn)練損失來嘗試一個簡單的娛樂模型。從結(jié)果中我們可以看出,由于訓(xùn)練數(shù)據(jù)集中的序列相對較短,額外的注意層并沒有帶來顯著的改進。由于編碼器和解碼器的注意層的計算開銷,該模型比沒有注意的seq2seq模型慢得多。

Transformer

在之前的章節(jié)中,我們已經(jīng)介紹了主流的神經(jīng)網(wǎng)絡(luò)架構(gòu)如卷積神經(jīng)網(wǎng)絡(luò)(CNNs)和循環(huán)神經(jīng)網(wǎng)絡(luò)(RNNs)。讓我們進行一些回顧:

  • CNNs 易于并行化,卻不適合捕捉變長序列內(nèi)的依賴關(guān)系。
  • RNNs 適合捕捉長距離變長序列的依賴,但是卻難以實現(xiàn)并行化處理序列。

為了整合CNN和RNN的優(yōu)勢,[Vaswani et al., 2017] 創(chuàng)新性地使用注意力機制設(shè)計了Transformer模型。該模型利用attention機制實現(xiàn)了并行化捕捉序列依賴,并且同時處理序列的每個位置的tokens,上述優(yōu)勢使得Transformer模型在性能優(yōu)異的同時大大減少了訓(xùn)練時間。

圖10.3.1展示了Transformer模型的架構(gòu),與9.7節(jié)的seq2seq模型相似,Transformer同樣基于編碼器-解碼器架構(gòu),其區(qū)別主要在于以下三點:

  1. Transformer blocks:將seq2seq模型重的循環(huán)網(wǎng)絡(luò)替換為了Transformer Blocks,該模塊包含一個多頭注意力層(Multi-head Attention Layers)以及兩個position-wise feed-forward networks(FFN)。對于解碼器來說,另一個多頭注意力層被用于接受編碼器的隱藏狀態(tài)。
  2. Add and norm:多頭注意力層和前饋網(wǎng)絡(luò)的輸出被送到兩個“add and norm”層進行處理,該層包含殘差結(jié)構(gòu)以及層歸一化。
  3. Position encoding:由于自注意力層并沒有區(qū)分元素的順序,所以一個位置編碼層被用于向序列元素里添加位置信息。

多頭注意力層
在我們討論多頭注意力層之前,先來迅速理解以下自注意力(self-attention)的結(jié)構(gòu)。自注意力模型是一個正規(guī)的注意力模型,序列的每一個元素對應(yīng)的key,value,query是完全一致的。如圖10.3.2 自注意力輸出了一個與輸入長度相同的表征序列,與循環(huán)神經(jīng)網(wǎng)絡(luò)相比,自注意力對每個元素輸出的計算是并行的,所以我們可以高效的實現(xiàn)這個模塊。
多頭注意力層包含 h 個并行的自注意力層,每一個這種層被成為一個head。對每個頭來說,在進行注意力計算之前,我們會將query、key和value用三個現(xiàn)行層進行映射,這 h 個注意力頭的輸出將會被拼接之后輸入最后一個線性層進行整合。
假設(shè)query,key和value的維度分別是 dq 、 dk 和 dv 。那么對于每一個頭 i=1,…,h ,我們可以訓(xùn)練相應(yīng)的模型權(quán)重 W(i)q∈Rpq×dq 、 W(i)k∈Rpk×dk 和 W(i)v∈Rpv×dv ,以得到每個頭的輸出:

o(i)=attention(W(i)qq,W(i)kk,W(i)vv)

這里的attention可以是任意的attention function,比如前一節(jié)介紹的dot-product attention以及MLP attention。之后我們將所有head對應(yīng)的輸出拼接起來,送入最后一個線性層進行整合,這個層的權(quán)重可以表示為 Wo∈Rd0×hpv
o=Wo[o(1),…,o(h)]

接下來我們就可以來實現(xiàn)多頭注意力了,假設(shè)我們有h個頭,隱藏層權(quán)重 hidden_size=pq=pk=pv 與query,key,value的維度一致。除此之外,因為多頭注意力層保持輸入與輸出張量的維度不變,所以輸出feature的維度也設(shè)置為 d0=hidden_size 。

基于位置的前饋網(wǎng)絡(luò)
Transformer 模塊另一個非常重要的部分就是基于位置的前饋網(wǎng)絡(luò)(FFN),它接受一個形狀為(batch_size,seq_length, feature_size)的三維張量。Position-wise FFN由兩個全連接層組成,他們作用在最后一維上。因為序列的每個位置的狀態(tài)都會被單獨地更新,所以我們稱他為position-wise,這等效于一個1x1的卷積。

Add and Norm
除了上面兩個模塊之外,Transformer還有一個重要的相加歸一化層,它可以平滑地整合輸入和其他層的輸出,因此我們在每個多頭注意力層和FFN層后面都添加一個含殘差連接的Layer Norm層。這里 Layer Norm 與7.5小節(jié)的Batch Norm很相似,唯一的區(qū)別在于Batch Norm是對于batch size這個維度進行計算均值和方差的,而Layer Norm則是對最后一維進行計算。層歸一化可以防止層內(nèi)的數(shù)值變化過大,從而有利于加快訓(xùn)練速度并且提高泛化性能。

位置編碼
與循環(huán)神經(jīng)網(wǎng)絡(luò)不同,無論是多頭注意力網(wǎng)絡(luò)還是前饋神經(jīng)網(wǎng)絡(luò)都是獨立地對每個位置的元素進行更新,這種特性幫助我們實現(xiàn)了高效的并行,卻丟失了重要的序列順序的信息。為了更好的捕捉序列信息,Transformer模型引入了位置編碼去保持輸入序列元素的位置。

假設(shè)輸入序列的嵌入表示 X∈Rl×d , 序列長度為 l 嵌入向量維度為 d ,則其位置編碼為 P∈Rl×d ,輸出的向量就是二者相加 X+P 。

位置編碼是一個二維的矩陣,i對應(yīng)著序列中的順序,j對應(yīng)其embedding vector內(nèi)部的維度索引。

編碼器
我們已經(jīng)有了組成Transformer的各個模塊,現(xiàn)在我們可以開始搭建了!編碼器包含一個多頭注意力層,一個position-wise FFN,和兩個 Add and Norm層。對于attention模型以及FFN模型,我們的輸出維度都是與embedding維度一致的,這也是由于殘差連接天生的特性導(dǎo)致的,因為我們要將前一層的輸出與原始輸入相加并歸一化。
現(xiàn)在我們來實現(xiàn)整個Transformer 編碼器模型,整個編碼器由n個剛剛定義的Encoder Block堆疊而成,因為殘差連接的緣故,中間狀態(tài)的維度始終與嵌入向量的維度d一致;同時注意到我們把嵌入向量乘以 d??√ 以防止其值過小。

解碼器
Transformer 模型的解碼器與編碼器結(jié)構(gòu)類似,然而,除了之前介紹的幾個模塊之外,編碼器部分有另一個子模塊。該模塊也是多頭注意力層,接受編碼器的輸出作為key和value,decoder的狀態(tài)作為query。與編碼器部分相類似,解碼器同樣是使用了add and norm機制,用殘差和層歸一化將各個子層的輸出相連。

仔細來講,在第t個時間步,當前輸入 xt 是query,那么self attention接受了第t步以及前t-1步的所有輸入 x1,…,xt?1 。在訓(xùn)練時,由于第t位置的輸入可以觀測到全部的序列,這與預(yù)測階段的情形項矛盾,所以我們要通過將第t個時間步所對應(yīng)的可觀測長度設(shè)置為t,以消除不需要看到的未來的信息。

對于Transformer解碼器來說,構(gòu)造方式與編碼器一樣,除了最后一層添加一個dense layer以獲得輸出的置信度分數(shù)。下面讓我們來實現(xiàn)一下Transformer Decoder,除了常規(guī)的超參數(shù)例如vocab_size embedding_size 之外,解碼器還需要編碼器的輸出 enc_outputs 和句子有效長度 enc_valid_length。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容