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