人工智能,一個貌似年輕但實際已經很有年頭的概念。
七年前,AlphaGo 走出了第一步,現在 ChatGPT 正在走第二步。
這里頭有兩個公司,DeepMind 和 OpenAI。
一個背后是谷歌,一個背后是微軟,似乎勢均力敵,好戲可期。
有人說 DeepMind 缺席這場盛宴,是否意味著最大輸家?這是否過于太以成敗論英雄了?
DeepMind 切入 LLM 相對較晚,但也有自己的技術優(yōu)勢。ChatGPT 用到的技術之一強化學習正是 DeepMind 的強項,只是之前應用于其他應用。
更何況 OpenAI 現在只是暫時領先,2023 才剛開始。
另外,不要忘了,ChatGPT 背后一個核心工作 Transformer,正是谷歌 2017 年的力作。
對今天的主角就是它,變形金剛。
哦不,拿錯道具了,是變換器。不過一般不翻譯,就叫 Transformer。
Generative Pre-trained Transformer
,即生成式預訓練變換器。△ 科幻電影《Her》
概括地講,自然語言處理 NLP 領域近年來有兩次大的研究范式的轉換。
第一次范式轉換是從深度學習到兩階段預訓練模型
主要是 Bert 和 GPT 的出現,解決了深度學習模型在 NLP 領域的兩個主要問題,即數據不足和特征抽取能力不強。這次范式轉換帶來的影響大概有幾個方面:
不同研究方向技術路線的統(tǒng)一。比如自然語言理解類任務和自然語言生成類任務,都可以用兩階段預訓練模型作為基礎框架,只需要在后面加上一些任務相關的模塊即可。典型的自然語言理解類任務包括文本分類、句子關系、情感傾向等,這種任務本質上都是分類任務,即模型根據輸入文本預測文本類別。自然語言生成也包含很多研究子方向,比如聊天、摘要、問答和翻譯等。生成類任務的特點是給定輸入文本,模型要生成一串文本。兩者差異主要體現在輸入輸出形式上。自從 Bert、GPT 模型誕生后,特征抽取器都逐漸從 LSTM、CNN 統(tǒng)一到 Transformer 上。
第二次范式從預訓練模型走向通用人工智能 AGI
第一次范式大致完成了技術上統(tǒng)一,然后朝著通用性人工智能發(fā)展??梢詫?ChatGPT 的出現作為第二次范式轉換的開端。這次范式轉變可以讓 LLM 成為人機交互接口,讓語言模型適配人以自然語言形式的命令表達方式,而不是反過來讓人去適配語言模型的指令模式。有了這一步,人類邁向 AGI 的路子似乎變得不再虛無縹緲了。
這里主要提兩個技術,即 Prompt Tuning
和 Instruction Tuning
。Prompt Tuning
針對每個任務單獨生成 prompt 模板,然后在每個任務上進行微調與評估,其中預訓練模型參數是凍結的。Prompt 方法的發(fā)展思路,通過完形填空的方式發(fā)掘語言模型的能力,prompt 方法比傳統(tǒng)的 finetune 好。LLM 已經被證明可以很好的應用到小樣本學習任務,例如 OpenAI 提出的 GPT-3 在小樣本(few-shot)場景上取得了不錯的表現,但是在零樣本(zero-shot)學習任務中表現不是很突出。
為了進一步提升模型的泛化能力和通用能力,誕生了一種新范式,即 Instruction Tuning
,通過以 Instrcution 為指導的大量任務進行學習,提升在未知任務的性能。Instruction Tuning
是一種新興的 NLP 技術范式,它利用自然語言指令來激發(fā)語言模型的理解能力,從而實現在未見過的任務上的零樣本或少樣本表現。Instruction Tuning
與 Prompt Tuning
不同,后者是通過給語言模型提供一些特定的輸入格式或提示來引導其產生正確的輸出。Instruction Tuning
更加靈活和通用,它可以讓語言模型根據不同的指令來執(zhí)行不同的任務,而無需為每個任務單獨存儲模型權重。Instruction Tuning
也可以提高語言模型在對話任務上的泛化能力。
本文主要針對第一次范式中的核心技術 Transformer 展開介紹。為了讓沒有這方面基礎的只有高中知識的讀者也可以試著學習,我們找到了一篇外網講得非常好的文章[1],以饗讀者。
Transformers 在 2017 年的這篇論文中作為一種序列轉換工具被引入,即將一個符號序列轉換為另一個符號序列。一個典型的例子是翻譯,如英語到德語。它也被修改為執(zhí)行序列填充, 給定一個開始提示,以相同的方式和風格進行。它們已迅速成為自然語言處理研究和產品開發(fā)不可或缺的工具。
我們的第一步是將所有單詞轉換為數字,以便我們可以對它們進行數學運算。
想象一下,我們的目標是創(chuàng)建響應我們的語音命令的計算機。我們的工作是構建將一系列聲音轉換為一系列單詞的轉換器。
我們首先選擇我們的詞匯表,即我們將在每個序列中使用的符號集合。在我們的例子中,將有兩組不同的符號,一組用于表示人聲的輸入序列,另一組用于表示單詞的輸出序列。
現在,假設我們正在使用英語。英語中有數萬個單詞,也許還有幾千個單詞涵蓋了計算機專用術語。這將使我們的詞匯量達到十萬中的大部分。將單詞轉換為數字的一種方法是從 1 開始計數,然后為每個單詞分配一個編號。然后可以將單詞序列表示為數字列表。
例如,考慮一種詞匯量為三個的微型語言:files、find 和 my。每個單詞都可以換成一個數字,也許 files = 1、find = 2 和 my = 3。那么由單詞序列 [find , my , files] 組成的句子 “Find my files” 可以表示為數字序列 [2, 3, 1]。
這是將符號轉換為數字的一種完全有效的方法,但事實證明還有另一種格式更容易讓計算機使用,即單熱編碼。在 one-hot 編碼中,一個符號由一個大部分為零的數組表示,與詞匯表的長度相同,只有一個元素的值為 1。數組中的每個元素對應一個單獨的符號。
考慮 one-hot 編碼的另一種方法是,每個單詞仍然被分配了自己的編號,但現在該編號是數組的索引。這是我們上面的示例,采用單熱編碼。
因此,“Find my files”這句話變成了一系列一維數組,將它們擠在一起后,開始看起來像一個二維數組。
注意,我將交替使用術語“一維數組”和“向量”?!岸S數組”和“矩陣”也是如此。
關于 one-hot 表示的一個真正有用的事情是它可以讓我們計算點積。這些也有其他令人生畏的名稱,如內積和標量積。要獲得兩個向量的點積,請將它們對應的元素相乘,然后將結果相加。
當我們使用獨熱詞表示時,點積特別有用。任何 one-hot 向量與自身的點積都是 1。
并且任何 one-hot 向量與任何其他 one-hot 向量的點積為零。
前兩個示例展示了如何使用點積來衡量相似性。作為另一個例子,考慮一個值向量,它表示具有不同權重的單詞組合。一個 one-hot 編碼的詞可以用點積與它進行比較,以顯示該詞的表示有多強。
點積是矩陣乘法的組成部分,矩陣乘法是組合一對二維數組的一種非常特殊的方法。我們稱這些矩陣中的第一個為 A,第二個為 B。最簡單的情況,當 A 只有一行,B 只有一列時,矩陣乘法的結果就是兩者的點積。
請注意 A 中的列數和 B 中的行數如何需要相同才能使兩個數組匹配并計算點積。
當 A 和 B 開始增長時,矩陣乘法開始變幻莫測。要處理 A 中的多行,請分別對 B 的每一行進行點積。答案的行數與 A 一樣多。
當 B 占用更多列時,將每列與 A 進行點積并將結果堆疊在連續(xù)的列中。
現在我們可以將其擴展為將任意兩個矩陣相乘,只要 A 中的列數與 B 中的行數相同即可。結果將具有與 A 相同的行數和與 B 相同的列數。
注意矩陣乘法在這里如何充當查找表。我們的 A 矩陣由一堆單熱向量組成。它們分別在第一列、第四列和第三列中。當我們完成矩陣乘法時,這用于按順序拉出 B 矩陣的第一行、第四行和第三行。這種使用 one-hot 向量提取矩陣特定行的技巧是 transformer 工作原理的核心。
我們可以暫時擱置矩陣,然后回到我們真正關心的問題,即單詞序列。想象一下,當我們開始開發(fā)我們的自然語言計算機接口時,我們只想處理三個可能的命令:
Show me my directories please.
Show me my files please.
Show me my photos please.
我們的詞匯量現在是七個:{directories, files, me, my, photos, please, show}。
表示序列的一種有用方法是使用轉移模型。對于詞匯表中的每個單詞,它會顯示下一個單詞可能是什么。如果用戶一半時間詢問照片,30% 時間詢問文件,其余時間詢問目錄,轉移模型將如下所示。遠離任何單詞的轉換總和總是加起來為 1。
這種特殊的轉移模型稱為馬爾可夫鏈,因為它滿足馬爾可夫性質,即下一個單詞的概率僅取決于最近的單詞。更具體地說,它是一階馬爾可夫模型,因為它只關注最近的單個單詞。如果它考慮最近的兩個詞,它將是二階馬爾可夫模型。
事實證明,馬爾可夫鏈可以方便地用矩陣形式表示。使用我們在創(chuàng)建 one-hot 向量時使用的相同索引方案,每一行代表我們詞匯表中的一個詞。每一列也是如此。矩陣轉移模型將矩陣視為查找表。找到與你感興趣的詞相對應的行。每列中的值顯示下一個出現該詞的概率。因為矩陣中每個元素的值代表一個概率,所以它們都會落在 0 和 1 之間。因為概率總和為 1,所以每行中的值總和為 1。
在這里的轉移矩陣中,我們可以清楚地看到我們三個句子的結構。幾乎所有的轉移概率都是 0 或 1。馬爾可夫鏈中只有一處發(fā)生分支。在 my 之后,單詞 directories、files 或 photos 可能會出現,每一個都有不同的概率。除此之外,對于接下來會出現哪個詞沒有任何不確定性。這種確定性通過轉移矩陣中大部分為 1 和 0 來反映。
我們可以重新審視我們的技巧,即使用矩陣乘法與獨熱向量來提取與任何給定單詞相關的轉移概率。例如,如果我們只是想隔離哪個單詞出現在 my 之后的概率,我們可以創(chuàng)建一個表示單詞 my 的獨熱向量,并將它乘以我們的轉移矩陣。這會拉出相應的行,并向我們展示下一個單詞的概率分布。
僅根據當前單詞預測下一個單詞很困難。這就像在給出第一個音符后預測曲調的其余部分。如果我們至少能得到兩個音符,我們的機會就會大很多。
我們可以看到它是如何在我們的計算機命令的另一種玩具語言模型中工作的。我們希望這個人只會看到兩個句子,比例為 40/60。
Check whether the battery ran down please.
Check whether the program ran please.
馬爾可夫鏈為此說明了一個一階模型。
在這里我們可以看到,如果我們的模型查看最近的兩個詞,而不是一個,它可以做得更好。當它遇到 battery run 時,它知道下一個詞是 down,當它看到 program run 時,它知道下一個詞是 please。這消除了模型中的一個分支,減少了不確定性并增加了信心。回顧兩個詞將其變成二階馬爾可夫模型。它提供了更多的上下文來預測下一個單詞。
為了突出兩者之間的區(qū)別,這里是一階轉移矩陣,
這是二階轉移矩陣。
請注意二階矩陣如何為每個單詞組合(其中大部分未在此處顯示)單獨一行。這意味著如果我們從
這給我們帶來了更多信心:二階模型中個數較多,分數較少。只有一行包含分數,我們模型中的一個分支。直覺上,查看兩個單詞而不是一個單詞可以提供更多上下文,更多信息可以作為下一個單詞猜測的基礎。
當我們只需要回顧兩個詞來決定下一個詞時,二階模型效果很好。當我們不得不進一步回顧時呢?想象一下我們正在構建另一個語言模型。這個只需要代表兩個句子,每個句子出現的可能性相同。
Check the program log and find out whether it ran please.
Check the battery log and find out whether it ran down please.
在這個例子中,為了確定哪個詞應該跟在 ran 之后,我們必須回顧過去的 8 個詞。如果我們想改進我們的二階語言模型,我們當然可以考慮三階和更高階模型。然而,由于詞匯量很大,這需要結合計算力才能執(zhí)行。八階模型的簡單實現會有
相反,我們可以引入一些技巧并設計二階模型,但考慮最近單詞與之前出現的每個單詞的組合。它仍然是二階的,因為我們一次只考慮兩個詞,但它允許我們進一步回溯并捕獲長程依賴。這種帶有跳過的二階模型與完整的無數階模型之間的區(qū)別在于,我們丟棄了大部分詞序信息和前面詞的組合。剩下的還是蠻給力的。
馬爾可夫鏈現在完全讓我們失望了,但我們仍然可以表示每對前面的單詞和后面的單詞之間的聯系。在這里,我們放棄了數字權重,而是只顯示與非零權重相關聯的箭頭。較大的權重用較粗的線表示。
這是它在轉換矩陣中的樣子。
此視圖僅顯示與預測 ran 之后的單詞相關的行。它顯示了詞匯表中每個其他單詞之前出現的最近單詞 ran 的實例。僅顯示相關值,所有空單元格都是零。
首先變得明顯的是,當試圖預測 ran 之后的單詞時,我們不再只看一行,而是看一整套。我們現在已經離開了馬爾可夫。每行不再代表序列在特定點的狀態(tài)。相反,每一行代表許多特征中的一個,這些特征可以描述特定點的序列。最近的單詞與之前出現的每個單詞的組合構成了適用行的集合,可能是一個大集合。由于這種意義的變化,矩陣中的每個值不再代表概率,而是投票。將對投票進行匯總和比較以預測下一個單詞。
接下來變得明顯的是,大多數特征都無關緊要。大多數單詞都出現在兩個句子中,因此它們已被看到的事實無助于預測接下來會發(fā)生什么。它們都具有 0.5 的值。僅有的兩個例外是 battery 和 program。它們有一些 1 和 0 的權重。特征 battery, ran 表示 ran 是最近的詞,并且 battery 出現在句子的較早位置。此特征的權重為 1 與 down 相關聯,權重為 0 與 please 相關聯。同樣,特征 program, ran 具有相反的一組權重。這種結構表明,句子中較早出現的這兩個詞對于預測下一個詞是決定性的。
要將這組詞對特征轉換為對下一個詞的估計,需要對所有相關行的值求和。按列相加,序列 Check the program log and find out whether it ran 為所有單詞生成的總和為 0,除了 4 代表down和 5 代表please。序列 Check the battery log and find out whether it ran 相同,除了 5 表示 down 和 4 表示please。通過選擇投票總數最高的單詞作為下一個單詞預測,該模型為我們提供了正確的答案,盡管它具有八個單詞的深度依賴關系。
更仔細地考慮,這是不令人滿意的。4 票和 5 票的總票數相差不大。這表明該模型并不像它應該的那樣自信。在更大、更有組織的語言模型中,很容易想象這種微小的差異可能會在統(tǒng)計噪聲中丟失。
我們可以通過清除所有無信息的特征投票來加強預測。除了電池,運行和程序,運行。記住這一點很有幫助,我們通過將相關行與一個向量相乘來顯示當前哪些特征處于活動狀態(tài),從而將相關行從轉移矩陣中拉出來。到目前為止,對于這個例子,我們一直在使用此處顯示的隱含特征向量。
每個特征都為 1,該特征是 ran 與其前面的每個單詞的組合。它后面的任何詞都不會包含在特征集中。在下一個單詞預測問題中,這些還沒有出現,因此使用它們預測接下來會發(fā)生什么是不合理的。并且這不包括所有其他可能的單詞組合。對于這個例子,我們可以安全地忽略這些,因為它們都將為零。
為了改善我們的結果,我們還可以通過創(chuàng)建掩膜將無用的特征強制消除掉,即設為零。它是一個充滿了 1 的向量,除了你想要隱藏或屏蔽的位置,這些位置被設置為零。在我們的例子中,我們想屏蔽除了 battery, ran 和 program, ran 之外的所有內容,這是僅有的兩個有用的特征。
為了應用 mask,我們將兩個向量逐個元素相乘。未屏蔽位置中的任何特征活動值都將乘以 1 并保持不變。屏蔽位置中的任何特征活動值都將乘以 0,因此強制為 0。
mask 具有隱藏大量轉移矩陣的效果。它隱藏了 run 與除 battery 和 program 之外的所有內容的組合,只留下重要的特征。
在屏蔽了無用的特征之后,下一個詞的預測變得更強。當單詞 battery 出現在句子的前面時,預測 ran 之后的單詞 down 的權重為 1,please 的權重為 0。原本 25% 的權重差異現在變成了無窮大百分比的差異。毫無疑問接下來是什么詞。當 program 前面出現時,同樣強烈的預測也會發(fā)生。
這種選擇性掩蔽的過程是關于 transformer 的原始論文標題中提到的 attention。到目前為止,我們所描述的只是論文中如何實現注意力的近似值。它捕獲了重要的概念,但細節(jié)有所不同,稍后會縮小差距。
用 selective-second-order-with-skips 模型來思考 transformer 的作用是一個很有意思的思路,至少在解碼器端是這樣。它大致捕捉到了像 OpenAI 的 GPT-3 這樣的生成語言模型正在做什么。它并沒有講述完整的故事,但它代表了故事的中心要旨。
接下來的部分將更多地介紹這種直觀的解釋與 transformer 的實現方式之間的差距。這些主要是由三個實際考慮因素驅動的。
計算機特別擅長矩陣乘法。整個行業(yè)都圍繞著專門為快速矩陣乘法構建計算機硬件。任何可以表示為矩陣乘法的計算都可以變得非常高效。你不妨設想一下,這是一輛子彈頭列車,如果你能把行李放進去,它會很快帶你去你想去的地方。
每個步驟都需要是可微分的。到目前為止,我們一直在處理玩具示例,并且可以手動選擇所有轉移概率和掩碼值,即模型的參數。在實踐中,這些必須通過反向傳播來學習,這取決于每個計算步驟都是可微分的。這意味著對于參數的任何微小變化,我們都可以計算模型誤差或損失的相應變化。
梯度需要平滑且條件良好。所有參數的所有導數的組合就是損失梯度。在實踐中,要使反向傳播表現良好,需要平滑的梯度,也就是說,當你在任何方向上做小步時,斜率不會很快改變。當梯度條件良好時,它們的表現也會好得多,也就是說,它在一個方向上不會比另一個方向大得多。如果將損失函數想象成一幅風景,那么大峽谷就是一處條件差的風景。根據你是沿著底部還是向上行駛,將有非常不同的坡度。相比之下,經典 Windows 屏幕保護程序的連綿起伏的丘陵將具有良好的梯度效果。
如果構建神經網絡的科學是創(chuàng)建可微分的積木塊,那么它們的藝術就是以梯度不會變化太快且在每個方向上大致相同的方式堆疊各個部分。
通過計算每個單詞對到下一個單詞的轉移在訓練中發(fā)生的頻率,可以直接構建特征權重,但注意 mask 則不然。到目前為止,我們已經憑空提取了 mask 向量。Transformer 如何找到相關 mask 很重要。使用某種查找表是很自然的,但現在我們正努力將所有內容表示為矩陣乘法。我們可以使用我們上面介紹的相同查找方法,將每個單詞的 mask 向量堆疊到一個矩陣中,并使用最近單詞的獨熱表示來提取相關 mask。
在顯示 mask 向量集合的矩陣中,為了清楚起見,我們只顯示了我們試圖提取的那個 mask 向量。
我們終于到了可以開始結合論文的地步了。此 mask 查找由注意力方程中的
查詢
到目前為止,我們一直在處理的另一個步驟是轉移矩陣的構造。我們已經清楚了邏輯,但不清楚如何用矩陣乘法來實現。
一旦我們得到了注意力步驟的結果,一個向量包含了最近的詞和它之前的一小部分詞,我們需要將其轉化為特征,每個特征都是一個詞對。注意 mask 為我們提供了所需的原材料,但它并沒有構建那些詞對特征。為此,我們可以使用單層全連接神經網絡。
為了了解神經網絡層如何創(chuàng)建這些詞對,我們將手工制作一個看看。它將被人為地清理和程式化,其權重與實際中的權重沒有任何相似之處,但它將展示神經網絡如何具有構建這兩個詞對特征所必需的表達能力。為了保持小而干凈,將只關注此示例中的三個參與詞,電池、程序、運行。
在上面的層圖中,我們可以看到權重如何將每個單詞的存在和不存在組合成一個特征集合。這也可以用矩陣形式表示。
它可以通過矩陣乘法與表示到目前為止所見單詞集合的向量來計算。
元素 battery 和 ran 為 1,元素 program 為 0,而元素 bias 始終為 1,它是神經網絡的一個特征。通過矩陣乘法,代表 battery, ran 的元素為 1 ,代表 program, ran 的元素為 -1 。另一種情況的結果是類似的。
計算這些單詞組合特征的最后一步是應用線性修正單元 (ReLU) 非線性。這樣做的效果是用零替換任何負值。這會清除這兩個結果,因此它們表示每個單詞組合特征的存在(1)或不存在(0)。
有了這些操作,我們終于有了一個基于矩陣乘法的方法來創(chuàng)建多詞特征。雖然我最初聲稱這些由最近的詞和一個較早的詞組成,但仔細觀察這種方法就會發(fā)現它也可以構建其他特征。當特征創(chuàng)建矩陣被學習時,而不是硬編碼,其他結構也可以被學習。即使在這個玩具示例中,也沒有什么可以阻止創(chuàng)建像 battery、program、ran 這樣的三個詞組合。如果這種組合足夠普遍,它可能最終會被表示出來。沒有任何方法表明這些單詞的出現順序(至少現在還沒有),但我們絕對可以利用它們的同時出現來進行預測。甚至可以使用忽略最近單詞的單詞組合,例如 battery, program。這些和其他類型的特征可能是在實踐中創(chuàng)建的,暴露了我在聲稱 transformers 是一個選擇性二階帶跳過序列模型時所做的過度簡化。它的細微差別遠不止于此,現在你可以準確地看到細微差別是什么。這不會是我們最后一次改變故事以融入更多微妙之處。
在這種形式下,多詞特征矩陣準備好再進行一次矩陣乘法,即我們上面開發(fā)的帶有跳躍的二階序列模型??偟膩碚f,如下所示的
特征創(chuàng)建矩陣
乘法,轉移矩陣
乘法的操作序列是應用注意力后緊接著應用的前饋處理步驟。論文中的等式 2 以簡明的數學公式顯示了這些步驟。
該論文的圖 1 架構圖顯示了這些作為前饋塊(Feed Forward block)集中在一起。
到目前為止,我們只討論了下一個單詞預測。為了讓解碼器生成一個長序列,我們需要添加一些片段。第一個是提示(prompt),即一些示例文本,它是為 Transformer 提供運行開始和構建其余序列的上下文。它被送入解碼器,即上圖中右側的列,其中標記為“輸出(右移)”。選擇給出有趣序列的提示本身就是一門藝術,稱為提示工程。這也是人類修改自己的行為來支持算法的一個很好的例子,而不是反過來。
一旦解碼器有一個部分序列可以開始,它就會進行前向傳遞。最終結果是一組預測的單詞概率分布,序列中的每個位置都有一個概率分布。在每個位置,分布顯示了詞匯表中每個下一個單詞的預測概率。我們不關心序列中每個已建立單詞的預測概率,因為他們已經在了。我們真正關心的是提示結束后下一個單詞的預測概率。有幾種方法可以選擇該詞應該是什么,但最直接的方法稱為貪心算法,即選擇概率最高的詞。
然后將新的下一個單詞添加到序列中,替換解碼器底部的 “Outputs”,然后重復該過程,直到你想停下來為止。
我們還沒有完全準備好詳細描述的部分是另一種形式的掩蔽,確保當 transformer 做出預測時它只看后面,而不是前面。它應用于標記為“Masked Multi-Head Attention”的塊中。當我們可以更清楚它是如何完成時,我們將在稍后重新討論它。
正如我們到目前為止所描述的,transformer 太大了。對于假設為 50,000 的詞匯量
問題不僅僅是矩陣的大小。為了建立一個穩(wěn)定的轉移語言模型,我們必須至少多次提供說明每個潛在序列的訓練數據。這將遠遠超過即使是最有野心的訓練數據集的容量。
那怎么辦呢?幸運的是,這兩個問題都有一個解決方法,即嵌入。
在一種語言的獨熱表示中,每個詞都有一個向量元素。對于大小為
在嵌入中,這些詞點全部被獲取并重新排列(投影,用線性代數術語)到低維空間中。例如,上圖顯示了它們在二維空間中的樣子。現在,我們不再需要
一個好的嵌入將具有相似含義的詞組合在一起。使用嵌入的模型在嵌入空間中學習模式。這意味著無論它學會用一個詞做什么,都會自動應用到它旁邊的所有詞上。這具有減少所需訓練數據量的額外好處。每個例子都提供了一點點學習,可以應用于整個單詞鄰域。
在這個插圖中,我試圖通過將重要組件放在一個區(qū)域(電池、日志、程序)、介詞放在另一個區(qū)域(向下、出去)和靠近中心的動詞(檢查、查找、運行)來展示這一點。在實際嵌入中,分組可能不是那么清晰或直觀,但基本概念是相同的。行為相似的單詞之間的距離較小。
嵌入大大減少了所需的參數數量。然而,嵌入空間中的維度越少,原始單詞的信息就會被丟棄得越多。語言的豐富性仍然需要相當多的空間來布置所有重要的概念,以免它們互相踩到腳趾。通過選擇嵌入空間的大小,我們可以在計算負載與模型精度之間進行權衡。
將單詞從其獨熱表示投影到嵌入空間涉及矩陣乘法。投影是矩陣最擅長的。從具有 1 行和
這個例子展示了一個 one-hot 向量,例如代表 battery,如何提取與其關聯的行,其中包含單詞在嵌入空間中的坐標。為了使關系更清晰,one-hot 向量中的 0 被省略,所有其他未從投影矩陣中拉出的行也是如此。完整的投影矩陣是密集的,每一行都包含與之關聯的單詞的坐標。
投影矩陣可以將 one-hot 詞匯向量的原始集合轉換為你想要的任何維度空間中的任何配置。最大的技巧是找到一個有用的投影,既將相似的詞組合在一起,又能有足夠的維度來分散它們。對于常見的語言,比如英語,有一些不錯的預計算嵌入。此外,與 transformer 中的其他所有內容一樣,它可以在訓練期間學習。
在原始論文的圖 1 架構圖中,這里是嵌入發(fā)生的地方。
到目前為止,我們假設單詞的位置被忽略,至少對于最近單詞之前的任何單詞都是如此?,F在我們開始使用位置嵌入來解決這個問題。
有幾種方法可以將位置信息引入我們的嵌入式單詞表示中,但在原始 transformer 中采用的方法是添加一個沿圓周擺動的機制。
單詞在嵌入空間中的位置充當圓心。根據它在單詞序列中的位置,向它添加一個擾動。對于每個位置,單詞以不同的角度轉動相同的距離,從而當在序列中移動時形成圓形圖案。序列中彼此靠近的詞具有相似的擾動,但相距較遠的詞將在不同方向上受到擾動。
由于圓是二維圖形,表示圓形擺動需要修改嵌入空間的二維。如果嵌入空間包含兩個以上的維度(幾乎總是如此),則在所有其他維度對中重復圓形擺動,但具有不同的角頻率,也就是說,在每種情況下,它在每個維度中掃出不同的旋轉次數。在某些維度對中,擺動會掃過圓的許多旋轉。在其他對中,它只會掃過一小部分旋轉。所有這些不同頻率的圓形擺動的組合可以很好地表示單詞在序列中的絕對位置。
這里是試圖以直覺方式去了解為什么會這樣。它似乎以一種不會破壞單詞和注意力之間學習關系的方式將位置信息添加到組合中。為了更深入地了解數學和含義,我推薦 Amirhossein Kazemnejad 的位置編碼教程。
在規(guī)范架構圖中,這些塊顯示了位置代碼的生成及其對嵌入詞的添加。
嵌入單詞使它們的使用效率大大提高,但是一旦聚會結束,它們就需要從原始詞匯表中轉換回單詞。去嵌入的完成方式與嵌入的方式相同,即從一個空間到另一個空間的投影,同樣也是矩陣乘法。
去嵌入矩陣的形狀與嵌入矩陣相同,但行數和列數翻轉了。行數是我們要轉換的空間的維度。在我們一直使用的例子中,它是我們嵌入空間的大小,2。列數是我們要轉換到的空間的維度 — 完整詞匯表的獨熱表示的大小,在我們的示例中為 13。
良好的去嵌入矩陣中的值不像嵌入矩陣中的值那樣易于說明,但效果相似。當表示單詞程序的嵌入向量乘以去嵌入矩陣時,相應位置的值很高。然而,由于投影到更高維空間的工作方式,與其他詞相關的值往往不會為零。嵌入空間中最接近程序的詞也將具有中高值。其他詞的價值接近于零。并且可能會有很多帶有負值的詞。詞匯空間中的輸出向量將不再是獨熱或稀疏的。它將是密集的,幾乎所有值都不為零。
沒關系。我們可以通過選擇與最高值關聯的詞來重新創(chuàng)建獨熱向量。此操作也稱為 argmax,即給出最大值的參數(元素)。如上所述,這就是如何進行貪心序列補全。這是一個很棒的一關,但我們可以做得更好。
如果一個嵌入很好地映射到幾個單詞,我們可能不想每次都選擇最好的一個。它可能只是比其他選擇好一點點,添加一點多樣性可以使結果更有趣。此外,有時在確定最終選擇之前先看幾個詞并考慮句子可能的所有方向也很有用。為了做到這些,我們必須首先將我們的去嵌入結果轉換為概率分布。
argmax 函數在最高值取勝的意義上是“困難的”,即使它僅比其他值無限大。如果我們想同時考慮多種可能性,最好使用我們從 softmax 獲得的“軟”最大值函數。要獲得向量中值
由于三個原因,softmax 在這里很有用。首先,它將我們的去嵌入結果向量從任意一組值轉換為概率分布。作為概率,比較不同單詞被選中的可能性變得更容易,如果我們想進一步展望未來,甚至可以比較多單詞序列的可能性。
其次,它使頂部附近的區(qū)域變薄。如果一個詞的得分明顯高于其他詞,softmax 會夸大這種差異,使其看起來幾乎像 argmax,獲勝值接近 1,而所有其他詞接近 0。但是,如果有幾個單詞都接近頂部,它會將它們全部保留為極有可能的結果,而不是人為地壓倒接近第二名的結果。
第三,softmax 是可微分的,這意味著我們可以計算結果的每個元素將發(fā)生多少變化,給定任何輸入元素的微小變化。這允許我們將它與反向傳播一起使用來訓練我們的變壓器。
去嵌入變換(如下面的線性塊所示)和 softmax 函數一起完成了去嵌入過程。
現在我們已經接受了投影(矩陣乘法)和空間(向量大?。?/span>的概念,我們可以重新審視核心注意力機制。如果我們可以更具體地了解每個階段的矩陣形狀,將有助于闡明算法。有一個重要數字的簡短列表。
原始輸入矩陣的構造方法是從句子中獲取每個詞的獨熱表示,并將它們堆疊起來,使每個獨熱向量都是它自己的行。生成的輸入矩陣有
如前所述,嵌入矩陣有
我們可以通過 transformer 跟蹤矩陣形狀的變化,作為跟蹤正在發(fā)生的事情的一種方式。在初始嵌入之后,位置編碼是相加的,而不是相乘的,所以它不會改變事物的形狀。然后嵌入的詞序列進入注意力層,并以相同的形狀從另一端出來。(我們稍后會回到這些的內部工作原理。)最后,去嵌入將矩陣恢復到其原始形狀,為序列中每個位置的詞匯表中的每個單詞提供概率。
終于到了面對我在第一次解釋注意力機制時所做的一些簡單假設的時候了。單詞表示為密集嵌入向量,而不是獨熱向量。注意力不只是 1 或 0、開或關,還可以是介于兩者之間的任何位置。為了讓結果落在 0 和 1 之間,我們再次使用 softmax 技巧。它具有強制所有值位于我們的 [0, 1] 注意力范圍內的雙重好處,它有助于強調最高值,同時積極擠壓最小值。這是我們之前在解釋模型的最終輸出時利用的差分 almost-argmax 行為。
關注 softmax 函數的一個復雜結果是它會傾向于關注單個元素。這是我們以前沒有考慮過的限制。有時在預測下一個詞時記住前面的幾個詞是很有用的,而 softmax 剝奪了我們這一點。這是模型的問題。
解決方案是讓多個不同的注意力實例或頭腦同時運行。這讓 transformer 在預測下一個詞時同時考慮幾個先前的詞。它帶回了我們在將 softmax 引入圖片之前所擁有的力量。
不幸的是,這樣做確實會增加計算量。計算注意力已經是大部分工作,我們只是將它乘以我們想要使用的頭數。為了解決這個問題,我們可以重新使用將所有內容投影到低維嵌入空間的技巧。這縮小了所涉及的矩陣,從而大大減少了計算時間。
要了解結果如何,我們可以繼續(xù)查看矩陣形狀。通過多頭注意塊的脈絡來追蹤矩陣形狀需要三個以上的數字。
每個注意力頭的結果與
簡明扼要地說明了所有這些。
我們已經完成了上面注意力的概念說明。實際的實現有點混亂,但我們早先的直覺仍然有幫助。查詢和鍵不再容易檢查和解釋,因為它們都被投射到它們自己的特殊子空間中。在我們的概念圖中,查詢矩陣中的一行代表詞匯空間中的一個點,感謝 one-hot 表示,它代表一個且僅一個詞。在它們的嵌入形式中,查詢矩陣中的一行代表嵌入空間中的一個點,該點將靠近一組具有相似含義和用法的詞。概念圖將一個查詢詞映射到一組鍵,這些鍵又過濾掉所有未被關注的值。實際實現中的每個注意力頭將一個查詢詞映射到另一個低維嵌入空間中的一個點。結果是注意力變成了詞組之間的關系,而不是單個詞之間的關系。它利用語義相似性(嵌入空間中的接近性)來概括它對相似詞的了解。
通過注意力計算跟蹤矩陣的形狀有助于跟蹤它在做什么。
查詢和鍵矩陣
理解這組計算的一個棘手部分是要記住,它正在為我們輸入序列的每個元素、我們句子中的每個單詞計算注意力,而不僅僅是最近的單詞。它還在計算對前面單詞的注意力。我們并不真正關心這些,因為他們的下一個詞已經被預測和確定。它還在計算未來單詞的注意力。這些目前還沒有多大用處,因為它們太過遙遠,而且它們的直接前任還沒有被選中。但是這些計算可以通過間接路徑影響對最近單詞的注意力,因此我們將它們全部包括在內。只是當我們走到最后并計算序列中每個位置的單詞概率時,
Mask 塊引入強制約束,使得對于這種序列填充任務中后面的單詞是不可見的。它避免了從虛構的未見詞中引入任何奇怪錯誤。它粗糙而有效,手動將對所有超過當前位置的單詞的注意力設置為負無窮大。在 The Annotated Transformer 中,一個對逐行顯示 Python 實現的論文非常有用的伴侶,掩碼矩陣是可視化的。紫色單元格顯示不允許注意的地方。每行對應于序列中的一個元素。允許第一行關注其自身(第一個元素),但之后什么都不關注。允許最后一行處理自身(最后一個元素)和之前的所有內容。掩碼是
注意力實現方式的另一個重要區(qū)別是,它利用單詞在序列中呈現的順序,并且將注意力表示為位置到位置關系,而不是單詞到單詞的關系。這在其
注意力是 transformer 所做的最基本的部分。它是核心機制,我們現在已經遍歷了它一個非常具體的層次。從這里開始的一切都是使其正常工作所必需的管道。它是讓注意力拉動我們繁重的工作量的其余部分。
我們還沒有解釋的一件事情是跳躍連接。這些發(fā)生在多頭注意塊周圍,以及標記為“添加和規(guī)范”的塊中的元素明智的前饋塊周圍。在跳過連接中,輸入的副本被添加到一組計算的輸出中。注意塊的輸入被添加回其輸出。元素前饋塊的輸入被添加到它的輸出。
跳躍連接有兩個目的。
首先是它們有助于保持梯度平滑,這對反向傳播有很大幫助。注意力是一個過濾器,這意味著當它正常工作時,它會阻止大部分試圖通過它的東西。這樣做的結果是,如果許多輸入碰巧落入被阻塞的通道,那么許多輸入的微小變化可能不會對輸出產生太大變化。這會在平坦的梯度中產生死點,但仍然離谷底不遠。這些鞍點和脊線是反向傳播的重要觸發(fā)點。跳躍連接有助于解決這些問題。在注意力的情況下,即使所有的權重都為零并且所有的輸入都被阻止,跳躍連接會將輸入的副本添加到結果中,并確保任何輸入的微小變化仍然會在結果中產生明顯的變化。這可以防止梯度下降卡在遠離好的解決方案的地方。
自 ResNet 圖像分類器問世以來,跳躍連接變得流行,因為它們可以提高性能。它們現在是神經網絡架構中的標準功能。在視覺上,我們可以通過比較有和沒有跳躍連接的網絡來看到跳躍連接的效果。下圖顯示了具有和不具有跳躍連接的 ResNet。當使用跳躍連接時,損失函數山丘的斜率更加溫和和均勻。
skip connections 的第二個目的是特定于 transformers — 保留原始輸入序列。即使有很多注意力頭,也不能保證一個詞會關注到它自己的位置。注意力過濾器有可能完全忘記最近的單詞,轉而關注所有可能相關的早期單詞。跳躍連接采用原始單詞并手動將其添加回信號中,這樣就不會丟失或忘記它。這種魯棒性的來源可能是 transformer 在如此多不同的序列完成任務中表現良好的原因之一。
歸一化是與跳躍連接配合良好的步驟。沒有理由必須將它們放在一起,但在一組計算(如注意力或前饋神經網絡)之后放置時,它們都能發(fā)揮最佳作用。
層規(guī)范化的簡短版本是將矩陣的值移動到均值為零并縮放為標準差為 1。
更長的版本是,在像 transformer 這樣的系統(tǒng)中,有很多移動部分,其中一些不是矩陣乘法(例如 softmax 運算符或整流線性單元),重要的是值有多大,以及它們如何在正負之間平衡。如果一切都是線性的,可以將所有輸入加倍,輸出將是原來的兩倍,一切都會正常進行。神經網絡并非如此。它們本質上是非線性的,這使得它們非常具有表現力,但對信號的幅度和分布也很敏感。歸一化是一種技術,已被證明可用于在整個多層神經網絡的每一步中保持信號值的一致分布。
關于規(guī)范化,我最喜歡的一點是,除了像我剛才給出的高級解釋之外,沒有人完全確定它為何如此有效。
當我們在上面奠定基礎時,我們展示了一個注意塊和一個精心選擇權重的前饋塊足以構建一個像樣的語言模型。在我們的示例中,大多數權重為零,其中一些為 1,而且它們都是手工挑選的。從原始數據進行訓練時,我們不會有這種奢侈。一開始權重都是隨機選擇的,大部分接近于零,少數不是我們需要的。距離我們的模型要表現良好所需的位置還有很長的路要走。
通過反向傳播的隨機梯度下降可以做一些非常了不起的事情,但它在很大程度上依賴于運氣。如果只有一種方法可以得到正確的答案,只有一種網絡運行良好所必需的權重組合,那么它不太可能找到自己的方法。但是,如果有很多路徑可以找到一個好的解決方案,那么模型到達那里的可能性就會大得多。
只有一個注意力層(只有一個多頭注意力塊和一個前饋塊)只允許一條通往一組好的 transformer 參數的路徑。每個矩陣的每個元素都需要找到正確的值才能使事情順利進行。它很脆弱,很可能會陷入一個遠非理想的解決方案,除非對參數的初始猜測非常非常幸運。
Transformers 回避這個問題的方法是擁有多個注意力層,每個注意力層都使用前一個的輸出作為其輸入。跳躍連接的使用使整個管道對個別注意塊失敗或給出不穩(wěn)定的結果具有魯棒性。擁有倍數意味著還有其他人在等待填補空缺。如果一個人偏離了軌道,或者以任何方式未能發(fā)揮其潛力,就會有另一個下游有另一個機會來縮小差距或修復錯誤。該論文表明,層數越多性能越好,盡管在 6 層之后改進變得微乎其微。
考慮多層的另一種方法是將其視為傳送帶裝配線。每個注意塊和前饋塊都有機會將輸入拉下線,計算有用的注意矩陣并進行下一個單詞預測。無論它們產生什么結果,有用與否,都會被添加回傳送帶,并傳遞到下一層。
這與傳統(tǒng)的將多層神經網絡描述為“深度”形成對比。由于跳躍連接,連續(xù)的層不會像提供冗余一樣提供越來越復雜的抽象。在一層中錯過的任何集中注意力、創(chuàng)建有用特征和做出準確預測的機會都可以被下一層抓住。工人成為流水線上的工人,每個人都盡其所能,但不必擔心接住每一件,因為下一個工人會接住他們錯過的。
到目前為止,我們已經小心地忽略了編碼器堆棧(transformer 架構的左側),而選擇了解碼器堆棧(右側)。我們將在幾段中解決這個問題。但值得注意的是,解碼器本身就非常有用。
正如我們在序列完成任務描述中所布局的那樣,解碼器可以完成部分序列并將它們擴展到想要的程度。OpenAI 創(chuàng)建了生成式預訓練 (GPT) 系列模型來執(zhí)行此操作。他們在本報告中描述的架構應該看起來很熟悉。它是一個帶有編碼器堆棧的 transformer,它的所有連接都通過手術移除了。剩下的是一個 12 層的解碼器堆棧。
每當遇到生成模型(如 BERT、ELMo 或 Copilot)時,都可能看到 transformer 的解碼器。
我們所了解的關于解碼器的幾乎所有內容也適用于編碼器。最大的區(qū)別是,最后沒有做出明確的預測,我們可以用來判斷其表現的對錯。相反,編碼器堆棧的最終產品是令人失望的抽象 — 嵌入空間中的一系列向量。它被描述為序列的純語義表示,脫離了任何特定的語言或詞匯,但這對我來說太浪漫了。我們可以肯定的是,它是一個有用的信號,可用于向解碼器堆棧傳達意圖和意義。
擁有編碼器堆棧可以充分發(fā)揮 transformer 的潛力,而不僅僅是生成序列,它們現在可以將序列從一種語言翻譯為另一種語言。翻譯任務的訓練不同于序列完成任務的訓練。訓練數據需要原始語言的序列和目標語言的匹配序列。完整的原始語言通過編碼器運行(這次沒有屏蔽,因為我們假設我們在創(chuàng)建翻譯之前看到整個句子)和結果,最終編碼器層的輸出作為輸入提供給每個解碼器層。然后解碼器中的序列生成像以前一樣進行,但這次沒有啟動它的提示。
啟動和運行完整 transformer 的最后一步是編碼器和解碼器堆棧之間的連接,即交叉注意力塊。我們把它留到最后,多虧了我們奠定的基礎,沒有太多要解釋的了。
Cross-attention 的工作原理與 self-attention 類似,只是鍵值矩陣
我們一路通過 transformer!我們對它進行了足夠詳細的介紹,應該不會留下任何神秘的黑盒子。有一些我們沒有深入研究的實現細節(jié)。你需要了解它們才能為自己構建一個工作版本。最后的幾個花絮與其說是關于 transformer 如何工作,不如說是關于讓神經網絡表現良好。Annotated Transformer 將幫助你填補這些空白。
我們還沒有完全完成。關于我們如何開始表示數據,還有一些重要的事情要說。這與其說是算法的強大功能,不如說是深思熟慮地解釋數據并理解其含義。
我們順便提到,詞匯表可以用高維獨熱向量表示,每個詞都有一個元素。為了做到這一點,我們需要確切地知道我們要表示多少個詞以及它們是什么。
一種天真的方法是列出所有可能的單詞,就像我們可能在韋氏詞典中找到的那樣。對于英語,這將為我們提供數萬個,具體數字取決于我們選擇包含或排除的內容。但這是過于簡單化了。大多數單詞有多種形式,包括復數、所有格和變位。單詞可以有替代拼寫。除非你的數據經過非常仔細的清理,否則它會包含各種印刷錯誤。這甚至沒有涉及自由格式文本、新詞、俚語、行話和廣闊的 Unicode 世界所帶來的可能性。所有可能的單詞的詳盡列表將是不可行的。
一個合理的后備位置是讓單個字符而不是單詞作為構建塊。詳盡的字符列表完全在我們必須計算的能力范圍內。然而,這有幾個問題。在我們將數據轉換到嵌入空間后,我們假設該空間中的距離具有語義解釋,也就是說,我們假設靠得很近的點具有相似的含義,而距離較遠的點則具有非常不同的含義。這使我們能夠隱式地將我們對一個詞的了解擴展到它的直接鄰居,這是我們依賴于計算效率的假設,并且 transformer 從中汲取了一些泛化能力。
在單字層面,語義內容非常少。例如英語中有一些單字詞,但并不多。表情符號是個例外,但它們并不是我們正在查看的大多數數據集的主要內容。這使我們處于無用的嵌入空間的不幸境地。
如果我們能夠觀察足夠豐富的字符組合來構建語義上有用的序列,如單詞、詞干或單詞對,那么理論上仍有可能解決這個問題。不幸的是,transformer 在內部創(chuàng)建的功能更像是一組輸入對,而不是一組有序的輸入。這意味著單詞的表示將是字符對的集合,而沒有強烈表示它們的順序。transformer 將被迫不斷地使用字謎,這使得它的工作變得更加困難。事實上,字符級表示的實驗表明,transformer 在它們方面表現不佳。
幸運的是,有一個優(yōu)雅的解決方案。稱為字節(jié)對編碼。從字符級表示開始,每個字符都被分配了一個代碼,它自己的唯一字節(jié)。然后在掃描一些有代表性的數據后,將最常見的一對字節(jié)組合在一起并分配一個新字節(jié),一個新代碼。新代碼被替換回數據,然后重復該過程。
假設我們有一個語料庫,其中包含單詞(pre-tokenization之后)— old, older, highest, 和 lowest,我們計算這些詞在語料庫中的出現頻率。假設這些詞出現的頻率如下:
{“old”: 7, “older”: 3, “finest”: 9, “l(fā)owest”: 4}
讓我們在每個單詞的末尾添加一個特殊的結束標記“”。
{“old”: 7, “older”: 3, “finest”: 9, “l(fā)owest”: 4}
在每個單詞的末尾添加“”標記以標識單詞邊界能夠讓算法知道每個單詞的結束位置(因為我們統(tǒng)計相鄰字符對時不能把分別位于兩個單詞中的字符對算進去),這有助于算法查看每個字符并找到頻率最高的字符配對。稍后我們將看到“”也能被算作字符對的一部分。
然后把 est 和 old 這些常見的詞綴或字母組合找出來,根據頻率排序,作為新的 token。解碼時需要再次替換回去。
表示字符對的代碼可以與表示其他字符或字符對的代碼組合,以獲得表示更長字符序列的新代碼。代碼可以表示的字符序列的長度沒有限制。它們會根據需要增長,以表示通常重復的序列。字節(jié)對編碼最酷的部分是推斷要從數據中學習哪些長字符序列,而不是笨拙地表示所有可能的序列。它學習用單字節(jié)代碼來表示像 transformer 這樣的長詞,但不會將代碼浪費在類似長度的任意字符串上,例如 ksowjmckder。而且因為它保留了其單個字符構建塊的所有字節(jié)代碼,它仍然可以表示奇怪的拼寫錯誤、新單詞,甚至外語。
當使用字節(jié)對編碼時,可以為其分配一個詞匯量大小,并且它將不斷構建新代碼直到達到該大小。詞匯量需要足夠大,字符串足夠長以捕獲文本的語義內容。他們必須意味著什么。然后它們將足夠豐富來為 transformer 供電。
在訓練或借用字節(jié)對編碼器后,我們可以用它來預處理輸出數據,然后再將其送入 transformer 轉換器。這將不間斷的文本流分成一系列不同的塊(希望其中大部分是可識別的單詞)并為每個塊提供簡潔的代碼。這是稱為標記化的過程。
現在回想一下,當我們開始整個冒險時,我們最初的目標是將音頻信號或口頭命令轉換為文本表示。到目前為止,我們所有的例子都是在假設我們正在處理書面語言的字符和單詞的情況下得出的。我們也可以將其擴展到音頻,但這將更大膽地涉足信號預處理。
音頻信號中的信息受益于一些重型預處理,以提取我們的耳朵和大腦用來理解語音的部分。該方法稱為梅爾頻率倒譜濾波,顧名思義,它的每一點都像巴洛克式的。如果你想深入了解引人入勝的細節(jié),這里有一個圖文并茂的教程。
預處理完成后,原始音頻將變成一個向量序列,其中每個元素代表特定頻率范圍內音頻活動的變化。它是密集的(沒有元素為零)并且每個元素都是實值的。
從積極的方面來說,每個向量都為 transformer 提供了一個很好的“詞”或標記,因為它意味著某些東西。它可以直接翻譯成一組可識別為單詞一部分的聲音。
另一方面,將每個向量視為一個詞是很奇怪的,因為每個向量都是獨一無二的。同一組矢量值出現兩次的可能性極小,因為聲音的組合有很多微妙的不同。我們之前的 one-hot representation 和 byte pair encoding 策略沒有幫助。
這里的技巧是注意像這樣的密集實值向量是我們在嵌入單詞后最終得到的。transformer 喜歡這種格式。為了利用它,我們可以像使用文本示例中的嵌入詞一樣使用 ceptrum 預處理的結果。這為我們節(jié)省了標記化和嵌入的步驟。
值得注意的是,我們也可以對我們想要的任何其他類型的數據執(zhí)行此操作。許多記錄的數據以一系列密集向量的形式出現。我們可以將它們直接插入到 transformer 的編碼器中,就好像它們是嵌入的單詞一樣。
[1] https://e2eml.school/transformers.html
聯系客服