漫畫 Transformer:手把手用數(shù)學(xué)公式推導(dǎo) 精華
我學(xué)習(xí)的時候總有個執(zhí)念:這個背后的底層原理是什么?
這個執(zhí)念經(jīng)常會讓我在理解新的知識的時候,造成很大的障礙。如果我不能理解它的底層原理,我就很難去理解在它基礎(chǔ)上構(gòu)建的知識。
GPT正屬于這類型。
我曾經(jīng)看了不下于幾十篇關(guān)于Tranformer的視頻、教程,但是最后特別是對于Q、K、V非常迷惑。
這篇文章完全解開了我之前的困惑。所以希望大家一定耐心看完。
紐約的 Transformer(由PhotoFunia 創(chuàng)建)
第一步 - 定義數(shù)據(jù)集
用于創(chuàng)建 ChatGPT 的數(shù)據(jù)集為 570 GB。但是,我們只是為了說明問題,所以我們使用一個非常小的數(shù)據(jù)集來執(zhí)行可視化的數(shù)值計算。
我們的整個數(shù)據(jù)集僅包含三個句子
我們的整個數(shù)據(jù)集只包含三個句子,這些句子都是來自電視劇的對話。盡管我們的數(shù)據(jù)集已經(jīng)清理過,但在 ChatGPT 創(chuàng)建等現(xiàn)實場景中,清理一個 570GB 的數(shù)據(jù)集需要大量的努力。
第二步——計算詞匯量
詞匯量也就是我們數(shù)據(jù)集中獨特單詞的總數(shù)。它可以通過以下公式計算,其中獨特單詞的總數(shù)為N。
詞匯量公式,其中 N 為總詞數(shù)
為了找到 N,我們需要將我們的數(shù)據(jù)集分解成單個單詞。
這里用到了一點點集合的知識哦~
計算變量 N
在獲得 N 之后,我們執(zhí)行集合操作以刪除重復(fù)項,然后我們可以計算獨特單詞的數(shù)量以確定詞匯量。
查找詞匯量大小
因此,詞匯量大小為23,因為我們的數(shù)據(jù)集中有23 個獨特的單詞。
步驟 3 — Encoding 編碼
現(xiàn)在,我們需要為每個單獨的單詞分配一個唯一的數(shù)字。
為每個單詞Encoding 編碼
我們已將單個 Token 視為一個單詞并為其分配一個數(shù)字,ChatGPT 則使用此公式將單詞的一部分視為單個Token :1 個Token = 0.75 個單詞
Encoding 完整個數(shù)據(jù)集后,現(xiàn)在是時候選擇我們的輸入并開始使用 Transformer 架構(gòu)工作了。
步驟 4 — 計算嵌入Embedding
讓我們從我們的語料庫中選取一個將在我們的 Transformer 架構(gòu)中處理的句子。
輸入(input)以供 Transformer 使用
我們已經(jīng)選擇了我們的輸入,并需要為其找到一個嵌入向量。原始論文為每個輸入詞使用了一個 512 維的嵌入向量。
原始論文使用 512 維向量
由于在我們的情況下,我們需要使用較小的嵌入向量維度來可視化計算的進(jìn)行過程。因此,我們將使用嵌入向量的維度6。
大小 6 其實是靠經(jīng)驗得來的。不過也有大拿給出了一個公式: n > 8.33logN
嵌入輸入向量
這些嵌入向量的值介于 0 和 1 之間,我們先用隨機(jī)數(shù)來填充一下矩陣。
隨著我們的 transformer 開始理解詞語之間的含義,這些值隨后會通過計算了更新(學(xué)習(xí))。
步驟 5 — 計算位置嵌入Positional Embedding
現(xiàn)在我們需要為我們的輸入Input 計算位置嵌入Positional Embedding。
根據(jù)嵌入向量中第 i 個值的每個詞的位置,有兩種計算位置嵌入Positional Embedding的公式:
位置嵌入公式
正如您所知,我們的輸入句子是“when you play the game of thrones”,起始詞是“when” ,起始索引(POS)值為 0,維度(d)為 6。
對于 i 從 0 to 5 ,我們計算輸入句子第一個詞的位置嵌入Positional Embedding:
位置嵌入:單詞:when
同樣,我們可以為我們輸入句子(input)中的所有單詞計算位置嵌入Positional Embedding。
計算輸入的位置嵌入(計算出的值已四舍五入)
步驟 6 — 連接位置和詞嵌入Concatenating Positional and Word Embeddings
在計算位置嵌入后,我們需要添加詞嵌入Word Embedding和位置嵌入Positional Embedding。
連接步驟
這個由兩個矩陣(詞嵌入矩陣和位置嵌入矩陣)組合而成的結(jié)果矩陣將被視為編碼部分的輸入。
步驟 7 — 多頭注意力Multi Head Attention
多頭注意力由許多單頭注意力組成。
我們需要組合多少個單頭注意力取決于我們。
例如,Meta 的 LLaMA LLM 在編碼器架構(gòu)中使用了 32 個單頭注意力。
以下是單頭注意力外觀的示意圖。
單頭注意力機(jī)制在 Transformer 中有三個輸入:查詢Query、鍵Key和值Value。
這些矩陣是通過將之前計算的相同矩陣的轉(zhuǎn)置與詞嵌入矩陣和位置嵌入矩陣相加,乘以不同的權(quán)重矩陣獲得的。
假設(shè),為了計算查詢矩陣Query,權(quán)重矩陣的行數(shù)必須與轉(zhuǎn)置矩陣的列數(shù)相同,而權(quán)重矩陣的列數(shù)可以是任意的;例如,我們假設(shè)權(quán)重矩陣中有4列。
權(quán)重矩陣中的值是0和1之間隨機(jī)數(shù),當(dāng)我們的轉(zhuǎn)換器開始學(xué)習(xí)這些詞的意義時,這些值將隨后被更新。
計算查詢矩陣Query
同樣,我們可以使用相同的程序來計算鍵 和值 矩陣,但權(quán)重矩陣中的值必須對兩者都不同。
計算鍵Key和值Value矩陣
因此,在矩陣相乘后,得到的結(jié)果查詢Query、鍵Key 和值Value 如下:
查詢、鍵、值矩陣
現(xiàn)在我們已經(jīng)有了這三個矩陣,讓我們一步一步地開始計算單頭注意力。
查詢與鍵的矩陣乘法
為了縮放結(jié)果矩陣,我們必須重復(fù)使用我們的嵌入向量(embedding vector)的維度,即6。
縮放結(jié)果矩陣,維度為5
下一步是掩碼是可選的,這里我們不計算。
掩碼就像告訴模型只關(guān)注某個點之前發(fā)生的事情,在確定句子中不同單詞的重要性時不要窺視未來。它幫助模型以逐步的方式理解事物,而不會通過提前查看來作弊。
因此,我們現(xiàn)在將對縮放后的結(jié)果矩陣應(yīng)用softmax 操作。
應(yīng)用 softmax 到結(jié)果矩陣
執(zhí)行最終的乘法步驟以從單頭注意力中獲取結(jié)果矩陣。
計算單頭注意力的最終矩陣
我們已經(jīng)計算了單頭注意力,而多頭注意力由多個單頭注意力組成,正如我之前所述。下面是它的可視化效果:
多頭注意力機(jī)制在 Transformer 中
每個單頭注意力有三個輸入:查詢、鍵和值,每個都有不同的權(quán)重集。一旦所有單頭注意力輸出它們的結(jié)果矩陣,它們將被連接起來,最終的連接矩陣再次通過乘以一組隨機(jī)初始化的權(quán)重矩陣進(jìn)行線性變換,這些權(quán)重矩陣將在 transformer 開始訓(xùn)練時進(jìn)行更新。
由于在我們的情況下,我們考慮的是單頭注意力,但如果我們在處理多頭注意力,它看起來是這樣的。
單頭注意力與多頭注意力
在任何情況下,無論是單頭注意力還是多頭注意力,結(jié)果矩陣都需要再次通過乘以一組權(quán)重矩陣進(jìn)行線性變換。
標(biāo)準(zhǔn)化單頭注意力矩陣
確保線性權(quán)重矩陣的列數(shù)必須等于我們之前計算的矩陣(詞嵌入 + 位置嵌入)的列數(shù),因為在下一步,我們將把結(jié)果歸一化矩陣與(詞嵌入 + 位置嵌入)矩陣相加。
輸出多頭注意力矩陣
我們已計算出多頭注意力的結(jié)果矩陣,接下來,我們將進(jìn)行添加和歸一化步驟。
步驟 8 — 添加和歸一化
一旦我們從多頭注意力中獲取到結(jié)果矩陣,我們必須將其添加到我們的原始矩陣中。我們先來做這個。
添加矩陣以執(zhí)行加法和范數(shù)步驟
為了規(guī)范化上述矩陣,我們需要計算每行的均值和標(biāo)準(zhǔn)差。
計算均值和標(biāo)準(zhǔn)差
我們用矩陣中每個值減去對應(yīng)行的平均值,然后除以對應(yīng)的標(biāo)準(zhǔn)差。
標(biāo)準(zhǔn)化結(jié)果矩陣
添加一個小的誤差值可以防止分母為零,從而避免使整個項趨于無窮大。
步驟 9 — 前饋網(wǎng)絡(luò)
在將矩陣歸一化后,它將通過前饋網(wǎng)絡(luò)進(jìn)行處理。我們將使用一個非?;镜木W(wǎng)絡(luò),該網(wǎng)絡(luò)只包含一個線性層和一個 ReLU 激活函數(shù)層。這是它的視覺外觀:
前饋網(wǎng)絡(luò)比較
首先,我們需要通過將我們最后計算的矩陣與一組隨機(jī)的權(quán)重矩陣相乘來計算線性層,該權(quán)重矩陣在 transformer 開始學(xué)習(xí)時將更新,并將結(jié)果矩陣添加到一個也包含隨機(jī)值的偏置矩陣中。
計算線性層
在計算線性層之后,我們需要將其通過 ReLU 層并使用其公式。
計算 ReLU 層
第 10 步 — 再次添加和歸一化
一旦我們從前饋網(wǎng)絡(luò)獲得結(jié)果矩陣,我們必須將其添加到從先前添加和歸一化步驟獲得的矩陣中,然后使用行均值和標(biāo)準(zhǔn)差對其進(jìn)行歸一化。
添加和歸一化在前饋網(wǎng)絡(luò)之后
該加法和歸一化步驟的輸出矩陣將作為解碼器部分中存在的多頭注意力機(jī)制之一的查詢和鍵矩陣,您可以通過從加法和歸一化追蹤到解碼器部分來輕松理解。
步驟 11 — 解碼器部分
好消息是,到目前為止,我們已經(jīng)計算了編碼器部分,我們所執(zhí)行的每一個步驟,從編碼我們的數(shù)據(jù)集到將我們的矩陣通過前饋網(wǎng)絡(luò)傳遞,都是獨特的。這意味著我們之前沒有計算過它們。但從現(xiàn)在開始,所有即將到來的步驟,即變換器(解碼器部分)的剩余架構(gòu),都將涉及類似類型的矩陣乘法。
查看我們的 Transformer 架構(gòu)。到目前為止我們已經(jīng)覆蓋的內(nèi)容以及我們還需要覆蓋的內(nèi)容:
即將進(jìn)行的步驟插圖
我們不會計算整個解碼器,因為其中大部分部分包含與我們已經(jīng)在編碼器中完成的類似計算。詳細(xì)計算解碼器只會因為重復(fù)步驟而使博客變長。相反,我們只需要關(guān)注解碼器的輸入和輸出計算。
在訓(xùn)練時,解碼器有兩個輸入。一個是來自編碼器,其中最后一個加和歸一化層的輸出矩陣作為查詢和鍵,用于解碼器部分的第二個多頭注意力層。以下是它的可視化(來自batool haider):
可視化來自巴圖爾·海德
當(dāng)值矩陣來自解碼器在第一次添加和歸一化 步驟之后。
解碼器的第二個輸入是預(yù)測的文本。如果你還記得,我們輸入到編碼器的是當(dāng)你玩權(quán)力的游戲,所以解碼器的輸入是預(yù)測的文本,在我們的例子中是你贏或你死。
但是預(yù)測輸入文本需要遵循一個標(biāo)準(zhǔn)的令牌包裝,使 transformer 知道從哪里開始和在哪里結(jié)束。
輸入:編碼器與解碼器的比較
在哪里<start> 和<end> 是兩個新標(biāo)記被引入。此外,解碼器每次只接受一個標(biāo)記作為輸入。這意味著<start> 將作為輸入,而你 必須是它的預(yù)測文本。
解碼器輸入單詞
正如我們已知,這些嵌入值充滿了隨機(jī)值,這些值將在訓(xùn)練過程中更新。
計算剩余的塊,方法與我們之前在編碼器部分計算的方法相同。
計算解碼器
在深入任何更詳細(xì)的內(nèi)容之前,我們需要理解什么是掩碼多頭注意力,通過一個簡單的數(shù)學(xué)例子來說明。
步驟 12 — 理解掩碼多頭注意力
在 Transformer 中,掩碼多頭注意力就像模型用來關(guān)注句子不同部分的聚光燈。它很特別,因為它不讓模型通過查看句子后面的單詞來作弊。這有助于模型逐步理解和生成句子,這對于像說話或把單詞翻譯成另一種語言這樣的任務(wù)很重要。
假設(shè)我們有一個以下輸入矩陣,其中每一行代表序列中的一個位置,每一列代表一個特征:
輸入矩陣,用于掩碼多頭注意力
現(xiàn)在,讓我們了解具有兩個頭的掩碼多頭注意力組件
- 線性投影(查詢、鍵、值):假設(shè)每個頭的線性投影:線性投影(查詢、鍵、值):假設(shè)每個頭的線性投影:頭 1:_Wq_1,_Wk_1,_Wv_1和頭 2:_Wq_2,_Wk_2,_Wv_2
- 計算注意力分?jǐn)?shù):對于每個頭,使用查詢和鍵的點積來計算注意力分?jǐn)?shù),并應(yīng)用掩碼以防止關(guān)注未來的位置。
- 應(yīng)用 Softmax:應(yīng)用 softmax 函數(shù)以獲得注意力權(quán)重。
- < strong id=0 > 加權(quán)求和(值): 將注意力權(quán)重乘以值以獲得每個頭的加權(quán)求和。
- 將兩個頭的輸出連接起來并應(yīng)用線性變換。
讓我們做一個簡化的計算:
假設(shè)兩個條件
- 強(qiáng) _Wq_1 = _Wk_1 = _Wv_1 = _Wq_2 = _Wk_2 = _Wv_2 = _I_,單位矩陣。
- Q=K=V=輸入矩陣
掩碼多頭注意力(兩個頭)
步驟將兩個注意力頭的輸出合并成一個單一的信息集。
想象你有兩個朋友,他們各自給你提供關(guān)于問題的建議。合并他們的建議意味著將這兩條建議放在一起,以便你能夠更全面地了解他們的建議。
在 Transformer 模型中,這一步驟有助于從多個角度捕捉輸入數(shù)據(jù)的各個方面,有助于模型在進(jìn)一步處理中使用更豐富的表示。
步驟 13 — 計算預(yù)測單詞
輸出矩陣必須包含與輸入矩陣相同的行數(shù),而列數(shù)可以是任何數(shù)量。在這里,我們處理6。
解碼器輸出添加和歸一化
解碼器的最后一個添加和歸一化塊的結(jié)果矩陣必須展平,以便與線性層匹配,以找到我們數(shù)據(jù)集(語料庫)中每個獨特單詞的預(yù)測概率。
將最后一個加和范數(shù)塊矩陣展平
這個展平層將通過一個線性層傳遞,以計算我們數(shù)據(jù)集中每個獨特單詞的logits(得分)。
計算對數(shù)幾率
一旦我們獲得 logits,就可以使用softmax 函數(shù)對它們進(jìn)行歸一化,并找到包含最高概率的單詞。
尋找預(yù)測的詞
因此,根據(jù)我們的計算,解碼器預(yù)測的詞是你。
解碼器的最終輸出
這個預(yù)測的單詞你將被視為解碼器的輸入單詞,這個過程會一直持續(xù)到預(yù)測到<end>標(biāo)記為止。
重要要點
- 上述示例非常簡單,因為它不涉及 epoch 或其他只能使用 Python 等編程語言可視化的重要參數(shù)。
- 它只展示了訓(xùn)練過程,而使用這種方法無法直觀地看到評估或測試。
- 掩碼多頭注意力可以用來防止 transformer 查看未來,有助于避免模型過擬合。
結(jié)論
在這篇博客中,我向您展示了一種非?;A(chǔ)的通過矩陣方法來理解 Transformers 數(shù)學(xué)工作原理的方式。我們應(yīng)用了位置編碼、softmax、前饋網(wǎng)絡(luò),最重要的是多頭注意力。
未來,我將發(fā)布更多關(guān)于變壓器和LLM的博客,因為我的核心關(guān)注點是自然語言處理。更重要的是,如果你想從頭開始使用 Python 構(gòu)建自己的百萬參數(shù)LLM,我已經(jīng)寫了一篇關(guān)于這個的博客,它在 Medium 上受到了很多贊賞。
本文轉(zhuǎn)載自??AI大模型世界??,作者: Khan
