從一個巧招到一整台機器
在前兩篇指南裡,你已經造好了引擎:自注意力讓每個詞都能從其他每個詞那裡收集訊息,多頭注意力則並行地跑好幾次這樣的查找,使模型能同時追蹤語法、含義與指代。但有了引擎並不等於有了汽車。單獨一層注意力是「淺」的——它只把訊息混合一次就停了。[[transformer-architecture|Transformer]],就是當你拿起這台引擎、再把整輛車的其餘部分圍著它造出來時所得到的東西:如何把這些層疊起來、如何讓它們保持穩定、以及如何讓整套裝置真正生成文字。
提出它的那篇著名的 2017 年論文,標題叫做*《注意力就是你所需要的一切》*——這是對當時主宰語言領域的循環網路的有意一擊。那些更老的模型嚴格地從左到右讀句子,一次一個詞,像接力棒一樣把一份不斷更新的記憶往下傳。這讓它們訓練起來很慢,而且讀到句尾時往往已經忘了句首。Transformer 下的賭注很激進:徹底扔掉循環,用注意力一次性看遍所有詞,讓堆疊的層去做深層的思考。
一個模組:先注意力,再一個小腦子
Transformer 由一個重複的單元——*模組*——多次堆疊而成。每個模組依次做兩件事。首先,一層注意力讓每個位置混入其他位置的訊息——這是*交流*步驟,詞與詞在這裡互相說話。接著是一個[[feed-forward-block|前饋模組]]:一個小小的兩層網路,*獨立地*作用在每個位置上,每個詞都複用這同一個小網路。如果說注意力是詞在說話,那麼前饋模組就是每個詞各自走開,私下裡琢磨它剛剛聽到的東西。
這種分工的重要性超出第一眼的感覺。注意力在位置*之間*搬運訊息,卻幾乎不做非線性的推理;前饋模組負責繁重的逐詞變換,卻看不到它的鄰居。讓兩者交替進行——收集,再處理,收集,再處理——正是深層 Transformer 力量的來源。若數一數參數,前饋模組通常才是模型的*大頭*,而不是注意力;模型所「知道」的很大一部分,就住在那些不聲不響的小網路裡。
還有一塊東西跑在第一個模組*之前*:位置編碼。因為注意力同時看所有詞,它本身沒有任何順序感——對原始的注意力來說,「狗咬人」和「人咬狗」是同一袋詞。位置編碼給每個詞元蓋上一個標記,表明它*坐在哪個位置*,把過去由循環免費提供的詞序重新補回來。
殘差與層歸一化:讓它得以變深的膠水
把幾十個模組疊起來聽上去很容易,但深層網路出了名地難訓練——梯度在穿過許多層往回傳播時,會漸漸消失或者猛然爆掉(你在階梯的更早處遇到過這個*梯度消失*問題)。兩個簡單的竅門讓這種深度變得可以承受。第一個是[[residual-connection|殘差連接]]:每個子層不去替換它的輸入,而是把自己的輸出*加*回輸入上。模組算出一個小小的修正量,而原始訊號則原封不動地徑直穿過。
想像一位編輯在批改草稿。殘差連接意味著編輯交還給你的是原稿*外加*頁邊的批註,而不是從頭到尾重寫一遍。文本能熬過五十位編輯的接力;梯度沿著同一條筆直的路往回走,也能活下來。沒有殘差,把 Transformer 訓練到超過區區幾層幾乎都做不到。
第二個竅門是[[layer-normalization|層歸一化]]:在每個子層之前(或之後),把每個位置上的數值重新居中、重新縮放到一個整潔的範圍。這能防止訊號在爬上層疊時漂到極端的數值,從而讓每一層都接收到處於舒適區間的輸入。把它*放在哪裡*——「前歸一化」(在子層之前歸一)還是「後歸一化」(在之後)——是一個實實在在的設計取捨;現代的大模型幾乎全都採用前歸一化,因為在很深的情況下它訓練起來穩定得多。
# one Transformer block (pre-norm style) x = x + attention(layer_norm(x)) # communicate: words mix x = x + feed_forward(layer_norm(x)) # compute: each word thinks # stack this block N times (N = 12, 48, 96, ...)
編碼器、解碼器,還是兩者都要
最初的 Transformer 是為機器翻譯而造的,所以它有兩疊模組——一個[[encoder-decoder-stack|編碼器–解碼器堆疊]]。*編碼器*讀入整句源文,並為它建起一份豐富的表示,其中每個詞都能朝兩個方向自由地關注其他每個詞。*解碼器*隨後生成譯文,並做兩種注意力:它關注自己迄今為止已經產出的詞,又通過[[cross-attention|交叉注意力]]回頭探入編碼器的表示,去查閱源文。編碼器消化,解碼器一邊瞄著編碼器的筆記一邊寫。
研究者很快注意到,你並不總是需要兩半都要。只保留*編碼器*,你就得到一個會閱讀、會理解、卻從不生成的模型——很適合給句子分類或打標籤(BERT 一系就是這樣工作的)。只保留*解碼器*,你就得到一個純粹的文本生成器。幾乎你聽說過的每一個聊天機器人式的大語言模型都是*僅解碼器*的:一疊模組,唯一的任務就是一遍又一遍地預測下一個詞。
解碼器如何寫作:一次一個詞元
解碼器靠[[autoregressive-decoding|自迴歸解碼]]來生成文本:它預測一個詞元,把它接到序列後面,再把整段重新餵進去以預測下一個——如此反覆,就像一個只能不斷添上下一個詞、永遠無法跳著往前寫的作者。訣竅在於,為了學會這件事,一個詞絕不能被允許偷看排在它*後面*的詞;否則模型就會靠讀答案來作弊。這一點由[[masked-attention|掩碼注意力]]來強制:在解碼器裡,注意力被擋住、不准向前看,於是每個位置只能看見它自己和過去。
- 讓提示詞穿過整疊模組,看最後一個位置輸出的向量。
- 把這個向量變成對整個詞表的一個概率分布(在數萬個可能的下一詞元上做 softmax)。
- 從這個分布裡挑出一個詞元——可以貪心地取最大,也可以採樣以增加多樣性。
- 把它接到序列後面,從第 1 步重複,直到遇到一個停止詞元。
這個循環也是為什麼生成會讓人覺得*是順序的*、而且可能很慢:詞元一個接一個地吐出來,每一個都得等上一個。有一項叫做 KV 快取的巧妙優化,會把更早詞元的注意力計算結果存下來,免得每一步都重算一遍——沒有它,生成一段長回覆會慢得沒法用。它改變的是速度,而非本質:Transformer 寫作的方式,仍然像你朗讀時那樣,一個詞接著一個詞。
值得誠實地說清這個循環是什麼、又不是什麼。模型並不是先規劃好一整段答案、再把它打出來;它在每一步只是在估計:在迄今的所有內容之下,*接下來傾向於出現哪個詞元*。那份流暢是真實的,常常令人驚嘆,但背後並沒有一本被查閱的事實帳本——這正是為什麼這些模型能信心十足地說出錯誤。這套架構是一台了不起的下一詞預測器,而不是一位神諭。
它為何勝出
Transformer 幾乎取代了它之前的一切,原因有一個被低估的:它*對並行很友好*。因為一層會同時處理每一個詞、而不必等上一個,你可以在 GPU 上一口氣把一整句話——甚至一整本書——灌進去。這使得在驚人體量的文本上訓練成為可能,而事實證明:用更多數據訓練的更大的 Transformer,就是會一直變好,平滑而可預測。這套架構贏的不只是品質;它贏在*規模上的可訓練性*。
這一切都不意味著 Transformer 就是定論,那種「它是我們將永遠需要的最後一種架構」的炒作也該打個折扣。它平方級的注意力開銷是一道實打實的天花板,位置編碼方案至今仍在被不斷重新發明,認真的替代方案也正在被探索。可以公允地說的是:你如今已經理解的這一小撮想法——一疊疊注意力與前饋模組、用殘差和層歸一化黏合、一次生成一個詞元——支撐著今天人們口中幾乎每一個被稱為「AI」的系統。你看的已不再是一個黑盒。你能叫出它每個部件的名字。