transformer是谷歌2023年發表的attention is all you need 中提到的seq2seq模型,我們常用的bert和gpt等都是基於transformer衍生的。本文主要參考了wmathor大佬的transformer 詳解和transformer 的 pytorch 實現兩篇文章。其中第一篇已經詳細說明了transformer的原理,本文主要結合**的實現及自己的理解對**進一步說明。全部**見我的github庫
目錄position encoding
在資料預處理方面為了降低**閱讀的難度,下面的**手動輸入了兩隊德語-->英語的句子,以及對應的編碼。為了劃分句子,有s、e、p三個標誌符號,每個部分的具體作用都在**中進行了注釋
'''
@author xyzhrrr
@time 2021/2/3
'''import math
import torch
import numpy as np
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as data
''' 資料預處理
並沒有用什麼大型的資料集,而是手動輸入了兩對德語→英語的句子,
還有每個字的索引也是手動硬編碼上去的,主要是為了降低**閱讀難度,
s: symbol that shows starting of decoding input
e: symbol that shows starting of decoding output
p: 如果當前批量資料大小短於時間步驟,將填充空白序列的符號
'''sentences = [
# encoder輸入 #decoder輸入 #decoder輸出
['ich mochte ein bier p', 's i want a beer .', 'i want a beer . e'],
['ich mochte ein cola p', 's i want a coke .', 'i want a coke . e']
]#填充應該是0,因為是翻譯所以兩個語言有兩個詞表
src_vocab =
#源詞表長度,這裡直接填序號了,實際中應該使用詞表查詢
src_vocab_size=len(src_vocab)#輸入長度,one-hot長度
tgt_vocab =
#目標詞表序號
idx2word=
#序號轉換成此的表
tgt_vocab_size=len(tgt_vocab)#輸出的one-hot長度
src_len=5 #encoder輸入的最大句長
tgt_le=6#decoder輸入和輸出的最大句長
'''
下面兩個函式分別生資料張量生成以及資料集處理類,其中第二個直接繼承自torch的實現。
'''
@:param sentenses 資料集
@:returns 資料的張量
預設的資料是floattensor型別,我們需要整形,所以用longtensor
'''def make_data(sentenses):
enc_inputs,dec_inputs,dec_outputs=,,
for i in range(len(sentenses)):
#split()以空格為分隔符,即除掉空格
enc_input=[[src_vocab[n] for n in sentenses[i][0].split()]]
#讀取輸入資料,並轉換為序號表示,加入inputs後:[[1, 2, 3, 4, 0], [1, 2, 3, 5, 0]]
dec_input=[[tgt_vocab[n]for n in sentenses[i][1].split()]]
#[6, 1, 2, 3, 4, 8], [6, 1, 2, 3, 5, 8]]
dec_output = [[tgt_vocab[n] for n in sentences[i][2].split()]]
# [[1, 2, 3, 4, 8, 7], [1, 2, 3, 5, 8, 7]]
enc_inputs.extend(enc_input)
dec_inputs.extend(dec_input)
dec_outputs.extend(dec_output)
#在列表末尾一次性追加另乙個序列中的多個值
return torch.longtensor(enc_inputs),torch.longtensor(dec_inputs),torch.longtensor(dec_outputs)
enc_inputs,dec_inputs,dec_outputs=make_data(sentences)
#獲取資料張量
'''資料處理類
'''class mydataset(data.dataset):
def __init__(self,enc_inputs,dec_inputs,dec_outputs):
self.enc_inputs=enc_inputs
self.dec_inputs=dec_inputs
self.dec_outputs=dec_outputs
def __len__(self):
return self.enc_inputs.shape[0]
#返回行數,即資料集大小
def __getitem__(self, item):
return self.enc_inputs[item],self.dec_inputs[item],self.dec_outputs[item]
#返回對應資料的各項內容
#載入資料集
loader=data.dataloader(dataset=mydataset(enc_inputs, dec_inputs, dec_outputs),
batch_size=2, #批處理大小,一次處理多少資料
shuffle=true)
下面變數代表的含義依次是字嵌入 & 位置嵌入的維度,這倆值是相同的,因此用乙個變數就行了
feedforward 層隱藏神經元個數
q、k、v 向量的維度,其中 q 與 k 的維度必須相等,v 的維度沒有限制,不過為了方便起見,我都設為 64
encoder 和 decoder 的個數
多頭注意力中 head 的數量
'''
transformer parameters
'''d_model=512 #embedding size詞嵌入大小
d_ff=2048 # feedforward dimension,全連線層維度
d_k = d_v = 64 # dimension of k(=q), v
n_layers = 6 # number of encoder and decoder layer
n_heads = 8 # number of heads in multi-head attention
由於 transformer 模型沒有迴圈神經網路的迭代操作,所以我們必須提供每個字的位置資訊給 transformer,這樣它才能識別出語言中的順序關係現在定義乙個位置嵌入的概念,也就是 positional encoding,位置嵌入的維度為 [max_sequence_length, embedding_dimension], 位置嵌入的維度與詞向量的維度是相同的,都是 embedding_dimension。max_sequence_length 屬於超引數,指的是限定每個句子最長由多少個詞構成
\[\begin
p e(p o s, 2 i)=\sin \left(p o s / 10000^}}\right) \\
p e(p o s, 2 i+1)=\cos \left(p o s / 10000^}}\right)
\end
\]位置函式的具體理解可以參考這篇文章transformer 中的 positional encoding
Transformer的殘差連線
在學習transformer的過程中,編碼器和解碼器都用到了殘差連線,下面我總結一下殘差連線。假如我們的輸入為x,要得到的輸出為h x 那麼我們可以通過 h f x x,轉換為學習f。等得到f的輸出後,在此基礎上加上x即可得h的輸出。在transformer中,此時的f即是下圖中的multi hea...
Transformer的幾個問題
transformer是 attention is all you need 提出來的,結構如下所示 講解transformer的文章很多,這裡不再重複,可以參考文獻1和文獻2 問題一 為什麼要除以d k sqrt dk 當d kd k dk 增大時,意味著q和k之間的點乘操作會增加,只要qik i...
Transformer 的優點和關鍵優勢
本文不是一篇全文解讀,僅談一談該模型的關鍵優勢,了解我們在構建深度學習模型時使用 transformer 模型的適用條件是什麼。什麼是 transformer?transformer 是 google 的研究者於 2017 年在 attention is all you need 一文中提出的一種用...