Transformer的原理及框架

2022-09-19 19:21:11 字數 4194 閱讀 9870

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 一文中提出的一種用...