為什麼只會配對還不夠
在上一篇導覽中,我們認識了 CLIP——一個學會把圖片的嵌入向量與其字幕的嵌入向量「拉近」的模型。它的好處非常漂亮:CLIP 把整張圖壓成「一個」向量,把整句話也壓成「一個」向量,然後只要量這兩個向量之間的夾角即可。這正是檢索(retrieval)所需要的——給我「一隻狗站在滑板上」這句文字,我就能用每張圖的單一向量與這句文字的單一向量有多接近,來替上百萬張圖排序。快速、簡單、可擴展。
但現在問一個更難的問題:「那位女士的雨傘是什麼顏色?」這就是 視覺問答(VQA),而 CLIP 根本做不到。為什麼?因為 CLIP 對整張圖只產出一個摘要向量——它從來沒有放大到問題真正在意的那塊「雨傘」區域。單一的全域向量把天空、街道、女士、雨傘全部混在一起。「雨傘=紅色」這個資訊或許藏在向量的某處,被抹散在各維度裡,但沒有任何機制能讓「雨傘」這個「字」主動去抓取那一塊區域的視覺特徵。
這其實是我們在第 2 篇提到的「組合性(compositionality)弱點」的更深層版本:因為 CLIP 把一切壓成一個向量,它很難追蹤「哪個屬性屬於哪個物件」。「紅雨傘配藍外套」和「藍雨傘配紅外套」可能落在幾乎相同的點上。比對兩個摘要,能告訴你一張圖和一句話大致講同一個場景,卻無法針對各部分之間的關係進行推理。要回答問題、或要精準地描述一張圖,文字必須能「往圖裡看」,並對圖的個別部分發出查詢。
快速複習:把注意力看成柔性查表
在我們把注意力推廣到跨模態之前,先確保最原始的概念穩固——下一節其實只是在它上面做個小變化。理解注意力最乾淨的方式,是把它看成一次「柔性查表」(soft lookup),像一個永遠不只回傳一筆結果的搜尋引擎:你打進一個查詢;搜尋引擎把它和每份文件的鍵(標題、標籤)比對;但它不是只給你最佳那一筆,而是回給你一個「混合」的答案——大部分來自最相符的幾筆,再摻一點其他的。
示意圖:一個查詢向量與多個鍵向量比對,產生注意力權重,再對值向量做加權總和。
注意力給每個項目三種角色,每種都是一個學出來的向量。「查詢」(Q)是「我在找什麼」;「鍵」(K)是「我把自己標榜成什麼」——別人用來找到我的標籤;「值」(V)是「一旦我被選中,我真正交出去的內容」。鍵與值成對出現:鍵決定一個項目「得到多少」注意力,值則是這個項目「貢獻什麼」。把兩者分開非常有力——一個項目可以很好找(鍵很有辨識度),同時攜帶豐富的內容(值是另一回事)。
縮放點積注意力。
我們逐項拆開。Q 是把查詢向量當作各列堆起來的矩陣(每個「發問」的項目一列);K 堆的是鍵向量,V 堆的是值向量(每個「被看」的項目一列)。乘積 QK^{\top} 是核心:其中每個元素都是某個查詢與某個鍵的點積,也就是一個相關性「分數」——這個查詢與這個鍵有多相符?點積越大代表「越相關」。我們除以 \sqrt{d_k},其中 d_k 是每個鍵向量的維度;若不除,在高維時點積會變得很大,把 softmax 推成接近 one-hot 的尖峰,使梯度消失。除以 \sqrt{d_k} 能把分數保持在合理的尺度,讓 softmax 維持平滑。接著 \operatorname{softmax} 把每一「列」分數轉成總和為 1 的正權重——也就是「該聽每個項目多少」的機率分布。最後乘上 V,便為每個查詢回傳值向量的加權平均:大部分來自它打高分的項目的值,再摻一點其餘的。
一個迷你的算例就能讓它豁然開朗。設 d_k=4,所以除以 \sqrt{4}=2。查詢 q=[1,0,1,0] 去看兩個項目,鍵分別是 k_1=[1,0,1,0](完美相符)與 k_2=[0,1,0,1](毫無重疊)。原始分數為 q\cdot k_1=2、q\cdot k_2=0;縮放後變成 1 和 0。接著 \operatorname{softmax}([1,0])=[\,e^1/(e^1+e^0),\,e^0/(e^1+e^0)\,]\approx[0.73,\,0.27]。所以輸出是 0.73\,v_1+0.27\,v_2——壓倒性地取相符項目的值,但絕不會是硬性的 100/0。正是這種「柔性」混合,讓注意力可微、可訓練。
多頭注意力示意圖:輸入被投影到數個頭,每個頭獨立計算縮放點積注意力,輸出再串接並投影。
最後一塊複習:真實的 Transformer 不是只跑一次注意力,而是跑「多頭」(multi-head)注意力——好幾個並行的注意力「專家」。每個頭都有自己學到的投影,把 Q、K、V 投到一個較小的子空間,於是某個頭也許專精於顏色關係,另一個專精於空間佈局,再一個專精於數數。它們的輸出被串接,再經一層線性層混合。可以想成同時用好幾副不同的鏡片去問同一個查表問題,再把這些視角整合起來。把這幅圖記牢——我們接下來要建的跨模態版本,用的就是一模一樣的機器,只改了「向量從哪裡來」這一件事。
跨模態注意力:讓文字去看像素
整篇導覽其實一句話就能講完:在 跨模態注意力 裡,查詢來自一個模態,而鍵與值來自「另一個」模態。具體來說,我們讓文字 token 當查詢,讓圖像 patch 當鍵與值。如此一來,每個字都能發出一個查詢,去搜尋整張圖的各個 patch,再抓回它們視覺特徵的加權混合。這個字不再被困在句子裡——它跨過橋樑,伸進了圖片之中。
跨模態注意力:查詢是文字 token 的投影;鍵與值是圖像 patch 的投影。
慢慢讀,因為唯一的新意全在下標裡。T 是「文字」token 特徵的矩陣(每個字一列);P 是「圖像」patch 特徵的矩陣(每個 patch 一列,正是 Vision Transformer 產出的那種 patch 嵌入)。W_Q、W_K、W_V 是學出來的投影矩陣——和我們在自注意力裡用的同一種。關鍵轉折:Q=W_Q T 由「文字」構成,而 K=W_K P 與 V=W_V P 「兩者都」由「圖像」構成。於是當我們算 QK^{\top} 時,每個字的查詢都會去和每個圖像 patch 的鍵比分,替每個字得到一組「哪些 patch 對這個字重要」的權重;再乘上 V,就為每個字回傳一份圖像特徵的加權混合。公式和先前一模一樣——仍是 \operatorname{softmax}(QK^{\top}/\sqrt{d_k})V——只有向量的「來源」改變了。
現在走一遍雨傘的例子。「那位女士的雨傘是什麼顏色?」這句話被斷詞後,「雨傘」這個字變成一個查詢向量 q_{\text{雨傘}}=W_Q\,t_{\text{雨傘}}。圖像被切成許多 patch,每個都有鍵與值。點積 q_{\text{雨傘}}\cdot k_{\text{patch}} 在真正含有雨傘的那幾個 patch 上很大、其餘地方都很小,於是 softmax 後權重便堆到那些雨傘 patch 上。因此回傳的值會由雨傘的視覺特徵主導——包含它的顏色。「雨傘」這個字其實是在問圖:「你在哪裡、長什麼樣?」並得到了答案。這正是讓模型能做 視覺問答 的細粒度查表。
一張圖疊上熱力圖,亮點落在雨傘區域,顯示「雨傘」這個字注意到了哪裡。
還有一個迷人的附加好處:那些 softmax 權重「就是」一張注意力圖,你可以把它畫回圖像上、變成熱力圖。挑「雨傘」這個字,讀出它對各 patch 的權重,亮起來的區域就精確顯示了模型在處理這個字時看了哪裡。這是深度學習中少數內部真正可解釋的時刻之一——你真的能「看見」一個字的目光。(不過讀這些圖要小心:高注意力代表「模型對這塊加了權重」,並不保證是因果解釋。第 4 篇會把這份「目光」變成真正能「指向」區域的能力。)
架構:雙塔、融合,與兩者兼得
掌握了自注意力與跨注意力後,你現在就能讀懂整張視覺語言架構地圖。第一個家族是「雙塔/雙編碼器」(dual-encoder),你早已認識它:CLIP。兩座分開的塔——一座圖像編碼器、一座文字編碼器——各自產出自己的嵌入,彼此「不通訊」。正因為兩塔獨立,你可以離線把每張圖的嵌入預先算好並存起來;查詢時只需編碼文字、再做一次便宜的點積。這就是 CLIP 能擴展到數十億張圖的原因。代價是兩塔從不在「部分」的層級互動,因此細粒度推理(VQA、屬性綁定)遙不可及。
第二個家族是「融合編碼器」(fusion-encoder)。這裡我們插入 跨模態注意力 層,讓文字與圖像特徵真正混合:字去看 patch(通常 patch 也會回看字)。它在 VQA、看圖說話,以及任何需要對「部分之間關係」推理的任務上都好得多——這正是 CLIP 所欠缺的互動。代價是速度。因為答案取決於「兩個」輸入一起流過跨注意力層,你無法獨立於文字去預先算好一張圖的表示。每一個圖文「配對」都得整個跑過模型一次。拿一句文字去比對一百萬張圖,現在意味著一百萬次完整的前向傳遞,而不是一百萬次點積。
那該選哪一個?實務上「兩個都用」——做成一條叫「先檢索、再重排」(retrieve-then-rerank)的流程。先用快速的雙編碼器,靠預先算好的嵌入,從數百萬中便宜地篩出例如前 50 名候選圖(或字幕)。接著只對這 50 個配對,跑那慢卻準的融合模型,用完整的跨注意力推理把它們重新排序。你同時拿到雙編碼器的可擴展性「與」融合編碼器的精準度,而昂貴的運算只花在一份已經很不錯的小清單上。任何 視覺語言模型 要承接真實流量時,到處都看得到這個模式。
Transformer 區塊示意圖:先自注意力,再一層看圖像特徵的跨注意力子層,最後前饋網路,每層都帶殘差連接。
那跨注意力層究竟坐在哪?在文字側的標準 Transformer 區塊裡,我們保留原本的自注意力子層(讓字彼此交談),然後加上「第二」個注意力子層——也就是跨注意力——讓文字查詢去看圖像的鍵/值。之後接上慣常的前饋網路,而且一如既往,每個子層都帶殘差連接與正規化。把幾個這樣的區塊疊起來,文字表示就會被圖像一再地精煉:自注意力整理句子,跨注意力注入視覺證據,一層接一層。
# One fusion Transformer block on the text stream (pseudocode).
# text: (num_words, d) -- token features (the queries)
# image: (num_patches, d) -- patch features from a vision encoder (keys/values)
def fusion_block(text, image):
# 1) Self-attention: words talk to each other (Q,K,V all from text)
text = text + self_attention(q=text, k=text, v=text)
text = layer_norm(text)
# 2) Cross-attention: words look at the image
# Q comes from TEXT, but K and V come from the IMAGE patches
text = text + cross_attention(q=text, k=image, v=image)
text = layer_norm(text)
# 3) Position-wise feed-forward, as in any Transformer
text = text + feed_forward(text)
text = layer_norm(text)
return text # text now carries fused visual evidenceBLIP:統一理解與生成
我們把以上一切落實到一個具體、現代的設計上:BLIP。BLIP 是一個融合模型,旨在做 CLIP 做不到的事——它既能「理解」圖像(檢索、VQA),又能「生成」關於圖像的文字(看圖說話)。它的做法是:用同一套共享的圖像與文字編碼器,同時對「三個」互補的訓練目標進行訓練。可以把這三個目標想成三場不同的考試,逼同一個模型從同一批圖文資料中學會三種不同的技能。
- 圖文對比(ITC):CLIP 式的目標。把相符的圖與字幕嵌入拉近、把不相符的推遠,使兩個模態活在一個共享、對齊的空間裡。這讓雙編碼器路徑在檢索上很快,也替更難的目標提供了一個整理好的起點。
- 圖文匹配(ITM):一個二元的「這兩個真的搭得起來嗎?」分類器。關鍵在於這個頭使用跨注意力,因此能做細粒度核對——不只是「大致同主題」,而是「每個細節都對得上嗎?」。它用「困難負例」(看起來幾乎對的不相符配對)訓練,逼模型察覺像「紅雨傘被標成藍」這種細微的綁定錯誤。
- 以圖為條件的語言建模(LM):以圖像為條件(透過跨注意力),逐字生成字幕。這就是給了 BLIP 一張嘴——能「寫」的能力。同一個生成頭同時驅動 看圖說話 與 視覺問答(問題不過是一段條件提示,答案則是生成出來的文字)。
為何三個都要?因為每一個都補上其他兩個留下的缺口。ITC 便宜地對齊空間,但只是粗略地;ITM 透過跨注意力加上細粒度的驗證;LM 加上真正「產出」語言、而不只是替它打分的能力。三者合起來,就造出「一個」既能檢索、又能判斷是否相符、又能寫字幕的模型——理解與生成共處於同一個骨幹。
還有第二個值得認識的 BLIP 點子:CapFilt,是 Caption-and-Filter(生成字幕並過濾)的縮寫。網路上的圖文資料量巨大卻很雜——替代文字常常是垃圾(「IMG_2043.jpg」、「點此」)。CapFilt 用模型自己的本事來清理它。一個「字幕生成器」(LM 頭)替每張網路圖生成一段全新的合成字幕,接著一個「過濾器」(ITM 頭)把任何——原始的「或」合成的——與圖像並不真正相符的字幕丟掉。存活下來的字幕構成一個更乾淨的訓練集,訓練出更好的模型,而它又能把字幕生成與過濾做得更好。乾淨的資料能提升品質,因為模型不再把容量浪費在背雜訊上,而是從真正描述了圖片的描述中學習。
融合帶來什麼好處,又付出什麼代價
把線索收攏起來。像 CLIP 那樣的純比對快速又可擴展,卻對「部分」視而不見——它比較的是兩份摘要,無法推理哪個屬性配哪個物件。跨模態注意力 修正了這點:它讓每個字都能伸進圖裡、抓取它正需要的那些 patch。光這一項能力,就解鎖了視覺問答、有依據的看圖說話,以及真正的多部件推理——也就是像 BLIP 這類模型所立基的能力。
但融合不是免費的。因為一個圖文配對的分數取決於兩個輸入「一起」流過跨注意力層,你再也無法像 CLIP 那樣預先算好並快取每張圖的向量——每個配對都需要一次完整的前向傳遞。這正是「先檢索、再重排」模式存在的全部經濟理由:靠便宜的雙編碼器縮小範圍,再把昂貴的融合運算只花在一份小而有希望的清單上。每當你設計多模態系統時,這個「速度對精準」的取捨,都是要先轉的第一個旋鈕。
還有一個要誠實面對的限制。即使有了跨注意力,融合模型回答的仍是「文字」。當你問「雨傘是什麼顏色?」它說「紅色」——它內部或許看了對的 patch,但它的「輸出」是文字,不是框在雨傘上的方框。若你需要模型真正「指向」那塊精確的區域——也就是定位(localise)——那是另一種能力。第 4 篇〈指向像素:把語言落地到影像〉,講的正是如何把這份內在的目光化為一個外顯的指標。
還有第二道前沿。本篇裡的模型都是「專才」——被微調來做檢索、匹配、看圖說話或問答。它們還不是你能下任意指令的通用助理(「描述這張圖表,然後寫一則推文」)。把一個強大的語言模型嫁接到視覺編碼器上,讓視覺特徵流入一個會聽指令的 LLM,便是邁向多模態大型語言模型的躍進——這是第 5 篇〈給語言模型一雙眼睛〉的主題。跨模態注意力正是讓這兩個下一步都成為可能的橋樑;而你現在已經理解了它們每一個所立基的機制。