L4.2 同一個東西換個位置出現,要怎麼讓模型知道那還是同一個東西?
起點:概念與位置
什麼都能擬合,那為什麼還需要別的架構? 在小影像 toy 上留下三個數字:MLP 學得會這個任務(測試 );換一個位置就不會了(左半訓練、右半測試 ,亂猜是 );而把像素順序整個打亂,它毫無感覺()。
那一篇也給了解釋:MLP 學到的是「第 37 號與第 38 號像素會一起亮」這種和位置綁死的規則。「橫線」這個概念從來沒有被學到。
而我們知道答案應該長什麼樣。一條橫線出現在畫面的左邊或右邊,是同一條橫線;一隻貓在照片的左上角或右下角,是同一隻貓。這不是模型要從資料裡發現的東西——這是我們一開始就知道的事實。問題只是:怎麼把它寫進模型裡。
「橫線」這個概念和它出現在哪裡無關,
可是模型學到的是「第 37 號和第 38 號像素會一起亮」——
要怎麼讓「換個位置還是同一件事」變成模型的一部分,而不是它要自己發現的東西?
課堂提問Q1
「平移之後還是同一件事」有兩種寫法:讓輸出完全不變(invariance,),或讓輸出跟著平移(equivariance,)。一個網路有很多層,這兩種各該放在哪一層?如果第一層就用不變,會失去什麼?
先想一想,再展開看整理後的答案
先看不變放在第一層會怎樣。 假設第一層輸出一個對所有平移都不變的向量。那麼「線在左邊」和「線在右邊」這兩張圖,在第一層之後就變成同一個東西了——位置資訊被永久刪除。
這對「橫的還是直的」這個任務剛好沒差。但只要任務需要用到位置——兩個物件的相對位置、線的長度、邊界在哪裡——後面的層就再也做不到了,因為那個資訊已經不在了。
不變是有損的。 它丟掉一個自由度來換一個保證,而那個保證只在你確定不需要那個自由度時才划算。
等變不丟東西。 說的是:輸入平移,輸出原封不動地跟著平移。位置資訊完整保留,只是被搬到輸出的座標上。所以等變可以一層一層疊下去——兩個等變的映射合成起來還是等變的。
於是分工很清楚:中間每一層用等變(保留位置,同時保證「同一個特徵在哪裡都用同一套規則偵測」),最後一步才用不變(把位置積掉,換成一個和位置無關的答案)。這最後一步通常就是 pooling——對所有位置取最大或取平均,而那正是把等變轉成不變的操作。
那要怎麼造一個等變的層? 這裡有一個很強的結果:一個和所有平移交換的線性映射,一定是卷積。 不是「卷積是一種選擇」,而是「在線性映射裡,卷積是唯一的選擇」。(下方的 <Details> 有兩行推導。)
所以卷積不是一個從影像處理借來的技巧,它是「我要一個對平移等變的線性層」這個要求的唯一解。
展開細節為什麼平移等變的線性映射一定是卷積
設 是線性的,寫成 。設 是平移 格的算子,。等變要求 對每一個 成立。
把兩邊都作用在基底向量 上,比較第 個分量:
取 :,也就是 只依賴 。寫成 ,代回去:
這正是卷積的定義。整個矩陣由一個向量 決定——這就是權重共享,它不是額外加上去的節省手段,它是等變這個要求逼出來的。
(「只看附近」則是另一件事:它對應 在距離超過 之後為零。等變不蘊含局部,局部也不蘊含等變——本篇第一節把兩者分開量。)
兩個獨立的宣告
卷積層通常被當成一個整體介紹,但它其實把兩件可以分開的事綁在一起:
- 局部(local):一個輸出只看輸入的一小塊(本篇是 )。宣告的是「有用的模式是局部的」。
- 共享(shared):每一個位置用同一組權重。宣告的是「一個模式在哪裡出現都算數」。
這兩件事可以拆開。局部但不共享是一個真實存在的層(locally connected layer):每個位置有自己獨立的 權重。它滿足局部,但完全不共享。
三個模型放在一起,就可以把兩個宣告各自的貢獻分開量:
| 局部 | 共享 | 參數量 | |
|---|---|---|---|
| MLP() | ✗ | ✗ | |
| 局部未共享(,每位置自己的權重) | ✓ | ✗ | |
| 卷積() | ✓ | ✓ |
兩個對照組的參數量刻意排得很接近( 對 ),而卷積少了 倍。三個模型後面都接同一個 global max-pool 與一個線性輸出,訓練流程完全相同(Adam 、3000 步、三個 seed 取中位數)。
三個條件,九個數字
沿用 什麼都能擬合,那為什麼還需要別的架構? 的三個條件:全位置(訓練與測試的線都可能出現在任何地方)、左訓右測(訓練集的線只出現在左半,測試集只出現在右半)、打亂像素(一個固定的隨機排列套在所有影像上)。
參數 全位置 左訓右測 打亂像素
MLP 13505 0.982 0.605 0.980
局部未共享 13321 1.000 0.878 0.998
卷積 217 1.000 0.998 0.780
先看第二欄。 從 到 到 ——這是「換一個位置還算不算同一件事」的能力,而它隨著宣告加進去而單調上升。卷積的 幾乎是滿分:它從來沒有看過右半邊的線,卻做得和看過一樣好。
而它只用了 個參數。這是整個 L4 想說的事的第一個乾淨證據:把正確的結構寫進假設空間,可以同時讓模型變小、變好、而且泛化到訓練分布之外。十個房仲各看一百間房:Bias 與 Variance 說過加資料只壓 variance;這裡壓掉的是 bias,而那是加資料做不到的。
正確的歸納偏置不是在「更少參數」和「更好表現」之間取捨,它同時買到兩個。
第三欄才是真正有意思的那一欄,而且它和直覺相反。
打亂像素順序,等於把「哪些像素相鄰」這個結構整個摧毀。直覺上,一個「利用空間結構」的模型應該會受傷。實測:
- MLP:。完全沒感覺,這是 什麼都能擬合,那為什麼還需要別的架構? 已經解釋過的——打亂等於把第一層權重乘上一個置換矩陣,假設空間沒變。
- 卷積:。真的受傷了。 這是「它在用空間結構」的證據——結構被破壞,它就做不好。
- 局部未共享:。也完全沒感覺。
第三列是這一篇最值得停的地方。 「局部」這個宣告聽起來就是「我在用空間結構」,但它在這個實驗裡完全不受打亂影響。
原因是:局部未共享的層有 個位置、每個位置一組自由的 權重,而這些接受域互相重疊、合起來覆蓋整張圖。打亂之後,每個 視窗裡裝的是 個任意的像素——但每個視窗的權重是自由的,所以它照樣可以學出一個能區分兩類的偵測器。它有「局部」這個形狀,但那個形狀沒有對它造成任何真正的限制。
卷積不行,因為它必須在每個位置用同一個 濾波器。打亂之後,「同一個局部模式會在很多地方重複出現」這件事不再成立,於是一個共享的濾波器就失去了立足點。
受傷的那個模型才是真的在用結構——而那個傷來自共享,不是來自局部。
等變是精確的,不是「大致成立」
上面都是訓練出來的結果,會受最佳化與 seed 影響。但等變性本身是一個結構性質,和訓練完全無關——它在隨機初始化的網路上就已經成立,而且是精確成立。
實測:取一個隨機初始化的 卷積層,把輸入影像整體往右平移一格,比較「平移後的特徵圖」與「原特徵圖平移一格」:
卷積層 max |f(平移 x) - 平移 f(x)| (避開邊界) = 0.000e+00
參考:特徵圖本身的量級 max|f| = 0.9530
是精確的零,不是很小的數。 這不是一個近似成立的性質,它是卷積這個運算的定義的直接後果。
對照 MLP 的隱藏層(同一批影像、同樣平移一格):
MLP 隱藏層 平均 |h(平移 x) - h(x)| = 0.2148 (量級 0.1818)
差異比訊號本身還大。 平移一格之後,MLP 的內部表示變成一個完全不同的東西。而且注意:對 MLP 我們連「把輸出也平移一下再比」都做不到——它的隱藏層沒有空間座標, 個隱藏單元不構成一張圖,「平移特徵圖」這個操作在那裡沒有定義。
這是「結構性保證」與「學出來的近似」之間的差別。 前者不需要資料、不需要訓練、不會因為 seed 而改變;後者需要你相信訓練過程把它學到了,而且要用實驗去驗證。
補充pooling 是把等變換成不變的那一步
上面三個模型最後都接了一個 global max-pool。這一步在做的事,正是 Q1 說的「最後一步才用不變」。
如果 對平移等變, 是對所有位置取最大,那麼
因為「所有位置的最大值」本來就不管那些值排在哪裡。等變 + pooling = 不變,而這個組合就是卷積網路能做到「換位置還算同一件事」的全部機制。
這也解釋了 pooling 的取捨:它每用一次就丟掉一次位置資訊。用得太早,後面就沒有位置可以用;用得太晚,不變性就沒有被建立起來。實務上的做法是逐步丟——每隔幾層降取樣一次,讓位置資訊以受控的速度換成語意資訊。一張圖裡同時有紋理、物件和整個場景,一個固定大小的核怎麼辦? 會把那個交換量出來。
刻意違反:當「不變」只是近似,模型會去利用那個縫隙
到這裡為止,「平移不變」都是好事。但它是一個宣告,而宣告可以是錯的——如果任務的答案本身就取決於位置(醫學影像裡器官的位置、文件版面裡欄位的位置),那麼一個對平移不變的模型在定義上就答不出來。
做一個這樣的任務:同一批橫線/直線影像,但標籤改成「線出現在前半還是後半」(線一律保持在畫面內部,不碰邊)。預期是:MLP 應該做得不錯(它本來就和位置綁死),卷積應該接近亂猜(它對平移不變)。
MLP 訓練 1.000 測試 0.893
卷積 訓練 0.998 測試 0.935
卷積不但沒有掉到 ,還比 MLP 好。 預期完全落空,而理由值得寫下來。
那個「不變」只是近似的。 上一節的等變測試刻意「避開邊界」——因為在邊界附近,等變根本不成立:一個 的視窗在影像中央有很多種對齊方式,在邊緣只有少數幾種。於是「一條線靠近上緣」和「一條線在中間」給出的 pooling 結果確實不同,而那個不同和標籤相關。
模型找到了這個縫隙並用了它。 這不是 bug,這是最佳化在做它該做的事:火力與時間是食譜的一部分,還是煮的時候決定的? 以來反覆出現的同一件事——只要某個訊號和標籤相關,梯度下降就會去用它,不管你希不希望。
三個實務上的推論。
- 「我寫進去的對稱性」和「模型實際遵守的對稱性」是兩件事。 邊界、padding 的選擇、pooling 的方式都會在對稱性上開縫。要知道有多大,就量一次(上一節那個 是內部的數字)。
- 需要位置的時候,把位置明確餵進去,而不是指望模型從邊界效應裡偷。實務上的做法是加上座標通道(CoordConv)或位置編碼——後者正是 要看哪裡,能不能由內容決定,而不是由位置決定? 會用到的東西。
- 這也是一個評估的教訓。 如果只看這個任務的準確率,會得出「卷積比 MLP 更會判斷位置」這個結論,而那是錯的——它做對的理由和你以為的完全不同。
寫進假設空間的對稱性,只在你沒有留縫的地方成立;而模型一定會找到縫。
局部、共享、等變:三個開關
互動 demo:切換模型看等變誤差:卷積是精確的 0,局部未共享是 10⁻¹ 的量級——等變來自共享,不來自局部。
回到情境:什麼時候該用它
它宣告了什麼。 兩件事:有用的模式是局部的;一個模式在哪裡出現都算數。兩個都是關於資料的斷言,而它們對影像、聲音、時間序列大致成立,對表格資料(欄位之間沒有「相鄰」可言)、對一般的集合(沒有位置)不成立。
這一切依賴什麼。
一,「相鄰」要有意義。打亂像素那一欄就是這個前提被拿掉時的樣子——卷積從最好的模型變成最差的。如果你的特徵順序是任意的(例如一張 CSV 的欄位),卷積不會有任何幫助,而且會比 MLP 差。
二,平移要真的是一個對稱性。刻意違反那一節是它不成立時的樣子;而更麻煩的是,它常常是部分成立的(影像的上下不對稱:天空在上、地面在下),那時候純粹的卷積會浪費容量去表達「不需要不變的那部分」。
三,尺度。這一篇的線一律是 個像素長,所以一個 的核就夠了。真實的物件有各種大小,而一個固定大小的核只覆蓋一個尺度——這就是下一篇的起點。
先消化一下
參考文獻
- LeCun, Y. et al. Backpropagation Applied to Handwritten Zip Code Recognition. Neural Computation 1(4), 1989.(局部連接與權重共享的原始論證,以及兩者在參數量上的效果。)
- Cohen, T. & Welling, M. Group Equivariant Convolutional Networks. ICML 2016.(把「等變的線性層」這個要求推廣到平移以外的群,本篇 Q1 那個唯一性結論的一般版本。)
- Liu, R. et al. An Intriguing Failing of Convolutional Neural Networks and the CoordConv Solution. NeurIPS 2018.(當任務需要位置時卷積的失敗模式,以及把座標明確餵進去的做法。)