Transformer個人詳細總結

2021-09-07 18:18:14 字數 3762 閱讀 4257

必看:非常詳細且準確transformer 總結的相當明確

大致流程:(應該是線性轉換,再將轉換之後的分為h個頭)

一. 將乙個句子進入embedding層得到句子的字向量(維度是512),再加入編碼資訊

二.重點:將這個句子得到的字向量複製三份為q, k, v(q,k,v的維度是(句子長度,512))

三. 將q,k,v分別平均切分為8份,得到q1,q2,q3…q8;k1,k2,k3…k8;v1,v2,v3…v8,他們的shape型別是一抹一樣的(句子長度,512/8=64),很暴力,直接拆分;他們的值也都是完全一樣(q1=k1=v1!=q2)

四. 將切分之後的值分別進行8次不同的線性轉換得到新的q1,q2,q3…q8;k1,k2,k3…k8;v1,v2,v3…v8;由於經過不同的線性轉換,所以得到值不同(q1 != k1 != v1)

五. 如下圖所示,將(q1,k1,v1),(q2,k2,v2)…(q8,k8,v8)分別進行如下圖所示的運算,得到head1,head2…head8

一 .encode部分transformer引數變換表示

首先給乙個輸入序列,輸入也就是輸入的batch_size個句子,其shape為input = [n,t_q],也就是[batch_size = 32,max_length = 15]

設定權重矩陣的大小,即embeding = [vocab_size,num_units],也就是[vocab_size,512],通過tf.nn.embedding_lookup(embeding ,input )函式得到乙個shape為[n,t_q,num_units],即[32,15,512]也就是transformer模型的輸入q,k,v

將三個q,k,v輸入到multi_head attention之前,需要進行位置編碼pos_embeding,得到位置編碼後的shape依然是[n,t_q,num_units],此時輸入的q,k,v都是具有位置資訊的向量了

這一步是重點,進入多頭注意力機制,這個多頭注意力機制是需要執行八次的,進入多頭注意力之後,首先要進行1次線性轉換,q = tf.layers.dense(queries, num_units, activation=tf.nn.relu),轉換之後的q,k,v的shape為[n,t_q,num_units],(這個就是為什麼多頭注意力機制會被稱為多頭了,實際上是經過8次線性轉換(self_attention)而來)然後將得到的q按照第2維拆分成為 h = 8 份,再按照第0維度拼接,q_ ,k_ ,v_ = tf.concat(tf.split(q, num_heads, axis=2), axis=0),得到之後的q_的shape為[hn,t_q,c/h],這裡的c就是num_units,[832,15,512/8=64]

11. 將q_ ,k_ 想乘,k_經過transponse後shape為[hn,c/h=t_k,t_k],再進行scale,得到v_的權重值outputs,shape為[hn,t_q,t_k]

12. 由於再輸入的時候,涉及到padding 0,為了消除這些本身沒有任何資訊的影響,需要對其msking,其輸入為q,k,不是q_ ,k_ ,shape為[n,t_q,num_units],具體步驟1.將此矩陣按照第2維度相加起來,key_masks = tf.sign(tf.abs(tf.reduce_sum(keys, axis=-1))) # (n, t_k) 得到[n,t_q],(這個矩陣只可能是0和1,0是被pading為0的,1就是具有資訊字詞),然後再經過key_masks = tf.tile(key_masks, [num_heads, 1]) 複製,得到shape為 (hn, t_k),然後增加其乙個維度,key_masks = tf.tile(tf.expand_dims(key_masks, 1), [1, tf.shape(queries)[1], 1]) 得到shape為(hn, t_q, t_k),目的就是為了和之前的outputs一樣。paddings = tf.ones_like(outputs)(-2**32+1)

outputs = tf.where(tf.equal(key_masks, 0), paddings, outputs)這兩行的目的就是利用tf.where()這個額函式將padding的向量置為非常非常小的數字,這樣就間接的忽略了padding對總體的影響。按照相同的方法將q也是這樣

13. 運用三角矩陣方法,在解碼的時候,可以選擇是否遮蔽未來的資訊

14. 進行droup_out,開始用v_的權值 * v_得到輸出,outputs = tf.matmul(outputs, v_) # ( hn, t_q, c/h)

15. 將這個shape再重寫 outputs = tf.concat(tf.split(outputs, num_heads, axis=0), axis=2 ) 得到乙個和輸入一樣的shape (n, t_q, c),然後再進行殘差連線 和normal ,outputs += queries,outputs = normalize(outputs) # (n, t_q, c),得到的最終結果和輸入時一樣,方便進行迴圈,並且輸入給全連線層。

!!!小總結:以上4-9就是多頭注意力機制+add,norm的部分

16.全連線層,該層的輸入也就是上面的多頭注意力最後的輸出outputs,輸入層==》隱藏層outputs = tf.layers.conv1d(**params)隱藏層到輸出層

params = ;outputs = tf.layers.conv1d(**params),然後再經過殘差連線+normal,就得出來shape為[n,t_k,c],encode的輸出

!!!以上4-10表示的就是就是完整的encode的部分了,需要迴圈8次!!!

二. decode部分

其實decode和encode差不多,不過比encode多乙個帶有mask的self_attention機制

1.作為decode的輸入,訓練和**是不一樣的,a.在訓練的時候,直接將目標語言拿過來,通過masked進行遮蓋未來資訊,即在t時刻時,其輸入時目標句子t-1時刻的所有資訊,在經過多頭注意力機制,輸出乙個q,當做下乙個多頭機制的三個輸出之一。這也是為什麼q就相當於前一時刻(也就是t時刻之前的所有時刻)的輸出,然後再跟當前時刻的輸入進行注意力計算。b.而在**的時候,由於源語言是隨意的,所以就沒有所謂的標準答案(目標語言),只能講上一時刻的輸出當做decode的輸入

2.經過embeding,再經過pos_embeding,得到q,k,v。跟encode一樣,只是未來資訊貝遮掩了,然後得到輸出當做下一時刻的輸入的q。而encode的輸出當做下一時刻的k,v,經過多頭注意力機制,得到乙個輸出。然後再經過全連線層,經過乙個線性轉換,在通過softmax的輸出乙個概率結果

3.quey就是multihead的輸入x,key、value是輸入x經過不同線性變換(比如,1x1的卷積)得到的不同值,用於計算query中每個詞的權重(self attention)

transformer資料彙總

transformer是google提出的一種新的網路結構,其最大的特點是它的self attention模組,相比於rnn和cnn,self attention可以直接捕獲整個序列的全域性資訊,同時可以平行計算,速度要快很多。了解該模型最直接的方式就是閱讀 原文 attention is all ...

學習筆記 Transformer

1.transform簡介 transformer中拋棄了傳統的cnn和rnn,整個網路結構完全是由attention機制組成。更準確地講,transformer由且僅由self attenion和feed forward neural network組成。乙個基於transformer的可訓練的神...

Transformer的殘差連線

在學習transformer的過程中,編碼器和解碼器都用到了殘差連線,下面我總結一下殘差連線。假如我們的輸入為x,要得到的輸出為h x 那麼我們可以通過 h f x x,轉換為學習f。等得到f的輸出後,在此基礎上加上x即可得h的輸出。在transformer中,此時的f即是下圖中的multi hea...