從『是什麼』到『在哪裡』:視覺定位問題
本軌前面的指南教會了機器說出一張圖是什麼。看圖說話(captioning)產生一個句子;視覺問答(VQA)回傳一個答案。但請注意少了什麼:兩者都從不「指出來」。如果一個看圖說話模型說「一個人拿著一個藍色馬克杯」,它從不告訴你哪些像素才是那個杯子。視覺定位正是補上這道缺口的任務——給定一句自然語言片語,它回傳影像中該片語所指的確切區域,可以是框住它的方框,也可以是像素級精確的遮罩。一句話:看圖說話與視覺問答回答是什麼,視覺定位回答在哪裡。
有兩個來自物件偵測與分割軌的詞彙會再次出現,我們先複習一下。邊界框(bounding box)是最簡單的「在哪裡」——四個數字(左、上、寬、高)圈出一個圍住物體的矩形。它便宜而粗糙:框住一隻蜷成一團的貓,四個角落仍然會框進三角形的背景。遮罩(mask)則是精確的替代方案——它為每一個像素貼上標籤,說「這個像素屬於該物體」或「不屬於」,於是答案會緊貼著貓真正的輪廓。視覺定位兩者都能輸出;你要哪一種,取決於下游用途需要多精確。
兩個重疊在物體上的矩形;交集區域被填色,聯集以外框標示。
為什麼「指出來」這麼重要?想像一個家用機器人被吩咐「把那個藍色馬克杯拿起來」。知道某處存在一個杯子毫無用處;夾爪需要座標,所以機器人必須先把這句話定位到一個區域,才能動手。擴增實境也一樣——要在那台濃縮咖啡機上方浮現一個標籤,頭戴裝置必須知道哪些像素才是那台機器。把場景念給視障使用者聽的無障礙工具,若能說「出口在你的右手邊」而不只是「這裡有個出口」,幫助會大得多。還有一個更安靜、更深層的理由:信任。當一個系統能讓你看到它的答案來自哪裡,你就能親自去看、去查證。
指代表達:『左邊數來第二個杯子』
一般的物件偵測回答的是類別問題:「找出所有的杯子。」而指代表達(referring expression)問的是更難、也更貼近人的東西:「找出我指的那一個杯子」——例如「左邊數來第二個杯子」,或「筆電後面那個藍色馬克杯」。把這樣一句話解析到它唯一所指區域的任務,稱為指代表達理解。它的核心難點在於這句話是組合性且關係性的:要挑出正確的那一個實例,模型必須解出屬性(「藍色」)、序數(「第二個」)以及空間關係(「左邊數來」、「後面」)。偵測找出所有杯子就停下;而視覺定位必須運用這些關係,精確地圈出唯一的一個。
當答案必須是像素級精確的遮罩、而非方框時,這個任務稱為指代表達分割。輸入相同——一句話加一張圖——但輸出是一張緊貼所指物體輪廓的模板,而不只是框住它的矩形。這正是語言與分割的天然交會點:它是把視覺定位推到像素解析度。一個需要抓住那個馬克杯杯口的機器人,或一個必須把左邊那隻狗摳出來的修圖工具,要的是遮罩,而不是方框。
一張影像,每個區域依其類別被填上不同的顏色。
左:三個杯子全部同一種顏色(語意)。右:同樣三個杯子各自不同顏色(實例)。
- 場景:桌上由左到右擺著一個紅杯、一個藍杯、再一個紅杯;筆電在中間那個的後面。
- 片語:「左邊數來第二個杯子」。先偵測出每一個杯子——這給出三個候選區域,和單純偵測會回傳的那一組相同。
- 解出名詞:只留下「杯子」候選(三個都符合)。再依空間關係「從左邊」解出序數「第二個」:把三個依其 x 座標排序,取第二個。
- 這就選中了中間那個藍杯。作為合理性檢查,屬性「藍色」也吻合——一個定位良好的模型,會發現基於關係與基於屬性的答案彼此一致。
這正是 CLIP 已知弱點咬人的地方。指南 2 曾指出,CLIP 這類模型很擅長把影像裡的一袋概念和字幕裡的一袋詞配對起來,卻不擅長組合結構——它們可能把「筆電左邊的杯子」和「杯子左邊的筆電」搞混,因為用詞相同,只有關係不同。指代表達的成敗,恰恰繫於這些關係,所以定位系統通常會在 CLIP 式特徵之上,再疊一層明確的關係推理。而要知道我們回傳的區域對不對,我們需要一種方法,把它和人工標出的答案打分。
交集比聯集(IoU):重疊面積除以合併面積。
把它讀作「這兩個區域到底重合了多少」。R_pred 是模型預測的區域;R_gt 是人工畫出的真實區域(下標 gt 即「ground truth,標準答案」)。符號 ∩(交集)是兩個區域共有的面積——它們重疊的地方——而 ∪(聯集)是它們合起來涵蓋的總面積,共有的部分只算一次。當兩個區域完全不相碰(交集為空)時,這個比值是 0;完美吻合(完全重合)時是 1;介於兩者之間則度量部分吻合。一個預測通常在它的 IoU 跨過某個門檻——常用 0.5——時才被算作正確。舉個例子:假設預測框和真實框面積都是 100,而它們重疊的區域面積是 80。那麼聯集是 100 + 100 − 80 = 120,於是 IoU = 80 / 120 ≈ 0.67——高於 0.5,所以這個預測算正確。完全相同的公式同時為方框與像素遮罩打分:對遮罩來說,面積只不過是改成數像素個數,而非矩形面積。
開放詞彙偵測:找出從未標註過的東西
傳統偵測器內建一份固定的類別清單。一個用 80 個類別訓練出的模型能找出「人」、「車」、「狗」——但在結構上對「太空人」是盲的,因為根本沒有給它的輸出格位。開放詞彙偵測把偵測(來自前面的軌)與指南 2 那種 CLIP 式的圖文對齊結合起來,去掉了這個天花板。核心想法只有一個替換:*把偵測器固定的分類頭,換成類別名稱*的文字嵌入。*一旦類別是用代表它們的詞*、而不是用固定格位來表示,你在測試時就能偵測任何你叫得出名字的東西。
回想偵測軌:偵測器在每個候選位置都有兩件工作——說出在哪裡(回歸出一個框)以及說出是什麼(把它分類)。在封閉詞彙偵測器裡,「是什麼」是一層固定大小的輸出層,每個已知類別對應一個輸出。開放詞彙偵測原封不動保留「在哪裡」那套機制,只改寫「是什麼」,讓分類變成一個區域與一段文字之間的配對問題。
一個共用的特徵骨幹分支到兩個並列的頭,一個輸出框座標,另一個輸出類別分數。
- 提出區域。跑偵測器的框機制,得到候選區域(proposals)——大概含有某個物體的框,但還沒說是什麼。
- 嵌入每個區域。讓每個候選通過影像編碼器,得到視覺嵌入 f_r——一個概括該區塊長相的向量,活在 CLIP 那個圖文共享空間裡。
- 嵌入類別名稱。拿你那份候選名稱清單——「人」、「頭盔」、「太空人」,什麼都行——讓每一個通過文字編碼器,得到落在同一個空間裡的文字嵌入 t_c。
- 用相似度配對。用餘弦相似度把每個區域和每個名稱打分,並把最匹配的名稱(須高於某個信心門檻)指派給該區域。
用餘弦相似度做區域–文字配對,再轉成信心分數。
左式量的是對齊程度。f_r 是候選區域 r 的視覺嵌入;t_c 是類別名稱 c 的文字嵌入。它們的內積 f_r · t_c 在兩個向量指向相同方向時很大,而除以兩者的長度 ‖f_r‖ 與 ‖t_c‖,則去掉了大小、只比較純粹的方向——這就是餘弦相似度,正是 CLIP 被訓練去產生的那種圖文對齊。它的範圍從 −1(相反)、經 0(無關)到 +1(完美對齊)。右式把原始相似度轉成可用的信心分數:σ 是 sigmoid,把任何數字壓進 (0, 1);而 τ(tau,「溫度」)控制小小的分數差異會被放大得多銳利——τ 小,決策乾脆俐落;τ 大,決策保持柔和。(當你必須為每個區域恰好選一個類別時,則改成對所有 t_c 做 softmax。)舉例:一個穿白色衣服人物的區域,對「太空人」算出 cos = 0.31、對「人」是 0.22、對「岩石」是 0.05——「太空人」勝出,經過 sigmoid 後那個 0.31 變成相當不錯的信心分數。重點來了:換上不同的類別名稱,就改變了能偵測什麼,而完全不需要重新訓練。這正是為什麼這真的是零樣本偵測。
# Open-vocabulary detection: detect any class you can name.
# image_encoder / text_encoder come from a CLIP-style model (guide 2).
vocabulary = ["person", "helmet", "astronaut", "rock", "flag"] # editable!
t = {c: l2_normalize(text_encoder(f"a photo of a {c}")) for c in vocabulary}
proposals = region_proposer(image) # candidate boxes ("where")
detections = []
for r in proposals:
f = l2_normalize(image_encoder(crop(image, r))) # region embedding
scores = {c: dot(f, t[c]) for c in vocabulary} # cosine (vectors are unit-norm)
best = argmax(scores)
conf = sigmoid(scores[best] / tau)
if conf > threshold:
detections.append((r, best, conf)) # box, name, confidence
# To find astronauts, you just add "astronaut" to `vocabulary`.
# No labels, no gradient steps, no retraining.順著追一遍:訓練資料裡從來沒有一個標著「太空人」的框。偵測器只學會了「提出物體形狀的區域、並把它們嵌進 CLIP 空間」這項通用技能;而 CLIP 則從網路規模的圖文配對中學到,「太空人」這個詞落在穿著太空裝人物的圖片附近。測試時這兩種能力交會,於是一個從未標註過的類別被找了出來。這是指南 2 中零樣本影像分類的「偵測版」手足:在那裡我們把整張圖拿去和類別名稱比較來分類;在這裡我們對每個區域做同樣的比較,於是我們連在哪裡也一併拿到,而不只是是什麼。
一個預測框與一個真實框重疊,重疊量以 IoU 度量。
場景圖:把一張圖變成結構化意義
到目前為止,每句片語都定位到一個區域。但一張圖不只是一袋物體——它是一張關係之網。場景圖(scene graph)把這張網表示成一個圖:每個物體是一個節點(node),每兩個物體間的關係是一條標上述語(predicate)的有向邊(edge)。一張男子騎馬的照片,會變成(男子)—騎→(馬),而若他戴著帽子,還會有(男子)—戴著→(帽子)。把這些邊讀出來,你得到的是對整個場景一份精簡、結構化的描述,而不是一張扁平的物件清單。這個任務就是場景圖生成。
何必把一張圖變成圖(graph)?因為結構解鎖了推理。像「一個男子、一匹馬、一頂帽子」這樣的扁平描述,遺失了誰對誰做了什麼;而圖把它保留下來,於是你能問組合性的問題(「有人在騎嗎?」),並藉由沿著邊走來回答。它讓看圖說話更忠實——一個讀圖(graph)的模型,遠不容易在真相是騎的時候幻想出「男子抱著馬」。它也驅動結構化檢索:「找出有人正在騎馬的照片」就變成一次圖樣式比對(graph-pattern match),而不是一次模糊的關鍵字猜測。
- 偵測物體。跑偵測器得到節點——每個都是一個帶類別的框,例如 {男子、馬、帽子}。(請注意這仰賴前面軌的偵測技能。)
- 組出候選配對。考慮可能有關係的有序物體配對,例如(男子, 馬)、(男子, 帽子)、(馬, 帽子)。
- 分類述語。對每一對,用兩個框、它們的相對位置、以及它們之間的視覺特徵,預測關係標籤——「騎」、「戴」、「在…旁邊」或「無關係」。
- 組裝成圖。留下有信心的述語邊,你就得到了場景圖:節點,加上有標籤、有方向的邊。
我們得誠實面對它為什麼難。第一,配對會爆炸:有 n 個被偵測到的物體,就有大約 *n × (n − 1)* 個有序配對要考慮,所以一個有 30 個物體的繁忙街景,候選關係就已經在 900 這個量級——這種組合式的爆量,逼著模型必須狠狠剪枝。第二,述語有一條殘酷的長尾:少數幾個像「在…上」、「有」、「靠近」主宰了資料,而真正有資訊量的,像「餵食」或「倒映在…中」卻很稀少。一個永遠只預測「在…上」的模型,在原始準確率上可能漂亮得騙人,實際卻幾乎什麼都沒說——這正是為什麼場景圖的評量強調關係的召回率(recall),尤其是稀有關係的召回。
請注意,場景圖裡的每個節點本身就是一個被定位的物體——一個綁著標籤的框——所以場景圖其實就是把視覺定位從一句片語,放大到一整張圖的關係結構。這就是橋樑:定位把個別的詞釘到像素上;場景圖則把一整句話份量的結構釘到像素上,而這正是下一篇那些健談的模型會需要的那種可查證、可核對的鷹架。
可提示的定位:點選、框選、指向
到目前為止的一切,都用詞來引導模型。但詞並不總是最順手的把手。想像一團糾纏交疊的電線,或灌木叢中某一片特定的葉子——用語言描述出確切的那一個非常痛苦,而單純指向它卻是瞬間的事。這就是視覺提示背後的想法:用一個視覺訊號、而非(或同時搭配)一句文字片語,來引導定位模型。
具體來說,一個可提示的分割模型(SAM 系列——「Segment Anything」——是典型代表)接受像點選一個點(「這個點底下的物體」)、畫一個框(「這個矩形裡的物體」)、或粗略塗鴉這樣的提示,並回傳所指物體的精確遮罩。這個互動是即時且反覆的:點一下,得到一個遮罩;如果它抓得太多,就補一個負點來扣掉一塊區域;補一個正點來納入更多。這就是互動式定位——人和模型一起收斂到正確的區域上。
把它變具體。你打開一個修圖工具,在一張熱鬧公園照片裡的狗身上點一下,立刻得到一張乾淨的、狗形狀的遮罩可以摳出來——不用打字、不用等待。一位放射科醫師在可疑區域上拖出一個框,得到一條像素緊貼的輪廓可供測量。一位原本得花上一分鐘手動描邊的資料標註員,現在點一下、再用第二下修正即可。每一個例子裡,提示都是在影像上的一個手勢,而輸出都是一個被定位的區域——正是我們整篇追逐的那個「在哪裡」,只不過改用「指」而非「描述」抵達。
把這兩個把手並排握著——一句指名某個區域的文字片語,和一次指向某個區域的點選——因為下一篇會把它們統一起來。多模態大型語言模型同時接受文字與視覺提示:你可以打「把那個小孩抱著的狗遮罩起來」,同時又點一下來消除歧義,全都在同一段對話裡。視覺定位正是讓這樣一個助理,能把任一種提示化為實際像素上一個實際區域的那套機制。
為什麼定位是『信任層』
退一步,本篇的主線就浮現了:定位讓視覺–語言系統變得可查證。一個只會說「對,有一具滅火器」的模型,要你憑信任接受它。而一個把滅火器框出輪廓的模型,把證據交到你手上——你瞥一眼那些被標亮的像素,自己判斷它是對的、還是在幻想。那種能展示答案來自哪裡的能力,正是把一個無法被否證的主張,變成一個可核對主張的關鍵,於是它直接攻擊這些系統最深的失效模式:自信而無法查證的幻覺。
一路上我們也撿起了度量定位的工具箱。IoU 把單一預測區域對著標準答案打分——而且別忘了,完全相同的公式對方框和像素遮罩都管用。召回率(recall)問的是:在所有真實物體(對場景圖而言,則是所有真實關係)中,模型實際找到了多少比例——當正確答案稀少、而一個偷懶的模型可以躲在常見答案後面時,這格外關鍵。遮罩專屬的指標(在各類別上平均的 mean IoU,或聚焦邊界的分數)獎勵「緊貼真實輪廓」,而不只是「重疊到」。合起來,它們讓我們能用數字說出一個「在哪裡」到底對不對。
我們也要清醒看待哪些仍然困難。關係推理依舊脆弱——指南 2 那個 CLIP 式組合性的缺口意味著,「筆電左邊的杯子」仍然很容易搞反方向。遮擋(occlusion)會把事情弄壞:當一張椅子有一半藏在桌子後面,框與遮罩對看不見的那部分都成了猜測。而有些失敗根本不是模型的錯——語言本身就是真的有歧義。當兩個杯子都同樣偏右時,「右邊那個杯子」是沒有定義的,一個誠實的系統大概應該發問或提供幾個選項,而不是自信地挑一個。
這就鋪好了壓軸。下一篇給語言模型一雙眼睛——多模態大型語言模型能看著一張圖、流暢地聊它。流暢既誘人又危險:一個說得漂亮的系統,也能編得漂亮。視覺定位正是讓它保持誠實的那個元件,逼這位健談的助理指出它正在談論的像素;而開放詞彙偵測則讓它能指向那些沒人費心預先標註過的東西。帶著這副鏡片去讀下一篇:每一個令人驚豔的答案,可信度只等於它能否讓你看見在哪裡。