編碼器 | 基于 Transformers 的編碼器-解碼器模型

基于 transformer 的編碼器-解碼器模型是?表征學(xué)習(xí)?和?模型架構(gòu)?這兩個領(lǐng)域多年研究成果的結(jié)晶。本文簡要介紹了神經(jīng)編碼器-解碼器模型的歷史,更多背景知識,建議讀者閱讀由 Sebastion Ruder 撰寫的這篇精彩?博文。此外,建議讀者對?自注意力 (self-attention) 架構(gòu)?有一個基本了解,可以閱讀 Jay Alammar 的?這篇博文?復(fù)習(xí)一下原始 transformer 模型。
本文分 4 個部分:
背景 -?簡要回顧了神經(jīng)編碼器-解碼器模型的歷史,重點關(guān)注基于 RNN 的模型。
編碼器-解碼器 -?闡述基于 transformer 的編碼器-解碼器模型,并闡述如何使用該模型進(jìn)行推理。
編碼器 -?闡述模型的編碼器部分。
解碼器 -?闡述模型的解碼器部分。
每個部分都建立在前一部分的基礎(chǔ)上,但也可以單獨閱讀。這篇分享是第三部分?編碼器。
編碼器
如前一節(jié)所述,?基于 transformer?的編碼器將輸入序列映射到上下文相關(guān)的編碼序列:
fθenc:X1:n→X1:n
仔細(xì)觀察架構(gòu),基于 transformer 的編碼器由許多?殘差注意力模塊?堆疊而成。每個編碼器模塊都包含一個?雙向?自注意力層,其后跟著兩個前饋層。這里,為簡單起見,我們忽略歸一化層 (normalization layer)。此外,我們不會深入討論兩個前饋層的作用,僅將其視為每個編碼器模塊?1?的輸出映射層。雙向自注意層將每個輸入向量?x′j,?j∈1,…,n?與全部輸入向量?x′1,…,x′n?相關(guān)聯(lián)并通過該機(jī)制將每個輸入向量?x′j?提煉為與其自身上下文相關(guān)的表征:?x′′j。因此,第一個編碼器塊將輸入序列?X1:n?(如下圖淺綠色所示) 中的每個輸入向量從?上下文無關(guān)?的向量表征轉(zhuǎn)換為?上下文相關(guān)?的向量表征,后面每一個編碼器模塊都會進(jìn)一步細(xì)化這個上下文表征,直到最后一個編碼器模塊輸出最終的上下文相關(guān)編碼?X1:n?(如下圖深綠色所示)。
我們對?編碼器如何將輸入序列 "I want to buy a car EOS" 變換為上下文編碼序列
這一過程進(jìn)行一下可視化。與基于 RNN 的編碼器類似,基于 transformer 的編碼器也在輸入序列最后添加了一個 EOS,以提示模型輸入向量序列已結(jié)束?2。

上圖中的?基于 transformer?的編碼器由三個編碼器模塊組成。我們在右側(cè)的紅框中詳細(xì)列出了第二個編碼器模塊的前三個輸入向量:?x1,x2?及?x3。紅框下部的全連接圖描述了雙向自注意力機(jī)制,上面是兩個前饋層。如前所述,我們主要關(guān)注雙向自注意力機(jī)制。
可以看出,自注意力層的每個輸出向量?x′′i,?i∈1,…,7?都?直接?依賴于?所有?輸入向量?x′1,…,x′7。這意味著,單詞 “want” 的輸入向量表示?x′2?與單詞 “buy” (即?x′4) 和單詞 “I” (即?x′1) 直接相關(guān)。 因此,“want” 的輸出向量表征,?即?x′′2,是一個融合了其上下文信息的更精細(xì)的表征。
我們更深入了解一下雙向自注意力的工作原理。編碼器模塊的輸入序列?X′1:n?中的每個輸入向量?x′i?通過三個可訓(xùn)練的權(quán)重矩陣?Wq,Wv,Wk?分別投影至?key
?向量?ki、value
?向量?vi?和?query
?向量?qi?(下圖分別以橙色、藍(lán)色和紫色表示):
qi=Wqx′i,?vi=Wvx′i,?ki=Wkx′i,??i∈1,…n
請注意,對每個輸入向量?xi(?i∈i,…,n) 而言,其所使用的權(quán)重矩陣都是?相同?的。將每個輸入向量?xi?投影到?query
?、?key
?和?value
?向量后,將每個?query
?向量?qj(?j∈1,…,n) 與所有?key
?向量?k1,…,kn?進(jìn)行比較。哪個?key
?向量與?query
?向量?qj?越相似,其對應(yīng)的?value
?向量?vj?對輸出向量?x′′j?的影響就越重要。更具體地說,輸出向量?x′′j?被定義為所有?value
?向量的加權(quán)和?v1,…,vn?加上輸入向量?x′j。而各?value
?向量的權(quán)重與?qj?和各個?key
?向量?k1,…,kn?之間的余弦相似度成正比,其數(shù)學(xué)公式為?Softmax(K1:n?qj),如下文的公式所示。關(guān)于自注意力層的完整描述,建議讀者閱讀?這篇?博文或?原始論文。
好吧,又復(fù)雜起來了。我們以上例中的一個?query
?向量為例圖解一下雙向自注意層。為簡單起見,本例中假設(shè)我們的?基于 transformer?的解碼器只有一個注意力頭?config.num_heads = 1
?并且沒有歸一化層。

圖左顯示了上個例子中的第二個編碼器模塊,右邊詳細(xì)可視化了第二個輸入向量?x′2?的雙向自注意機(jī)制,其對應(yīng)輸入詞為 “want”。首先將所有輸入向量?x′1,…,x′7?投影到它們各自的?query
?向量?q1,…,q7?(上圖中僅以紫色顯示前三個?query
?向量),?value
?向量?v1,…,v7?(藍(lán)色) 和?key
?向量?k1,…,k7?(橙色)。然后,將?query
?向量?q2?與所有?key
?向量的轉(zhuǎn)置 (?即?K1:7?) 相乘,隨后進(jìn)行 softmax 操作以產(chǎn)生?自注意力權(quán)重?。 自注意力權(quán)重最終與各自的?value
?向量相乘,并加上輸入向量?x′2,最終輸出單詞 “want” 的上下文相關(guān)表征,?即?x′′2?(圖右深綠色表示)。整個等式顯示在圖右框的上部。?K1:7??和?q2?的相乘使得將 “want” 的向量表征與所有其他輸入 (“I”,“to”,“buy”,“a”,“car”,“EOS”) 的向量表征相比較成為可能,因此自注意力權(quán)重反映出每個輸入向量?x′j?對 “want” 一詞的最終表征?x′′2?的重要程度。
為了進(jìn)一步理解雙向自注意力層的含義,我們假設(shè)以下句子: “?房子很漂亮且位于市中心,因此那兒公共交通很方便?”。 “那兒”這個詞指的是“房子”,這兩個詞相隔 12 個字。在基于 transformer 的編碼器中,雙向自注意力層運算一次,即可將“房子”的輸入向量與“那兒”的輸入向量相關(guān)聯(lián)。相比之下,在基于 RNN 的編碼器中,相距 12 個字的詞將需要至少 12 個時間步的運算,這意味著在基于 RNN 的編碼器中所需數(shù)學(xué)運算與距離呈線性關(guān)系。這使得基于 RNN 的編碼器更難對長程上下文表征進(jìn)行建模。此外,很明顯,基于 transformer 的編碼器比基于 RNN 的編碼器-解碼器模型更不容易丟失重要信息,因為編碼的序列長度相對輸入序列長度保持不變,?即?len?(X1:n)=len(X1:n)=n,而 RNN 則會將?len((X1:n)=n?壓縮到?len(c)=1,這使得 RNN 很難有效地對輸入詞之間的長程依賴關(guān)系進(jìn)行編碼。
除了更容易學(xué)到長程依賴外,我們還可以看到 transformer 架構(gòu)能夠并行處理文本。從數(shù)學(xué)上講,這是通過將自注意力機(jī)制表示為?query
?、?key
?和?value
?的矩陣乘來完成的:
X′′1:n=V1:nSoftmax(Q1:n?K1:n)+X′1:n
輸出?X′′1:n=x′′1,…,x′′n?是由一系列矩陣乘計算和 softmax 操作算得,因此可以有效地并行化。請注意,在基于 RNN 的編碼器模型中,隱含狀態(tài)?c?的計算必須按順序進(jìn)行: 先計算第一個輸入向量的隱含狀態(tài)?x1; 然后計算第二個輸入向量的隱含狀態(tài),其取決于第一個隱含向量的狀態(tài),依此類推。RNN 的順序性阻礙了有效的并行化,并使其在現(xiàn)代 GPU 硬件上比基于 transformer 的編碼器模型的效率低得多。
太好了,現(xiàn)在我們應(yīng)該對:
a) 基于 transformer 的編碼器模型如何有效地建模長程上下文表征,以及
b) 它們?nèi)绾斡行У靥幚黹L序列向量輸入這兩個方面有了比較好的理解了。
現(xiàn)在,我們寫一個?MarianMT
?編碼器-解碼器模型的編碼器部分的小例子,以驗證這些理論在實踐中行不行得通。
1?關(guān)于前饋層在基于 transformer 的模型中所扮演的角色的詳細(xì)解釋超出了本文的范疇。Yun 等人 (2017)?的工作認(rèn)為前饋層對于將每個上下文向量?x′i?映射到目標(biāo)輸出空間至關(guān)重要,而單靠?自注意力?層無法達(dá)成這一目的。這里請注意,每個輸出詞元?x′?都經(jīng)由相同的前饋層處理。更多詳細(xì)信息,建議讀者閱讀論文。
2?我們無須將 EOS 附加到輸入序列,雖然有工作表明,在很多情況下加入它可以提高性能。相反地,基于 transformer 的解碼器必須把?BOS?作為第 0 個目標(biāo)向量,并以之為條件預(yù)測第 1 個目標(biāo)向量。
python
from transformers import MarianMTModel, MarianTokenizerimport torchtokenizer = MarianTokenizer.from_pretrained("Helsinki-NLP/opus-mt-en-de")model = MarianMTModel.from_pretrained("Helsinki-NLP/opus-mt-en-de")embeddings = model.get_input_embeddings()# create ids of encoded input vectorsinput_ids = tokenizer("I want to buy a car", return_tensors="pt").input_ids# pass input_ids to encoderencoder_hidden_states = model.base_model.encoder(input_ids, return_dict=True).last_hidden_state# change the input slightly and pass to encoderinput_ids_perturbed = tokenizer("I want to buy a house", return_tensors="pt").input_idsencoder_hidden_states_perturbed = model.base_model.encoder(input_ids_perturbed, return_dict=True).last_hidden_state# compare shape and encoding of first vectorprint(f"Length of input embeddings {embeddings(input_ids).shape[1]}. Length of encoder_hidden_states {encoder_hidden_states.shape[1]}")# compare values of word embedding of "I" for input_ids and perturbed input_idsprint("Is encoding for `I` equal to its perturbed version?: ", torch.allclose(encoder_hidden_states[0, 0], encoder_hidden_states_perturbed[0, 0], atol=1e-3))
輸出:
? ?Length of input embeddings 7. Length of encoder_hidden_states 7 ? ?Is encoding for `I` equal to its perturbed version?: False
我們比較一下輸入詞嵌入的序列長度 (?即?embeddings(input_ids)
,對應(yīng)于?X1:n) 和?encoder_hidden_states
?的長度 (對應(yīng)于X1:n)。同時,我們讓編碼器對單詞序列 “I want to buy a car” 及其輕微改動版 “I want to buy a house” 分別執(zhí)行前向操作,以檢查第一個詞 “I” 的輸出編碼在更改輸入序列的最后一個單詞后是否會有所不同。
不出意外,輸入詞嵌入和編碼器輸出編碼的長度,?即?len(X1:n)?和?len?(X1:n),是相等的。同時,可以注意到當(dāng)最后一個單詞從 “car” 改成 “house” 后,x1=“I”?的編碼輸出向量的值也改變了。因為我們現(xiàn)在已經(jīng)理解了雙向自注意力機(jī)制,這就不足為奇了。
順帶一提,?自編碼?模型 (如 BERT) 的架構(gòu)與?基于 transformer?的編碼器模型是完全一樣的。?自編碼?模型利用這種架構(gòu)對開放域文本數(shù)據(jù)進(jìn)行大規(guī)模自監(jiān)督預(yù)訓(xùn)練,以便它們可以將任何單詞序列映射到深度雙向表征。在?Devlin 等 (2018)?的工作中,作者展示了一個預(yù)訓(xùn)練 BERT 模型,其頂部有一個任務(wù)相關(guān)的分類層,可以在 11 個 NLP 任務(wù)上獲得 SOTA 結(jié)果。你可以從?此處?找到 ?? transformers 支持的所有?自編碼?模型。
敬請關(guān)注其余部分的文章。
英文原文:?https://hf.co/blog/encoder-decoder
原文作者: Patrick von Platen
譯者: Matrix Yao (姚偉峰),英特爾深度學(xué)習(xí)工程師,工作方向為 transformer-family 模型在各模態(tài)數(shù)據(jù)上的應(yīng)用及大規(guī)模模型的訓(xùn)練推理。
審校/排版: zhongdongy (阿東)