seq2seq到加上attention機制,再整合成transformer

時間問題,,開個好頭。


1.機器翻譯有一個大問題,就是輸入輸出的序列長度不一定相等。於是設計出Encoder-Decoder模型

*

在這裏插入圖片描述
於是就有了Sequence to Sequenceseq模型
在這裏插入圖片描述
簡答來說就是在輸出的時候:先輸入bos,然後以eos爲結束標記。
總結:

  1. Sequence to Sequence encoder、decoder的網絡可以是任意RNN網絡:LSTM,雙向RNN等;
  2. 這裏Encoder不需要用到每一個單元的output,只需把H傳到Decoder作爲初始輸入;
  3. 注意embedding X的shape(batch_size, seq_len, embed_size),但是RNN的第一個輸入維度要是時間步數,所以要轉換一下
X = X.transpose(0, 1)
 # (seq_len, batch_size, embed_size)

補充:
數據集預處理的時候除了要padding每一個sample,還要記錄每一個sample的vail_len,因爲參數更新的時候無需更新padding的單元,記錄了就直接在padding的位置值-無窮;那麼exp(tokens)就爲0,不影響softmax

array = torch.tensor([pad(line, max_len, vocab.pad) for line in lines])
valid_len = (array != vocab.pad).sum(1)
# 取出vail_len的單元
 maxlen = X.size(1) # 每一行的最大 就是這一行有多少列
 mask = torch.arange(maxlen)[None, :].to(X_len.device) < X_len[:, None] 
 X[~mask]=value(value爲0-1) 

還有就是數據預處理其實也不好做,之前上課做的很多情況,特別是處理中文文本,要考慮超級無敵多情況,要學會熟練使用re正則表達式。 還有一些符號,比如空格 的編碼字符不能被計算機識別,要轉換成可以識別的狀況,這個是真的大坑啊!

t.replace('\u202f', ' ').replace('\xa0', ' ')

1.2.Beam Search*

在這裏插入圖片描述
decoder的時候,經過dense選取得分最高的一個是貪婪搜索,將當前每一個最高分的token輸出,這樣可能會錯過最優解;
但是全局搜索(維特比算法,經典算法)的話計算量又很大,不符合現實;
於是取中,選取每一次得分最高的N個進行搜索解。
比如最高的兩個:
在這裏插入圖片描述
注意 :集束算法也不一定是最優解,也屬於貪心算法。

2.Attention機制

2.1 在機器翻譯中,較長的句子很難寄希望encoder保留有效信息,與此同時,解碼的目標詞語可能只與原輸入的部分詞語有關,而並不是與所有的輸入有關

在seq2seq模型中,解碼器只能隱式地從編碼器的最終狀態中選擇相應的信息。然而,注意力機制可以將這種選擇過程顯式地建模。記起老師說好像也可以作用在cnn上,不一定只應用於機器翻譯。
Attention三大部分:query values keys

總結:

  1. 增加單詞組合之間的聯繫,這裏直接關心他是怎麼實現的。
  2. 簡單的線性計算就能產生很好的效果,真的是太厲害了。

在這裏插入圖片描述

2.2 引入到seq2seq模型

在這裏插入圖片描述

Encoder的每一個單元的outputs作爲key-value (這裏就運用到output了)
Encoder最後的H作爲Query
attention的輸出就當成 content vector. 然後和輸入Dt cat一起

在代碼中加入:

# select hidden state of the last rnn layer as query
query = hidden_state[0][-1].unsqueeze(1) # np.expand_dims(hidden_state[0][-1], axis=1)
# context has same shape as query
# print("query enc_outputs, enc_outputs:\n",query.size(), enc_outputs.size(), enc_outputs.size())
context = self.attention_cell(query, enc_outputs, enc_outputs, enc_valid_len)
# Concatenate on the feature dimension
#print("context.size:",context.size())
x = torch.cat((context, x.unsqueeze(1)), dim=-1)
# Reshape x to (1, batch_size, embed_size+hidden_size)
out, hidden_state = self.rnn(x.transpose(0,1), hidden_state)
outputs.append(out)
outputs = self.dense(torch.cat(outputs, dim=0))

3.Transformer

實現兩大難點:處理長序列信息;實現並行化(q,k,v維度一致)

3.1多頭注意力層 multi_head attention(多頭並行一起計算)

注意:Decoder 部分的第二個注意力層不是自注意力,key-value來自編碼器而query來自解碼器
在這裏插入圖片描述
多頭注意力層:簡單理解就是每一個輸入都是Q,K,V(shape一樣) [補充:attention 本質就是 q,k,v的簡單線性輸出 w*x,好像沒有b] 這裏每一個計算出來就concat起來到dense
在這裏插入圖片描述

3.2 基於位置的前饋網絡(PositionWiseFFN)

他等效於一個1*1的卷積,因爲他接受的輸入(batch_size,seq_length, feature_size)的三維張量

class PositionWiseFFN(nn.Module):
    def __init__(self, input_size, ffn_hidden_size, hidden_size_out, **kwargs):
        super(PositionWiseFFN, self).__init__(**kwargs)
        self.ffn_1 = nn.Linear(input_size, ffn_hidden_size)
        self.ffn_2 = nn.Linear(ffn_hidden_size, hidden_size_out)
        
        
    def forward(self, X):
        return self.ffn_2(F.relu(self.ffn_1(X)))

與多頭注意力層相似,FFN層同樣只會對最後一維的大小進行改變;除此之外,對於兩個完全相同的輸入,FFN層的輸出也將相等。這個很重要,後面計算一定要注意維度!!

3.3 Add and Norm

這裏涉及到 layer_norm和batch_norm
參考:https://zhuanlan.zhihu.com/p/54530247
Transformer還有一個重要的相加歸一化層,它可以平滑地整合輸入和其他層的輸出,因此我們在每個多頭注意力層和FFN層後面都添加一個含殘差連接的Layer Norm層。

(這裏 Layer Norm 與7.5小節的Batch Norm很相似,唯一的區別在於Batch Norm是對於batch size這個維度進行計算均值和方差的,而Layer Norm則是對最後一維進行計算。層歸一化可以防止層內的數值變化過大,從而有利於加快訓練速度並且提高泛化性能。)

BN:對同一個batch裏的樣本(不同樣本)的同一個channel進行歸一化;
LN:對同一個樣本的不同channel進行歸一化 ;就是一個seq_len的所有時間步進行歸一化。
補充:還有其他三種歸一化。。遇見的時候再補充

exmaples:
layernorm = nn.LayerNorm(normalized_shape=2, elementwise_affine=True)
batchnorm = nn.BatchNorm1d(num_features=2, affine=True)
X = torch.FloatTensor([[1,2], [3,4]])
print('layer norm:', layernorm(X))  # 對行
print('batch norm:', batchnorm(X)) # 對列

3.4 位置編碼

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

涉及到(seq_len, embedding_size) 更新的時候並行更新,會丟失序列信息
i:序列中的順序(就是i在seq_len中第幾個), j:embedding vector內部的索引(第幾個embeding vector)

我的理解是:並行運算 原來的seq embedding vector計算的時候不是一個個vector進行計算的,或者說可其他vector組合了(multi_head attention),原來的序列就找不到了。
在這裏插入圖片描述

3.5 Decoder層

也是多了add_norm層等等

唯一注意就是:由於t位置的輸入可以觀測到所有序列,這樣不能進行預測,所以要通過將第t個時間步所對應的可觀測長度設置爲t,以消除不需要看到的未來的信息。 通過valid_length進行處理
valid_length = torch.FloatTensor(np.tile(np.arange(1, seq_len+1), (batch_size, 1)))

Sequence Mask只在Decoder端進行,目的是爲了使得decoder不能看見未來的信息.也就是對於一個序列中的第i個token,解碼的時候只能夠依靠i時刻之前(包括i)的的輸出,而不能依賴於i時刻之後的輸出.

關於mask,還有:

  1. 對key中padding進行的mask操作
  2. 對query中的padding進行的mask操作

目前沒理解錯的話,這兩種都是爲了對padding的內容進行運算後置0的操作,不對他進行attention(更新)。
在這裏插入圖片描述

內容太多了!!參考資料太少,我還要好多理解還沒寫上去,時間問題!!好多坑啊,好多不懂的 懂得總結還沒寫上去。。以後要補充!!!

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