每個詞都在問的問題
讀這句話:「獎盃沒能塞進手提箱,因為它太大了。」這裡的「它」指什麼?你立刻就知道:獎盃。但請留意你的腦子做了什麼——為了理解一個詞,它伸到句子另一頭,把另一個詞拉了過來。這種「伸過去拉」正是[[attention-mechanism|注意力機制]]背後的全部想法。在這條階梯更早的地方你見過循環網絡,它一次處理一個詞,並試圖用一份記憶把含義一路往前帶。注意力把這個瓶頸扔掉了:每個詞都直接地、同時地看向其他每一個詞。
到這一步,每個詞已經是一個向量——一個[[embedding|嵌入]],把這個詞安放在高維語義空間中的某處。[[self-attention|自注意力]]就是讓這些向量彼此交談、並更新自己的那道運算。「自」不過是說,詞關注的是同一個序列裡的別的詞(而不是某個另外的輸入)。一輪過後,「它」這個詞的向量已悄悄吸收了一點「獎盃」,於是它現在的含義更接近「它(那隻獎盃)」。這種混合正是整個 Transformer 的引擎。
查詢、鍵、值:一座小圖書館
這套機制給每個詞三個角色,最乾淨的類比是一次圖書館檢索。查詢(query)是一個詞在找什麼(「我是個代詞——我屬於哪個名詞?」)。鍵(key)是每個詞為自己掛出的標籤(「我是個單數的、具體的物體」)。值(value)是一個詞若被選中,真正會交出來的內容。這個三件套太核心了,因而有自己的名字:查詢、鍵、值,通常寫作 Q、K、V。
關鍵在於:這三個向量並非直接給模型的。每個詞的嵌入會分別乘上三個可學習的權重矩陣——W_Q、W_K、W_V——來生成它的查詢、鍵和值。於是同一個詞「bank」在河流的句子裡能掛出一種鍵,在金錢的句子裡又能扮演另一種有用的角色,因為這個網絡是通過在海量文本上做梯度下降,學會了什麼樣的提問、什麼樣的標籤、什麼樣的內容才有用。Q、K、V 是被學出來的投影,而不是詞的固定屬性。
逐步拆解:縮放點積注意力
現在可以執行這次檢索了。要決定詞 A 該聽詞 B 多少,我們取 A 的查詢和 B 的鍵,算它們的點積——一個數,當兩個向量指向同一方向時這個數就大。所以點積實打實地度量了「B 的標籤把 A 的問題答得多好?」對每一對都這麼算,你就得到一張原始分數的網格:每個詞對每一個其他詞。
- 打分:用每個詞的查詢,去和每個詞的鍵做點積,得到一行原始的匹配分數。
- 縮放:把每個分數除以鍵維度的平方根。這就是「縮放」那部分,它的作用比看上去重要。
- 歸一化:把這一行送進 softmax,將分數變成一組為正、且加起來等於 1 的權重——一種類似機率的注意力分布。
- 混合:用這些權重對所有的值向量做加權平均。那個混合出來的向量,就是這個詞新的、帶上下文的表示。
這整套配方就是縮放點積注意力。其中的 softmax 步驟,讓它成為一次「軟」選擇而非「硬」選擇:一個詞不會只挑中另一個詞,而是把注意力攤開——也許 0.7 給「獎盃」,0.1 給「手提箱」,剩下一點點抹在別處。輸出是每個位置一個全新的向量,每個都是整句話的值按相關度加權後定制混合而成。
許多個頭,許多種視角
一次注意力只能形成一種混合——對「什麼重要」的一種意見。但語言一次需要好幾種:誰指代誰、誰是這個動詞的主語、是什麼時態、是什麼語氣。於是 Transformer 不做一次大的注意力計算,而是並排跑好幾次更小的,每次都有自己的 W_Q、W_K、W_V。每一次就是一個頭(head),整套安排就是多頭注意力。
每個頭把詞投影到一個更小的子空間,在那裡做自己的縮放點積注意力,產出自己那份混合輸出。然後各頭的輸出被拼接(concatenate)在一起,再過一個可學習的矩陣,把它們融合回每個詞一個向量。因為各頭不共享權重,它們就能自由地各司其職——而當研究者剖析訓練好的模型時,確實有些頭看起來在追蹤語法關係,有些追蹤鄰近詞,有些則追蹤罕見的遠距離聯繫。
# one head, sketched (Q,K,V already projected) scores = Q @ K.T / sqrt(d_k) # every query vs every key weights = softmax(scores) # rows sum to 1 out = weights @ V # weighted blend of values # multi-head: do the above H times in parallel, then # combined = concat(out_1, ..., out_H) @ W_O
注意力看不見什麼——以及如何補救
有個讓人清醒的事實:純粹的自注意力根本不知道詞是按什麼順序來的。因為它對一個集合做加權平均,「狗咬人」和「人咬狗」在它看來會一模一樣。這種基於集合的視角,恰恰是注意力速度快、能一次性並行的原因——可詞序顯然是帶含義的。補救辦法是位置編碼:在注意力運行之前,給每個詞的嵌入加進一個與位置相關的信號,於是這些向量悄悄帶上了「我是第 1 個詞」「我是第 2 個詞」等等。
另一個該誠實承認的局限是開銷。因為每個詞都要和其他每個詞比較,工作量隨序列長度的平方增長:文本翻一倍,計算量和記憶體大約翻四倍。這種平方級的增長,正是長輸入昂貴的原因,也是模型有一個有限上下文長度的原因;它是一整條研究路線——更快的注意力變體、更聰明的記憶方案——不斷啃食的核心問題。注意力之所以強大,恰恰因為它把一切連向一切;而正是這同一個性質,讓它如此「餓」。
退一步看,畫面很清晰。一個詞起初是不帶上下文的嵌入;注意力讓它從序列各處收集相關資訊;多個頭一次收集好幾類;而把許多這樣的層堆疊起來,含義就一層又一層地複合,直到「它」可靠地知道自己是那隻獎盃。在下一篇導讀裡,我們會把這些模塊——再加上歸一化層和前饋層——組裝成完整的 Transformer,並看清這套設計為何席捲了整個領域。